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 145 IconSource IconFrom() const; 146 void SetIconFrom(IconSource); 147 // where is this model getting it's icon from 148 149 void ResetIconFrom(); 150 // called from the attribute changed calls to force a lookup of 151 // a new icon 152 153 // symlink handling calls, mainly used by the IconCache 154 const Model* ResolveIfLink() const; 155 Model* ResolveIfLink(); 156 // works on anything 157 Model* LinkTo() const; 158 // fast, works only on symlinks 159 void SetLinkTo(Model*); 160 161 status_t GetLongVersionString(BString &, version_kind); 162 status_t GetVersionString(BString &, version_kind); 163 status_t AttrAsString(BString &, int64* value, 164 const char* attributeName, uint32 attributeType); 165 166 // Node monitor update call 167 void UpdateEntryRef(const node_ref* dirRef, const char* name); 168 bool AttrChanged(const char*); 169 // returns true if pose needs to update it's icon, etc. 170 // pass null to force full update 171 bool StatChanged(); 172 // returns true if pose needs to update it's icon 173 174 status_t WatchVolumeAndMountPoint(uint32, BHandler*); 175 // correctly handles boot volume name watching 176 177 bool IsDropTarget(const Model* forDocument = 0, 178 bool traverse = false) const; 179 // if nonzero <forDocument> passed, mime info is used to 180 // resolve if document can be opened 181 // if zero, all executables, directories and volumes pass 182 // if traverse, dereference symlinks 183 bool IsDropTargetForList(const BObjectList<BString>* list) const; 184 // <list> contains mime types of all documents about to be handled 185 // by model 186 187 #if DEBUG 188 void PrintToStream(int32 level = 1, bool deep = false); 189 void TrackIconSource(icon_size); 190 #endif 191 192 bool IsSuperHandler() const; 193 int32 SupportsMimeType(const char* type, 194 const BObjectList<BString>* list, bool exactReason = false) const; 195 // pass in one string in <type> or a bunch in <list> 196 // if <exactReason> false, returns as soon as it figures out that 197 // app supports a given type, if true, returns an exact reason 198 199 // get rid of this?? 200 ssize_t WriteAttr(const char* attr, type_code type, off_t, 201 const void* buffer, size_t ); 202 // cover call, creates a writable node and writes out attributes 203 // into it; work around for file nodes not being writeable 204 ssize_t WriteAttrKillForeign(const char* attr, 205 const char* foreignAttr, type_code type, off_t, 206 const void* buffer, size_t); 207 208 bool Mimeset(bool force); 209 // returns true if mime type changed 210 211 bool HasLocalizedName() const; 212 213 private: 214 status_t OpenNodeCommon(bool writable); 215 void SetupBaseType(); 216 void FinishSettingUpType(); 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 kUnknownNode 243 }; 244 245 entry_ref fEntryRef; 246 StatStruct fStatBuf; 247 BString fMimeType; 248 // should use string that may be shared for common types 249 250 // bit of overloading hackery here to save on footprint 251 union { 252 char* fPreferredAppName; // used if we are neither a volume 253 // nor a symlink 254 char* fVolumeName; // used if we are a volume 255 Model* fLinkTo; // used if we are a symlink 256 }; 257 258 uint8 fBaseType; 259 uint8 fIconFrom; 260 bool fWritable; 261 BNode* fNode; 262 status_t fStatus; 263 BString fLocalizedName; 264 bool fHasLocalizedName; 265 bool fLocalizedNameIsCached; 266 }; 267 268 269 class ModelNodeLazyOpener { 270 // a utility open state manager, usefull to allocate on stack 271 // and have close up model when done, etc. 272 public: 273 // consider failing when open does not succeed 274 275 ModelNodeLazyOpener(Model* model, bool writable = false, 276 bool openLater = true); 277 ~ModelNodeLazyOpener(); 278 279 bool IsOpen() const; 280 bool IsOpenForWriting() const; 281 bool IsOpen(bool forWriting) const; 282 Model* TargetModel() const; 283 status_t OpenNode(bool writable = false); 284 285 private: 286 Model* fModel; 287 bool fWasOpen; 288 bool fWasOpenForWriting; 289 }; 290 291 // handy flavors of openers 292 class BModelOpener : public ModelNodeLazyOpener { 293 public: 294 BModelOpener(Model* model) 295 : ModelNodeLazyOpener(model, false, false) 296 { 297 } 298 }; 299 300 class BModelWriteOpener : public ModelNodeLazyOpener { 301 public: 302 BModelWriteOpener(Model* model) 303 : ModelNodeLazyOpener(model, true, false) 304 { 305 } 306 }; 307 308 309 #if DEBUG 310 // #define CHECK_OPEN_MODEL_LEAKS 311 #endif 312 313 #ifdef CHECK_OPEN_MODEL_LEAKS 314 void DumpOpenModels(bool extensive); 315 void InitOpenModelDumping(); 316 #endif 317 318 // inlines follow ----------------------------------- 319 320 inline const char* 321 Model::MimeType() const 322 { 323 return fMimeType.String(); 324 } 325 326 327 inline const entry_ref* 328 Model::EntryRef() const 329 { 330 return &fEntryRef; 331 } 332 333 334 inline const node_ref* 335 Model::NodeRef() const 336 { 337 // the stat structure begins with a node_ref 338 return (node_ref*)&fStatBuf; 339 } 340 341 342 inline BNode* 343 Model::Node() const 344 { 345 return fNode; 346 } 347 348 349 inline const StatStruct* 350 Model::StatBuf() const 351 { 352 return &fStatBuf; 353 } 354 355 356 inline IconSource 357 Model::IconFrom() const 358 { 359 return (IconSource)fIconFrom; 360 } 361 362 363 inline void 364 Model::SetIconFrom(IconSource from) 365 { 366 fIconFrom = from; 367 } 368 369 370 inline Model* 371 Model::LinkTo() const 372 { 373 ASSERT(IsSymLink()); 374 return fLinkTo; 375 } 376 377 378 inline bool 379 Model::IsFile() const 380 { 381 return fBaseType == kPlainNode 382 || fBaseType == kQueryNode 383 || fBaseType == kQueryTemplateNode 384 || fBaseType == kExecutableNode; 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(); 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::HasLocalizedName() const 466 { 467 return fHasLocalizedName; 468 } 469 470 471 inline 472 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable, 473 bool openLater) 474 : fModel(model), 475 fWasOpen(model->IsNodeOpen()), 476 fWasOpenForWriting(model->IsNodeOpenForWriting()) 477 { 478 if (!openLater) 479 OpenNode(writable); 480 } 481 482 483 inline 484 ModelNodeLazyOpener::~ModelNodeLazyOpener() 485 { 486 if (!fModel->IsNodeOpen()) 487 return; 488 if (!fWasOpen) 489 fModel->CloseNode(); 490 else if (!fWasOpenForWriting) 491 fModel->OpenNode(); 492 } 493 494 495 inline bool 496 ModelNodeLazyOpener::IsOpen() const 497 { 498 return fModel->IsNodeOpen(); 499 } 500 501 502 inline bool 503 ModelNodeLazyOpener::IsOpenForWriting() const 504 { 505 return fModel->IsNodeOpenForWriting(); 506 } 507 508 509 inline bool 510 ModelNodeLazyOpener::IsOpen(bool forWriting) const 511 { 512 return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen(); 513 } 514 515 516 inline Model* 517 ModelNodeLazyOpener::TargetModel() const 518 { 519 return fModel; 520 } 521 522 523 inline status_t 524 ModelNodeLazyOpener::OpenNode(bool writable) 525 { 526 if (writable) { 527 if (!fModel->IsNodeOpenForWriting()) 528 return fModel->OpenNode(true); 529 } else if (!fModel->IsNodeOpen()) 530 return fModel->OpenNode(); 531 532 return B_OK; 533 } 534 535 } // namespace BPrivate 536 537 #endif // _NU_MODEL_H 538