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& 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 211 private: 212 status_t OpenNodeCommon(bool writable); 213 void SetupBaseType(); 214 void FinishSettingUpType(); 215 void DeletePreferredAppVolumeNameLinkTo(); 216 void CacheLocalizedName(); 217 218 status_t FetchOneQuery(const BQuery*, BHandler* target, 219 BObjectList<BQuery>*, BVolume*); 220 221 enum CanHandleResult { 222 kCanHandle, 223 kCannotHandle, 224 kNeedToCheckType 225 }; 226 227 CanHandleResult CanHandleDrops() const; 228 229 enum NodeType { 230 kPlainNode, 231 kExecutableNode, 232 kDirectoryNode, 233 kLinkNode, 234 kQueryNode, 235 kQueryTemplateNode, 236 kVolumeNode, 237 kRootNode, 238 kTrashNode, 239 kDesktopNode, 240 kVirtualDirectoryNode, 241 kUnknownNode 242 }; 243 244 entry_ref fEntryRef; 245 StatStruct fStatBuf; 246 BString fMimeType; 247 // should use string that may be shared for common types 248 249 // bit of overloading hackery here to save on footprint 250 union { 251 char* fPreferredAppName; // used if we are neither a volume 252 // nor a symlink 253 char* fVolumeName; // used if we are a volume 254 Model* fLinkTo; // used if we are a symlink 255 }; 256 257 uint8 fBaseType; 258 uint8 fIconFrom; 259 bool fWritable; 260 BNode* fNode; 261 status_t fStatus; 262 BString fLocalizedName; 263 bool fHasLocalizedName; 264 bool fLocalizedNameIsCached; 265 }; 266 267 268 class ModelNodeLazyOpener { 269 // a utility open state manager, usefull to allocate on stack 270 // and have close up model when done, etc. 271 public: 272 // consider failing when open does not succeed 273 274 ModelNodeLazyOpener(Model* model, bool writable = false, 275 bool openLater = true); 276 ~ModelNodeLazyOpener(); 277 278 bool IsOpen() const; 279 bool IsOpenForWriting() const; 280 bool IsOpen(bool forWriting) const; 281 Model* TargetModel() const; 282 status_t OpenNode(bool writable = false); 283 284 private: 285 Model* fModel; 286 bool fWasOpen; 287 bool fWasOpenForWriting; 288 }; 289 290 // handy flavors of openers 291 class BModelOpener : public ModelNodeLazyOpener { 292 public: 293 BModelOpener(Model* model) 294 : ModelNodeLazyOpener(model, false, false) 295 { 296 } 297 }; 298 299 class BModelWriteOpener : public ModelNodeLazyOpener { 300 public: 301 BModelWriteOpener(Model* model) 302 : ModelNodeLazyOpener(model, true, false) 303 { 304 } 305 }; 306 307 308 #if DEBUG 309 // #define CHECK_OPEN_MODEL_LEAKS 310 #endif 311 312 #ifdef CHECK_OPEN_MODEL_LEAKS 313 void DumpOpenModels(bool extensive); 314 void InitOpenModelDumping(); 315 #endif 316 317 // inlines follow ----------------------------------- 318 319 inline const char* 320 Model::MimeType() const 321 { 322 return fMimeType.String(); 323 } 324 325 326 inline const entry_ref* 327 Model::EntryRef() const 328 { 329 return &fEntryRef; 330 } 331 332 333 inline const node_ref* 334 Model::NodeRef() const 335 { 336 // the stat structure begins with a node_ref 337 return (node_ref*)&fStatBuf; 338 } 339 340 341 inline BNode* 342 Model::Node() const 343 { 344 return fNode; 345 } 346 347 348 inline const StatStruct* 349 Model::StatBuf() const 350 { 351 return &fStatBuf; 352 } 353 354 355 inline IconSource 356 Model::IconFrom() const 357 { 358 return (IconSource)fIconFrom; 359 } 360 361 362 inline void 363 Model::SetIconFrom(IconSource from) 364 { 365 fIconFrom = from; 366 } 367 368 369 inline Model* 370 Model::LinkTo() const 371 { 372 ASSERT(IsSymLink()); 373 return fLinkTo; 374 } 375 376 377 inline bool 378 Model::IsFile() const 379 { 380 return fBaseType == kPlainNode 381 || fBaseType == kQueryNode 382 || fBaseType == kQueryTemplateNode 383 || fBaseType == kExecutableNode 384 || fBaseType == kVirtualDirectoryNode; 385 } 386 387 388 inline bool 389 Model::IsVolume() const 390 { 391 return fBaseType == kVolumeNode; 392 } 393 394 395 inline bool 396 Model::IsDirectory() const 397 { 398 return fBaseType == kDirectoryNode 399 || fBaseType == kVolumeNode 400 || fBaseType == kRootNode 401 || fBaseType == kTrashNode 402 || fBaseType == kDesktopNode; 403 } 404 405 406 inline bool 407 Model::IsQuery() const 408 { 409 return fBaseType == kQueryNode; 410 } 411 412 413 inline bool 414 Model::IsQueryTemplate() const 415 { 416 return fBaseType == kQueryTemplateNode; 417 } 418 419 420 inline bool 421 Model::IsContainer() const 422 { 423 // I guess as in should show container window - 424 // volumes show the volume window 425 return IsQuery() || IsDirectory() || IsVirtualDirectory(); 426 } 427 428 429 inline bool 430 Model::IsRoot() const 431 { 432 return fBaseType == kRootNode; 433 } 434 435 436 inline bool 437 Model::IsTrash() const 438 { 439 return fBaseType == kTrashNode; 440 } 441 442 443 inline bool 444 Model::IsDesktop() const 445 { 446 return fBaseType == kDesktopNode; 447 } 448 449 450 inline bool 451 Model::IsExecutable() const 452 { 453 return fBaseType == kExecutableNode; 454 } 455 456 457 inline bool 458 Model::IsSymLink() const 459 { 460 return fBaseType == kLinkNode; 461 } 462 463 464 inline bool 465 Model::IsVirtualDirectory() const 466 { 467 return fBaseType == kVirtualDirectoryNode; 468 } 469 470 471 inline bool 472 Model::HasLocalizedName() const 473 { 474 return fHasLocalizedName; 475 } 476 477 478 inline 479 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable, 480 bool openLater) 481 : 482 fModel(model), 483 fWasOpen(model->IsNodeOpen()), 484 fWasOpenForWriting(model->IsNodeOpenForWriting()) 485 { 486 if (!openLater) 487 OpenNode(writable); 488 } 489 490 491 inline 492 ModelNodeLazyOpener::~ModelNodeLazyOpener() 493 { 494 if (!fModel->IsNodeOpen()) 495 return; 496 if (!fWasOpen) 497 fModel->CloseNode(); 498 else if (!fWasOpenForWriting) 499 fModel->OpenNode(); 500 } 501 502 503 inline bool 504 ModelNodeLazyOpener::IsOpen() const 505 { 506 return fModel->IsNodeOpen(); 507 } 508 509 510 inline bool 511 ModelNodeLazyOpener::IsOpenForWriting() const 512 { 513 return fModel->IsNodeOpenForWriting(); 514 } 515 516 517 inline bool 518 ModelNodeLazyOpener::IsOpen(bool forWriting) const 519 { 520 return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen(); 521 } 522 523 524 inline Model* 525 ModelNodeLazyOpener::TargetModel() const 526 { 527 return fModel; 528 } 529 530 531 inline status_t 532 ModelNodeLazyOpener::OpenNode(bool writable) 533 { 534 if (writable) { 535 if (!fModel->IsNodeOpenForWriting()) 536 return fModel->OpenNode(true); 537 } else if (!fModel->IsNodeOpen()) 538 return fModel->OpenNode(); 539 540 return B_OK; 541 } 542 543 } // namespace BPrivate 544 545 546 #endif // _NU_MODEL_H 547