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