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