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 }; 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 } 385 386 387 inline bool 388 Model::IsVolume() const 389 { 390 return fBaseType == kVolumeNode; 391 } 392 393 394 inline bool 395 Model::IsDirectory() const 396 { 397 return fBaseType == kDirectoryNode 398 || fBaseType == kVolumeNode 399 || fBaseType == kRootNode 400 || fBaseType == kTrashNode 401 || fBaseType == kDesktopNode; 402 } 403 404 405 inline bool 406 Model::IsQuery() const 407 { 408 return fBaseType == kQueryNode; 409 } 410 411 412 inline bool 413 Model::IsQueryTemplate() const 414 { 415 return fBaseType == kQueryTemplateNode; 416 } 417 418 419 inline bool 420 Model::IsContainer() const 421 { 422 // I guess as in should show container window - 423 // volumes show the volume window 424 return IsQuery() || IsDirectory(); 425 } 426 427 428 inline bool 429 Model::IsRoot() const 430 { 431 return fBaseType == kRootNode; 432 } 433 434 435 inline bool 436 Model::IsTrash() const 437 { 438 return fBaseType == kTrashNode; 439 } 440 441 442 inline bool 443 Model::IsDesktop() const 444 { 445 return fBaseType == kDesktopNode; 446 } 447 448 449 inline bool 450 Model::IsExecutable() const 451 { 452 return fBaseType == kExecutableNode; 453 } 454 455 456 inline bool 457 Model::IsSymLink() const 458 { 459 return fBaseType == kLinkNode; 460 } 461 462 463 inline bool 464 Model::HasLocalizedName() const 465 { 466 return fHasLocalizedName; 467 } 468 469 470 inline 471 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable, 472 bool openLater) 473 : fModel(model), 474 fWasOpen(model->IsNodeOpen()), 475 fWasOpenForWriting(model->IsNodeOpenForWriting()) 476 { 477 if (!openLater) 478 OpenNode(writable); 479 } 480 481 482 inline 483 ModelNodeLazyOpener::~ModelNodeLazyOpener() 484 { 485 if (!fModel->IsNodeOpen()) 486 return; 487 if (!fWasOpen) 488 fModel->CloseNode(); 489 else if (!fWasOpenForWriting) 490 fModel->OpenNode(); 491 } 492 493 494 inline bool 495 ModelNodeLazyOpener::IsOpen() const 496 { 497 return fModel->IsNodeOpen(); 498 } 499 500 501 inline bool 502 ModelNodeLazyOpener::IsOpenForWriting() const 503 { 504 return fModel->IsNodeOpenForWriting(); 505 } 506 507 508 inline bool 509 ModelNodeLazyOpener::IsOpen(bool forWriting) const 510 { 511 return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen(); 512 } 513 514 515 inline Model* 516 ModelNodeLazyOpener::TargetModel() const 517 { 518 return fModel; 519 } 520 521 522 inline status_t 523 ModelNodeLazyOpener::OpenNode(bool writable) 524 { 525 if (writable) { 526 if (!fModel->IsNodeOpenForWriting()) 527 return fModel->OpenNode(true); 528 } else if (!fModel->IsNodeOpen()) 529 return fModel->OpenNode(); 530 531 return B_OK; 532 } 533 534 } // namespace BPrivate 535 536 #endif // _NU_MODEL_H 537