1/* 2Open Tracker License 3 4Terms and Conditions 5 6Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a copy of 9this software and associated documentation files (the "Software"), to deal in 10the Software without restriction, including without limitation the rights to 11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12of the Software, and to permit persons to whom the Software is furnished to do 13so, subject to the following conditions: 14 15The above copyright notice and this permission notice applies to all licensees 16and shall be included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of Be Incorporated shall not be 26used in advertising or otherwise to promote the sale, use or other dealings in 27this Software without prior written authorization from Be Incorporated. 28 29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30of Be Incorporated in the United States and other countries. Other brand product 31names are registered trademarks or trademarks of their respective holders. 32All rights reserved. 33*/ 34 35// Dedicated to BModel 36#ifndef _NU_MODEL_H 37#define _NU_MODEL_H 38 39 40#include <AppFileInfo.h> 41#include <Debug.h> 42#include <Mime.h> 43#include <StorageDefs.h> 44#include <String.h> 45 46#include "IconCache.h" 47#include "ObjectList.h" 48 49 50class BPath; 51class BHandler; 52class BEntry; 53class BQuery; 54 55 56#if __GNUC__ && __GNUC__ < 3 57// using std::stat instead of just stat here because of what 58// seems to be a gcc bug involving namespace and struct stat interaction 59typedef struct std::stat StatStruct; 60#else 61// on mwcc std isn't turned on but there is no bug either. 62// Also seems to be fixed in gcc 3. 63typedef struct stat StatStruct; 64#endif 65 66 67namespace BPrivate { 68 69enum { 70 kDoesNotSupportType, 71 kSuperhandlerModel, 72 kModelSupportsSupertype, 73 kModelSupportsType, 74 kModelSupportsFile 75}; 76 77 78class Model { 79public: 80 Model(); 81 Model(const Model& other); 82 Model(const BEntry* entry, bool open = false, bool writable = false); 83 Model(const entry_ref*, bool traverse = false, bool open = false, 84 bool writable = false); 85 Model(const node_ref* dirNode, const node_ref* node, const char* name, 86 bool open = false, bool writable = false); 87 ~Model(); 88 89 Model& operator=(const Model&); 90 91 status_t InitCheck() const; 92 93 status_t SetTo(const BEntry*, bool open = false, 94 bool writable = false); 95 status_t SetTo(const entry_ref*, bool traverse = false, 96 bool open = false, bool writable = false); 97 status_t SetTo(const node_ref* dirNode, const node_ref* node, 98 const char* name, bool open = false, bool writable = false); 99 100 int CompareFolderNamesFirst(const Model* compareModel) const; 101 102 // node management 103 status_t OpenNode(bool writable = false); 104 // also used to switch from read-only to writable 105 void CloseNode(); 106 bool IsNodeOpen() const; 107 bool IsNodeOpenForWriting() const; 108 109 status_t UpdateStatAndOpenNode(bool writable = false); 110 // like OpenNode, called on zombie poses to check if they turned 111 // real, starts by rereading the stat structure 112 113 // basic getters 114 const char* Name() const; 115 const entry_ref* EntryRef() const; 116 const node_ref* NodeRef() const; 117 const StatStruct* StatBuf() const; 118 119 BNode* Node() const; 120 // returns NULL if not open 121 void GetPath(BPath*) const; 122 void GetEntry(BEntry*) const; 123 124 const char* MimeType() const; 125 const char* PreferredAppSignature() const; 126 // only not-null if not default for type and not self for app 127 void SetPreferredAppSignature(const char*); 128 129 // type getters 130 bool IsFile() const; 131 bool IsDirectory() const; 132 bool IsQuery() const; 133 bool IsQueryTemplate() const; 134 bool IsContainer() const; 135 bool IsExecutable() const; 136 bool IsSymLink() const; 137 bool IsRoot() const; 138 bool IsTrash() const; 139 bool IsDesktop() const; 140 bool IsVolume() const; 141 bool IsVirtualDirectory() const; 142 143 IconSource IconFrom() const; 144 void SetIconFrom(IconSource); 145 // where is this model getting it's icon from 146 147 void ResetIconFrom(); 148 // called from the attribute changed calls to force a lookup of 149 // a new icon 150 151 // symlink handling calls, mainly used by the IconCache 152 const Model* ResolveIfLink() const; 153 Model* ResolveIfLink(); 154 // works on anything 155 Model* LinkTo() const; 156 // fast, works only on symlinks 157 void SetLinkTo(Model*); 158 159 status_t GetLongVersionString(BString &, version_kind); 160 status_t GetVersionString(BString &, version_kind); 161 status_t AttrAsString(BString &, int64* value, 162 const char* attributeName, uint32 attributeType); 163 164 // Node monitor update call 165 void UpdateEntryRef(const node_ref* dirRef, const char* name); 166 bool AttrChanged(const char* attrName); 167 // returns true if pose needs to update it's icon, etc. 168 // pass null to force full update 169 bool StatChanged(); 170 // returns true if pose needs to update it's icon 171 172 status_t WatchVolumeAndMountPoint(uint32, BHandler*); 173 // correctly handles boot volume name watching 174 175 bool IsDropTarget(const Model* forDocument = 0, 176 bool traverse = false) const; 177 // if nonzero <forDocument> passed, mime info is used to 178 // resolve if document can be opened 179 // if zero, all executables, directories and volumes pass 180 // if traverse, dereference symlinks 181 bool IsDropTargetForList(const BObjectList<BString>* list) const; 182 // <list> contains mime types of all documents about to be handled 183 // by model 184 185#if DEBUG 186 void PrintToStream(int32 level = 1, bool deep = false); 187 void TrackIconSource(icon_size); 188#endif 189 190 bool IsSuperHandler() const; 191 int32 SupportsMimeType(const char* type, 192 const BObjectList<BString>* list, bool exactReason = false) const; 193 // pass in one string in <type> or a bunch in <list> 194 // if <exactReason> false, returns as soon as it figures out that 195 // app supports a given type, if true, returns an exact reason 196 197 // get rid of this?? 198 ssize_t WriteAttr(const char* attr, type_code type, off_t, 199 const void* buffer, size_t ); 200 // cover call, creates a writable node and writes out attributes 201 // into it; work around for file nodes not being writeable 202 ssize_t WriteAttrKillForeign(const char* attr, 203 const char* foreignAttr, type_code type, off_t, 204 const void* buffer, size_t); 205 206 bool Mimeset(bool force); 207 // returns true if mime type changed 208 209 bool HasLocalizedName() const; 210 211private: 212 status_t OpenNodeCommon(bool writable); 213 void SetupBaseType(); 214 void FinishSettingUpType(); 215 bool ShouldUseWellKnownIcon() const; 216 bool CheckAppIconHint() const; 217 void DeletePreferredAppVolumeNameLinkTo(); 218 void CacheLocalizedName(); 219 220 status_t FetchOneQuery(const BQuery*, BHandler* target, 221 BObjectList<BQuery>*, BVolume*); 222 223 enum CanHandleResult { 224 kCanHandle, 225 kCannotHandle, 226 kNeedToCheckType 227 }; 228 229 CanHandleResult CanHandleDrops() const; 230 231 enum NodeType { 232 kPlainNode, 233 kExecutableNode, 234 kDirectoryNode, 235 kLinkNode, 236 kQueryNode, 237 kQueryTemplateNode, 238 kVolumeNode, 239 kRootNode, 240 kTrashNode, 241 kDesktopNode, 242 kVirtualDirectoryNode, 243 kUnknownNode 244 }; 245 246 entry_ref fEntryRef; 247 StatStruct fStatBuf; 248 BString fMimeType; 249 // should use string that may be shared for common types 250 251 // bit of overloading hackery here to save on footprint 252 union { 253 char* fPreferredAppName; // used if we are neither a volume 254 // nor a symlink 255 char* fVolumeName; // used if we are a volume 256 Model* fLinkTo; // used if we are a symlink 257 }; 258 259 uint8 fBaseType; 260 uint8 fIconFrom; 261 bool fWritable; 262 BNode* fNode; 263 status_t fStatus; 264 BString fLocalizedName; 265 bool fHasLocalizedName; 266 bool fLocalizedNameIsCached; 267}; 268 269 270class ModelNodeLazyOpener { 271 // a utility open state manager, usefull to allocate on stack 272 // and have close up model when done, etc. 273 public: 274 // consider failing when open does not succeed 275 276 ModelNodeLazyOpener(Model* model, bool writable = false, 277 bool openLater = true); 278 ~ModelNodeLazyOpener(); 279 280 bool IsOpen() const; 281 bool IsOpenForWriting() const; 282 bool IsOpen(bool forWriting) const; 283 Model* TargetModel() const; 284 status_t OpenNode(bool writable = false); 285 286 private: 287 Model* fModel; 288 bool fWasOpen; 289 bool fWasOpenForWriting; 290}; 291 292// handy flavors of openers 293class BModelOpener : public ModelNodeLazyOpener { 294 public: 295 BModelOpener(Model* model) 296 : ModelNodeLazyOpener(model, false, false) 297 { 298 } 299}; 300 301class BModelWriteOpener : public ModelNodeLazyOpener { 302 public: 303 BModelWriteOpener(Model* model) 304 : ModelNodeLazyOpener(model, true, false) 305 { 306 } 307}; 308 309 310#if DEBUG 311// #define CHECK_OPEN_MODEL_LEAKS 312#endif 313 314#ifdef CHECK_OPEN_MODEL_LEAKS 315void DumpOpenModels(bool extensive); 316void InitOpenModelDumping(); 317#endif 318 319// inlines follow ----------------------------------- 320 321inline const char* 322Model::MimeType() const 323{ 324 return fMimeType.String(); 325} 326 327 328inline const entry_ref* 329Model::EntryRef() const 330{ 331 return &fEntryRef; 332} 333 334 335inline const node_ref* 336Model::NodeRef() const 337{ 338 // the stat structure begins with a node_ref 339 return (node_ref*)&fStatBuf; 340} 341 342 343inline BNode* 344Model::Node() const 345{ 346 return fNode; 347} 348 349 350inline const StatStruct* 351Model::StatBuf() const 352{ 353 return &fStatBuf; 354} 355 356 357inline IconSource 358Model::IconFrom() const 359{ 360 return (IconSource)fIconFrom; 361} 362 363 364inline void 365Model::SetIconFrom(IconSource from) 366{ 367 fIconFrom = from; 368} 369 370 371inline Model* 372Model::LinkTo() const 373{ 374 ASSERT(IsSymLink()); 375 return fLinkTo; 376} 377 378 379inline bool 380Model::IsFile() const 381{ 382 return fBaseType == kPlainNode 383 || fBaseType == kQueryNode 384 || fBaseType == kQueryTemplateNode 385 || fBaseType == kExecutableNode 386 || fBaseType == kVirtualDirectoryNode; 387} 388 389 390inline bool 391Model::IsVolume() const 392{ 393 return fBaseType == kVolumeNode; 394} 395 396 397inline bool 398Model::IsDirectory() const 399{ 400 return fBaseType == kDirectoryNode 401 || fBaseType == kVolumeNode 402 || fBaseType == kRootNode 403 || fBaseType == kTrashNode 404 || fBaseType == kDesktopNode; 405} 406 407 408inline bool 409Model::IsQuery() const 410{ 411 return fBaseType == kQueryNode; 412} 413 414 415inline bool 416Model::IsQueryTemplate() const 417{ 418 return fBaseType == kQueryTemplateNode; 419} 420 421 422inline bool 423Model::IsContainer() const 424{ 425 // I guess as in should show container window - 426 // volumes show the volume window 427 return IsQuery() || IsDirectory() || IsVirtualDirectory(); 428} 429 430 431inline bool 432Model::IsRoot() const 433{ 434 return fBaseType == kRootNode; 435} 436 437 438inline bool 439Model::IsTrash() const 440{ 441 return fBaseType == kTrashNode; 442} 443 444 445inline bool 446Model::IsDesktop() const 447{ 448 return fBaseType == kDesktopNode; 449} 450 451 452inline bool 453Model::IsExecutable() const 454{ 455 return fBaseType == kExecutableNode; 456} 457 458 459inline bool 460Model::IsSymLink() const 461{ 462 return fBaseType == kLinkNode; 463} 464 465 466inline bool 467Model::IsVirtualDirectory() const 468{ 469 return fBaseType == kVirtualDirectoryNode; 470} 471 472 473inline bool 474Model::HasLocalizedName() const 475{ 476 return fHasLocalizedName; 477} 478 479 480inline 481ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable, 482 bool openLater) 483 : 484 fModel(model), 485 fWasOpen(model->IsNodeOpen()), 486 fWasOpenForWriting(model->IsNodeOpenForWriting()) 487{ 488 if (!openLater) 489 OpenNode(writable); 490} 491 492 493inline 494ModelNodeLazyOpener::~ModelNodeLazyOpener() 495{ 496 if (!fModel->IsNodeOpen()) 497 return; 498 if (!fWasOpen) 499 fModel->CloseNode(); 500 else if (!fWasOpenForWriting) 501 fModel->OpenNode(); 502} 503 504 505inline bool 506ModelNodeLazyOpener::IsOpen() const 507{ 508 return fModel->IsNodeOpen(); 509} 510 511 512inline bool 513ModelNodeLazyOpener::IsOpenForWriting() const 514{ 515 return fModel->IsNodeOpenForWriting(); 516} 517 518 519inline bool 520ModelNodeLazyOpener::IsOpen(bool forWriting) const 521{ 522 return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen(); 523} 524 525 526inline Model* 527ModelNodeLazyOpener::TargetModel() const 528{ 529 return fModel; 530} 531 532 533inline status_t 534ModelNodeLazyOpener::OpenNode(bool writable) 535{ 536 if (writable) { 537 if (!fModel->IsNodeOpenForWriting()) 538 return fModel->OpenNode(true); 539 } else if (!fModel->IsNodeOpen()) 540 return fModel->OpenNode(); 541 542 return B_OK; 543} 544 545} // namespace BPrivate 546 547 548#endif // _NU_MODEL_H 549