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 37 #ifndef _NU_MODEL_H 38 #define _NU_MODEL_H 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 #if __GNUC__ && __GNUC__ < 3 56 // using std::stat instead of just stat here because of what 57 // seems to be a gcc bug involving namespace and struct stat interaction 58 typedef struct std::stat StatStruct; 59 #else 60 // on mwcc std isn't turned on but there is no bug either. 61 // Also seems to be fixed in gcc 3. 62 typedef struct stat StatStruct; 63 #endif 64 65 namespace BPrivate { 66 67 enum { 68 kDoesNotSupportType, 69 kSuperhandlerModel, 70 kModelSupportsSupertype, 71 kModelSupportsType, 72 kModelSupportsFile 73 }; 74 75 class Model { 76 public: 77 Model(); 78 Model(const Model &); 79 Model(const BEntry *entry, bool open = false, bool writable = false); 80 Model(const entry_ref *, bool traverse = false, bool open = false, 81 bool writable = false); 82 Model(const node_ref *dirNode, const node_ref *node, const char *name, 83 bool open = false, bool writable = false); 84 ~Model(); 85 86 Model& operator=(const Model &); 87 88 status_t InitCheck() const; 89 90 status_t SetTo(const BEntry *, bool open = false, bool writable = false); 91 status_t SetTo(const entry_ref *, bool traverse = false, bool open = false, 92 bool writable = false); 93 status_t SetTo(const node_ref *dirNode, const node_ref *node, const char *name, 94 bool open = false, bool writable = false); 95 96 int CompareFolderNamesFirst(const Model *compareModel) const; 97 98 // node management 99 status_t OpenNode(bool writable = false); 100 // also used to switch from read-only to writable 101 void CloseNode(); 102 bool IsNodeOpen() const; 103 bool IsNodeOpenForWriting() const; 104 105 status_t UpdateStatAndOpenNode(bool writable = false); 106 // like OpenNode, called on zombie poses to check if they turned 107 // real, starts by rereading the stat structure 108 109 // basic getters 110 const char *Name() const; 111 const entry_ref *EntryRef() const; 112 const node_ref *NodeRef() const; 113 const StatStruct *StatBuf() const; 114 115 BNode *Node() const; 116 // returns null if not Open 117 void GetPath(BPath *) const; 118 void GetEntry(BEntry *) const; 119 120 const char *MimeType() const; 121 const char *PreferredAppSignature() const; 122 // only not-null if not default for type and not self for app 123 void SetPreferredAppSignature(const char *); 124 125 void GetPreferredAppForBrokenSymLink(BString &result); 126 // special purpose call - if a symlink is unresolvable, it makes sense 127 // to be able to get at it's preferred handler which may be different 128 // from the Tracker. Used by the network neighborhood. 129 130 // type getters 131 bool IsFile() const; 132 bool IsDirectory() const; 133 bool IsQuery() const; 134 bool IsQueryTemplate() const; 135 bool IsContainer() const; 136 bool IsExecutable() const; 137 bool IsSymLink() const; 138 bool IsRoot() const; 139 bool IsTrash() const; 140 bool IsDesktop() const; 141 bool IsVolume() 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, const char *attributeName, 162 uint32 attributeType); 163 164 // Node monitor update call 165 void UpdateEntryRef(const node_ref *dirRef, const char *name); 166 bool AttrChanged(const char *); 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, const BObjectList<BString> *list, 192 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, const char *foreignAttr, 203 type_code type, off_t, const void *buffer, size_t); 204 205 bool Mimeset(bool force); 206 // returns true if mime type changed 207 208 bool HasLocalizedName() const; 209 210 private: 211 status_t OpenNodeCommon(bool writable); 212 void SetupBaseType(); 213 void FinishSettingUpType(); 214 void DeletePreferredAppVolumeNameLinkTo(); 215 void CacheLocalizedName(); 216 217 status_t FetchOneQuery(const BQuery *, BHandler *target, 218 BObjectList<BQuery>*, BVolume *); 219 220 enum CanHandleResult { 221 kCanHandle, 222 kCannotHandle, 223 kNeedToCheckType 224 }; 225 226 CanHandleResult CanHandleDrops() const; 227 228 enum NodeType { 229 kPlainNode, 230 kExecutableNode, 231 kDirectoryNode, 232 kLinkNode, 233 kQueryNode, 234 kQueryTemplateNode, 235 kVolumeNode, 236 kRootNode, 237 kTrashNode, 238 kDesktopNode, 239 kUnknownNode 240 }; 241 242 entry_ref fEntryRef; 243 StatStruct fStatBuf; 244 BString fMimeType; // should use string that may be shared for common types 245 246 // bit of overloading hackery here to save on footprint 247 union { 248 char *fPreferredAppName; // used if we are neither a volume nor a symlink 249 char *fVolumeName; // used if we are a volume 250 Model *fLinkTo; // used if we are a symlink 251 }; 252 253 uint8 fBaseType; 254 uint8 fIconFrom; 255 bool fWritable; 256 BNode *fNode; 257 status_t fStatus; 258 BString fLocalizedName; 259 bool fHasLocalizedName; 260 }; 261 262 263 class ModelNodeLazyOpener { 264 // a utility open state manager, usefull to allocate on stack 265 // and have close up model when done, etc. 266 public: 267 // consider failing when open does not succeed 268 269 ModelNodeLazyOpener(Model *model, bool writable = false, bool openLater = true); 270 ~ModelNodeLazyOpener(); 271 272 bool IsOpen() const; 273 bool IsOpenForWriting() const; 274 bool IsOpen(bool forWriting) const; 275 Model *TargetModel() const; 276 status_t OpenNode(bool writable = false); 277 278 private: 279 Model *fModel; 280 bool fWasOpen; 281 bool fWasOpenForWriting; 282 }; 283 284 // handy flavors of openers 285 class BModelOpener : public ModelNodeLazyOpener { 286 public: 287 BModelOpener(Model *model) 288 : ModelNodeLazyOpener(model, false, false) 289 { 290 } 291 }; 292 293 class BModelWriteOpener : public ModelNodeLazyOpener { 294 public: 295 BModelWriteOpener(Model *model) 296 : ModelNodeLazyOpener(model, true, false) 297 { 298 } 299 }; 300 301 302 #if DEBUG 303 // #define CHECK_OPEN_MODEL_LEAKS 304 #endif 305 306 #ifdef CHECK_OPEN_MODEL_LEAKS 307 void DumpOpenModels(bool extensive); 308 void InitOpenModelDumping(); 309 #endif 310 311 // inlines follow ----------------------------------- 312 313 inline const char * 314 Model::MimeType() const 315 { 316 return fMimeType.String(); 317 } 318 319 320 inline const entry_ref * 321 Model::EntryRef() const 322 { 323 return &fEntryRef; 324 } 325 326 327 inline const node_ref * 328 Model::NodeRef() const 329 { 330 // the stat structure begins with a node_ref 331 return (node_ref *)&fStatBuf; 332 } 333 334 335 inline BNode * 336 Model::Node() const 337 { 338 return fNode; 339 } 340 341 342 inline const StatStruct * 343 Model::StatBuf() const 344 { 345 return &fStatBuf; 346 } 347 348 349 inline IconSource 350 Model::IconFrom() const 351 { 352 return (IconSource)fIconFrom; 353 } 354 355 356 inline void 357 Model::SetIconFrom(IconSource from) 358 { 359 fIconFrom = from; 360 } 361 362 363 inline Model * 364 Model::LinkTo() const 365 { 366 ASSERT(IsSymLink()); 367 return fLinkTo; 368 } 369 370 371 inline bool 372 Model::IsFile() const 373 { 374 return fBaseType == kPlainNode 375 || fBaseType == kQueryNode 376 || fBaseType == kQueryTemplateNode 377 || fBaseType == kExecutableNode; 378 } 379 380 381 inline bool 382 Model::IsVolume() const 383 { 384 return fBaseType == kVolumeNode; 385 } 386 387 388 inline bool 389 Model::IsDirectory() const 390 { 391 return fBaseType == kDirectoryNode 392 || fBaseType == kVolumeNode 393 || fBaseType == kRootNode 394 || fBaseType == kTrashNode 395 || fBaseType == kDesktopNode; 396 } 397 398 399 inline bool 400 Model::IsQuery() const 401 { 402 return fBaseType == kQueryNode; 403 } 404 405 406 inline bool 407 Model::IsQueryTemplate() const 408 { 409 return fBaseType == kQueryTemplateNode; 410 } 411 412 413 inline bool 414 Model::IsContainer() const 415 { 416 // I guess as in should show container window - 417 // volumes show the volume window 418 return IsQuery() || IsDirectory(); 419 } 420 421 422 inline bool 423 Model::IsRoot() const 424 { 425 return fBaseType == kRootNode; 426 } 427 428 429 inline bool 430 Model::IsTrash() const 431 { 432 return fBaseType == kTrashNode; 433 } 434 435 436 inline bool 437 Model::IsDesktop() const 438 { 439 return fBaseType == kDesktopNode; 440 } 441 442 443 inline bool 444 Model::IsExecutable() const 445 { 446 return fBaseType == kExecutableNode; 447 } 448 449 450 inline bool 451 Model::IsSymLink() const 452 { 453 return fBaseType == kLinkNode; 454 } 455 456 457 inline bool 458 Model::HasLocalizedName() const 459 { 460 return fHasLocalizedName; 461 } 462 463 464 inline 465 ModelNodeLazyOpener::ModelNodeLazyOpener(Model *model, bool writable, bool openLater) 466 : fModel(model), 467 fWasOpen(model->IsNodeOpen()), 468 fWasOpenForWriting(model->IsNodeOpenForWriting()) 469 { 470 if (!openLater) 471 OpenNode(writable); 472 } 473 474 475 inline 476 ModelNodeLazyOpener::~ModelNodeLazyOpener() 477 { 478 if (!fModel->IsNodeOpen()) 479 return; 480 if (!fWasOpen) 481 fModel->CloseNode(); 482 else if (!fWasOpenForWriting) 483 fModel->OpenNode(); 484 } 485 486 487 inline bool 488 ModelNodeLazyOpener::IsOpen() const 489 { 490 return fModel->IsNodeOpen(); 491 } 492 493 494 inline bool 495 ModelNodeLazyOpener::IsOpenForWriting() const 496 { 497 return fModel->IsNodeOpenForWriting(); 498 } 499 500 501 inline bool 502 ModelNodeLazyOpener::IsOpen(bool forWriting) const 503 { 504 return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen(); 505 } 506 507 508 inline Model * 509 ModelNodeLazyOpener::TargetModel() const 510 { 511 return fModel; 512 } 513 514 515 inline status_t 516 ModelNodeLazyOpener::OpenNode(bool writable) 517 { 518 if (writable) { 519 if (!fModel->IsNodeOpenForWriting()) 520 return fModel->OpenNode(true); 521 } else if (!fModel->IsNodeOpen()) 522 return fModel->OpenNode(); 523 524 return B_OK; 525 } 526 527 528 } // namespace BPrivate 529 530 531 #endif 532