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 78 class Model { 79 public: 80 Model(); 81 Model(const Model &); 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 void GetPreferredAppForBrokenSymLink(BString &result); 130 // special purpose call - if a symlink is unresolvable, it makes 131 // sense to be able to get at it's preferred handler which may be 132 // different from the Tracker. Used by the network neighborhood. 133 134 // type getters 135 bool IsFile() const; 136 bool IsDirectory() const; 137 bool IsQuery() const; 138 bool IsQueryTemplate() const; 139 bool IsContainer() const; 140 bool IsExecutable() const; 141 bool IsSymLink() const; 142 bool IsRoot() const; 143 bool IsTrash() const; 144 bool IsDesktop() const; 145 bool IsVolume() const; 146 bool IsVirtualDirectory() const; 147 148 IconSource IconFrom() const; 149 void SetIconFrom(IconSource); 150 // where is this model getting it's icon from 151 152 void ResetIconFrom(); 153 // called from the attribute changed calls to force a lookup of 154 // a new icon 155 156 // symlink handling calls, mainly used by the IconCache 157 const Model* ResolveIfLink() const; 158 Model* ResolveIfLink(); 159 // works on anything 160 Model* LinkTo() const; 161 // fast, works only on symlinks 162 void SetLinkTo(Model*); 163 164 status_t GetLongVersionString(BString &, version_kind); 165 status_t GetVersionString(BString &, version_kind); 166 status_t AttrAsString(BString &, int64* value, 167 const char* attributeName, uint32 attributeType); 168 169 // Node monitor update call 170 void UpdateEntryRef(const node_ref* dirRef, const char* name); 171 bool AttrChanged(const char* attrName); 172 // returns true if pose needs to update it's icon, etc. 173 // pass null to force full update 174 bool StatChanged(); 175 // returns true if pose needs to update it's icon 176 177 status_t WatchVolumeAndMountPoint(uint32, BHandler*); 178 // correctly handles boot volume name watching 179 180 bool IsDropTarget(const Model* forDocument = 0, 181 bool traverse = false) const; 182 // if nonzero <forDocument> passed, mime info is used to 183 // resolve if document can be opened 184 // if zero, all executables, directories and volumes pass 185 // if traverse, dereference symlinks 186 bool IsDropTargetForList(const BObjectList<BString>* list) const; 187 // <list> contains mime types of all documents about to be handled 188 // by model 189 190 #if DEBUG 191 void PrintToStream(int32 level = 1, bool deep = false); 192 void TrackIconSource(icon_size); 193 #endif 194 195 bool IsSuperHandler() const; 196 int32 SupportsMimeType(const char* type, 197 const BObjectList<BString>* list, bool exactReason = false) const; 198 // pass in one string in <type> or a bunch in <list> 199 // if <exactReason> false, returns as soon as it figures out that 200 // app supports a given type, if true, returns an exact reason 201 202 // get rid of this?? 203 ssize_t WriteAttr(const char* attr, type_code type, off_t, 204 const void* buffer, size_t ); 205 // cover call, creates a writable node and writes out attributes 206 // into it; work around for file nodes not being writeable 207 ssize_t WriteAttrKillForeign(const char* attr, 208 const char* foreignAttr, type_code type, off_t, 209 const void* buffer, size_t); 210 211 bool Mimeset(bool force); 212 // returns true if mime type changed 213 214 bool HasLocalizedName() const; 215 216 private: 217 status_t OpenNodeCommon(bool writable); 218 void SetupBaseType(); 219 void FinishSettingUpType(); 220 void DeletePreferredAppVolumeNameLinkTo(); 221 void CacheLocalizedName(); 222 223 status_t FetchOneQuery(const BQuery*, BHandler* target, 224 BObjectList<BQuery>*, BVolume*); 225 226 enum CanHandleResult { 227 kCanHandle, 228 kCannotHandle, 229 kNeedToCheckType 230 }; 231 232 CanHandleResult CanHandleDrops() const; 233 234 enum NodeType { 235 kPlainNode, 236 kExecutableNode, 237 kDirectoryNode, 238 kLinkNode, 239 kQueryNode, 240 kQueryTemplateNode, 241 kVolumeNode, 242 kRootNode, 243 kTrashNode, 244 kDesktopNode, 245 kVirtualDirectoryNode, 246 kUnknownNode 247 }; 248 249 entry_ref fEntryRef; 250 StatStruct fStatBuf; 251 BString fMimeType; 252 // should use string that may be shared for common types 253 254 // bit of overloading hackery here to save on footprint 255 union { 256 char* fPreferredAppName; // used if we are neither a volume 257 // nor a symlink 258 char* fVolumeName; // used if we are a volume 259 Model* fLinkTo; // used if we are a symlink 260 }; 261 262 uint8 fBaseType; 263 uint8 fIconFrom; 264 bool fWritable; 265 BNode* fNode; 266 status_t fStatus; 267 BString fLocalizedName; 268 bool fHasLocalizedName; 269 bool fLocalizedNameIsCached; 270 }; 271 272 273 class ModelNodeLazyOpener { 274 // a utility open state manager, usefull to allocate on stack 275 // and have close up model when done, etc. 276 public: 277 // consider failing when open does not succeed 278 279 ModelNodeLazyOpener(Model* model, bool writable = false, 280 bool openLater = true); 281 ~ModelNodeLazyOpener(); 282 283 bool IsOpen() const; 284 bool IsOpenForWriting() const; 285 bool IsOpen(bool forWriting) const; 286 Model* TargetModel() const; 287 status_t OpenNode(bool writable = false); 288 289 private: 290 Model* fModel; 291 bool fWasOpen; 292 bool fWasOpenForWriting; 293 }; 294 295 // handy flavors of openers 296 class BModelOpener : public ModelNodeLazyOpener { 297 public: 298 BModelOpener(Model* model) 299 : ModelNodeLazyOpener(model, false, false) 300 { 301 } 302 }; 303 304 class BModelWriteOpener : public ModelNodeLazyOpener { 305 public: 306 BModelWriteOpener(Model* model) 307 : ModelNodeLazyOpener(model, true, false) 308 { 309 } 310 }; 311 312 313 #if DEBUG 314 // #define CHECK_OPEN_MODEL_LEAKS 315 #endif 316 317 #ifdef CHECK_OPEN_MODEL_LEAKS 318 void DumpOpenModels(bool extensive); 319 void InitOpenModelDumping(); 320 #endif 321 322 // inlines follow ----------------------------------- 323 324 inline const char* 325 Model::MimeType() const 326 { 327 return fMimeType.String(); 328 } 329 330 331 inline const entry_ref* 332 Model::EntryRef() const 333 { 334 return &fEntryRef; 335 } 336 337 338 inline const node_ref* 339 Model::NodeRef() const 340 { 341 // the stat structure begins with a node_ref 342 return (node_ref*)&fStatBuf; 343 } 344 345 346 inline BNode* 347 Model::Node() const 348 { 349 return fNode; 350 } 351 352 353 inline const StatStruct* 354 Model::StatBuf() const 355 { 356 return &fStatBuf; 357 } 358 359 360 inline IconSource 361 Model::IconFrom() const 362 { 363 return (IconSource)fIconFrom; 364 } 365 366 367 inline void 368 Model::SetIconFrom(IconSource from) 369 { 370 fIconFrom = from; 371 } 372 373 374 inline Model* 375 Model::LinkTo() const 376 { 377 ASSERT(IsSymLink()); 378 return fLinkTo; 379 } 380 381 382 inline bool 383 Model::IsFile() const 384 { 385 return fBaseType == kPlainNode 386 || fBaseType == kQueryNode 387 || fBaseType == kQueryTemplateNode 388 || fBaseType == kExecutableNode 389 || fBaseType == kVirtualDirectoryNode; 390 } 391 392 393 inline bool 394 Model::IsVolume() const 395 { 396 return fBaseType == kVolumeNode; 397 } 398 399 400 inline bool 401 Model::IsDirectory() const 402 { 403 return fBaseType == kDirectoryNode 404 || fBaseType == kVolumeNode 405 || fBaseType == kRootNode 406 || fBaseType == kTrashNode 407 || fBaseType == kDesktopNode; 408 } 409 410 411 inline bool 412 Model::IsQuery() const 413 { 414 return fBaseType == kQueryNode; 415 } 416 417 418 inline bool 419 Model::IsQueryTemplate() const 420 { 421 return fBaseType == kQueryTemplateNode; 422 } 423 424 425 inline bool 426 Model::IsContainer() const 427 { 428 // I guess as in should show container window - 429 // volumes show the volume window 430 return IsQuery() || IsDirectory() || IsVirtualDirectory(); 431 } 432 433 434 inline bool 435 Model::IsRoot() const 436 { 437 return fBaseType == kRootNode; 438 } 439 440 441 inline bool 442 Model::IsTrash() const 443 { 444 return fBaseType == kTrashNode; 445 } 446 447 448 inline bool 449 Model::IsDesktop() const 450 { 451 return fBaseType == kDesktopNode; 452 } 453 454 455 inline bool 456 Model::IsExecutable() const 457 { 458 return fBaseType == kExecutableNode; 459 } 460 461 462 inline bool 463 Model::IsSymLink() const 464 { 465 return fBaseType == kLinkNode; 466 } 467 468 469 inline bool 470 Model::IsVirtualDirectory() const 471 { 472 return fBaseType == kVirtualDirectoryNode; 473 } 474 475 476 inline bool 477 Model::HasLocalizedName() const 478 { 479 return fHasLocalizedName; 480 } 481 482 483 inline 484 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable, 485 bool openLater) 486 : 487 fModel(model), 488 fWasOpen(model->IsNodeOpen()), 489 fWasOpenForWriting(model->IsNodeOpenForWriting()) 490 { 491 if (!openLater) 492 OpenNode(writable); 493 } 494 495 496 inline 497 ModelNodeLazyOpener::~ModelNodeLazyOpener() 498 { 499 if (!fModel->IsNodeOpen()) 500 return; 501 if (!fWasOpen) 502 fModel->CloseNode(); 503 else if (!fWasOpenForWriting) 504 fModel->OpenNode(); 505 } 506 507 508 inline bool 509 ModelNodeLazyOpener::IsOpen() const 510 { 511 return fModel->IsNodeOpen(); 512 } 513 514 515 inline bool 516 ModelNodeLazyOpener::IsOpenForWriting() const 517 { 518 return fModel->IsNodeOpenForWriting(); 519 } 520 521 522 inline bool 523 ModelNodeLazyOpener::IsOpen(bool forWriting) const 524 { 525 return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen(); 526 } 527 528 529 inline Model* 530 ModelNodeLazyOpener::TargetModel() const 531 { 532 return fModel; 533 } 534 535 536 inline status_t 537 ModelNodeLazyOpener::OpenNode(bool writable) 538 { 539 if (writable) { 540 if (!fModel->IsNodeOpenForWriting()) 541 return fModel->OpenNode(true); 542 } else if (!fModel->IsNodeOpen()) 543 return fModel->OpenNode(); 544 545 return B_OK; 546 } 547 548 } // namespace BPrivate 549 550 551 #endif // _NU_MODEL_H 552