6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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:
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.
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.
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.
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.
35 // Dedicated to BModel
38 // Consider moving iconFrom logic to BPose
39 // use a more efficient way of storing file type and preferred app strings
54 #include <Directory.h>
59 #include <NodeMonitor.h>
64 #include <VolumeRoster.h>
66 #include "Attributes.h"
68 #include "FindPanel.h"
70 #include "MimeTypes.h"
72 #include "Utilities.h"
75 #undef B_TRANSLATION_CONTEXT
76 #define B_TRANSLATION_CONTEXT "Model"
79 #ifdef CHECK_OPEN_MODEL_LEAKS
80 BObjectList
<Model
>* writableOpenModelList
= NULL
;
81 BObjectList
<Model
>* readOnlyOpenModelList
= NULL
;
86 CheckNodeIconHint(BNode
* node
)
92 if (node
->GetAttrInfo(kAttrIcon
, &info
) == B_OK
93 // has a vector icon, or
94 || (node
->GetAttrInfo(kAttrMiniIcon
, &info
) == B_OK
95 && node
->GetAttrInfo(kAttrLargeIcon
, &info
) == B_OK
)) {
96 // has a mini _and_ large icon
104 // #pragma mark - Model()
109 fPreferredAppName(NULL
),
110 fBaseType(kUnknownNode
),
111 fIconFrom(kUnknownSource
),
115 fHasLocalizedName(false),
116 fLocalizedNameIsCached(false)
121 Model::Model(const Model
& other
)
123 fEntryRef(other
.fEntryRef
),
124 fMimeType(other
.fMimeType
),
125 fPreferredAppName(NULL
),
126 fBaseType(other
.fBaseType
),
127 fIconFrom(other
.fIconFrom
),
130 fLocalizedName(other
.fLocalizedName
),
131 fHasLocalizedName(other
.fHasLocalizedName
),
132 fLocalizedNameIsCached(other
.fLocalizedNameIsCached
)
134 fStatBuf
.st_dev
= other
.NodeRef()->device
;
135 fStatBuf
.st_ino
= other
.NodeRef()->node
;
137 if (other
.IsSymLink() && other
.LinkTo())
138 fLinkTo
= new Model(*other
.LinkTo());
140 fStatus
= OpenNode(other
.IsNodeOpenForWriting());
141 if (fStatus
== B_OK
) {
143 fNode
->GetStat(&fStatBuf
);
144 ASSERT(fStatBuf
.st_dev
== other
.NodeRef()->device
);
145 ASSERT(fStatBuf
.st_ino
== other
.NodeRef()->node
);
147 if (!other
.IsNodeOpen())
152 Model::Model(const node_ref
* dirNode
, const node_ref
* node
, const char* name
,
153 bool open
, bool writable
)
155 fPreferredAppName(NULL
),
158 fHasLocalizedName(false),
159 fLocalizedNameIsCached(false)
161 SetTo(dirNode
, node
, name
, open
, writable
);
165 Model::Model(const BEntry
* entry
, bool open
, bool writable
)
167 fPreferredAppName(NULL
),
170 fHasLocalizedName(false),
171 fLocalizedNameIsCached(false)
173 SetTo(entry
, open
, writable
);
177 Model::Model(const entry_ref
* ref
, bool traverse
, bool open
, bool writable
)
179 fPreferredAppName(NULL
),
180 fBaseType(kUnknownNode
),
181 fIconFrom(kUnknownSource
),
184 fHasLocalizedName(false),
185 fLocalizedNameIsCached(false)
187 BEntry
entry(ref
, traverse
);
188 fStatus
= entry
.InitCheck();
190 SetTo(&entry
, open
, writable
);
195 Model::DeletePreferredAppVolumeNameLinkTo()
198 Model
* tmp
= fLinkTo
;
199 // deal with link to link to self
202 } else if (IsVolume())
205 free(fPreferredAppName
);
207 fPreferredAppName
= NULL
;
213 #ifdef CHECK_OPEN_MODEL_LEAKS
214 if (writableOpenModelList
!= NULL
)
215 writableOpenModelList
->RemoveItem(this);
217 if (readOnlyOpenModelList
!= NULL
)
218 readOnlyOpenModelList
->RemoveItem(this);
221 DeletePreferredAppVolumeNameLinkTo();
222 if (IconCache::NeedsDeletionNotification((IconSource
)fIconFrom
)) {
223 // this check allows us to use temporary Model in the IconCache
224 // without the danger of a deadlock
225 IconCache::sIconCache
->Deleting(this);
229 PRINT(("destructor closing node for %s\n", Name()));
237 Model::SetTo(const BEntry
* entry
, bool open
, bool writable
)
241 DeletePreferredAppVolumeNameLinkTo();
242 fIconFrom
= kUnknownSource
;
243 fBaseType
= kUnknownNode
;
246 fStatus
= entry
->GetRef(&fEntryRef
);
250 fStatus
= entry
->GetStat(&fStatBuf
);
254 fStatus
= OpenNode(writable
);
263 Model::SetTo(const entry_ref
* newRef
, bool traverse
, bool open
, bool writable
)
267 DeletePreferredAppVolumeNameLinkTo();
268 fIconFrom
= kUnknownSource
;
269 fBaseType
= kUnknownNode
;
272 BEntry
tmpEntry(newRef
, traverse
);
273 fStatus
= tmpEntry
.InitCheck();
278 tmpEntry
.GetRef(&fEntryRef
);
282 fStatus
= tmpEntry
.GetStat(&fStatBuf
);
286 fStatus
= OpenNode(writable
);
295 Model::SetTo(const node_ref
* dirNode
, const node_ref
* nodeRef
,
296 const char* name
, bool open
, bool writable
)
300 DeletePreferredAppVolumeNameLinkTo();
301 fIconFrom
= kUnknownSource
;
302 fBaseType
= kUnknownNode
;
305 fStatBuf
.st_dev
= nodeRef
->device
;
306 fStatBuf
.st_ino
= nodeRef
->node
;
307 fEntryRef
.device
= dirNode
->device
;
308 fEntryRef
.directory
= dirNode
->node
;
309 fEntryRef
.name
= strdup(name
);
311 BEntry
tmpNode(&fEntryRef
);
312 fStatus
= tmpNode
.InitCheck();
316 fStatus
= tmpNode
.GetStat(&fStatBuf
);
320 fStatus
= OpenNode(writable
);
330 Model::InitCheck() const
337 Model::CompareFolderNamesFirst(const Model
* compareModel
) const
339 if (compareModel
== NULL
)
342 const Model
* resolvedCompareModel
= compareModel
->ResolveIfLink();
343 const Model
* resolvedMe
= ResolveIfLink();
345 bool meIsDirOrVolume
= resolvedMe
->IsDirectory() || resolvedMe
->IsVolume()
346 || resolvedMe
->IsVirtualDirectory();
347 bool otherIsDirOrVolume
= resolvedCompareModel
->IsDirectory()
348 || resolvedCompareModel
->IsVolume()
349 || resolvedCompareModel
->IsVirtualDirectory();
351 if (meIsDirOrVolume
) {
352 if (!otherIsDirOrVolume
)
354 } else if (otherIsDirOrVolume
)
357 return NaturalCompare(Name(), compareModel
->Name());
364 static const char* kRootNodeName
= B_TRANSLATE_MARK(B_DISKS_DIR_NAME
);
365 static const char* kTrashNodeName
= B_TRANSLATE_MARK(B_TRASH_DIR_NAME
);
366 static const char* kDesktopNodeName
= B_TRANSLATE_MARK(B_DESKTOP_DIR_NAME
);
370 return B_TRANSLATE_NOCOLLECT(kRootNodeName
);
373 if (fVolumeName
!= NULL
)
378 return B_TRANSLATE_NOCOLLECT(kTrashNodeName
);
381 return B_TRANSLATE_NOCOLLECT(kDesktopNodeName
);
387 if (fHasLocalizedName
&& gLocalizedNamePreferred
)
388 return fLocalizedName
.String();
390 return fEntryRef
.name
;
395 Model::OpenNode(bool writable
)
397 if (IsNodeOpen() && (writable
== IsNodeOpenForWriting()))
400 OpenNodeCommon(writable
);
407 Model::UpdateStatAndOpenNode(bool writable
)
409 if (IsNodeOpen() && (writable
== IsNodeOpenForWriting()))
412 // try reading the stat structure again
413 BEntry
tmpEntry(&fEntryRef
);
414 fStatus
= tmpEntry
.InitCheck();
418 fStatus
= tmpEntry
.GetStat(&fStatBuf
);
422 OpenNodeCommon(writable
);
429 Model::OpenNodeCommon(bool writable
)
432 PRINT(("opening node for %s\n", Name()));
435 #ifdef CHECK_OPEN_MODEL_LEAKS
436 if (writableOpenModelList
!= NULL
)
437 writableOpenModelList
->RemoveItem(this);
439 if (readOnlyOpenModelList
!= NULL
)
440 readOnlyOpenModelList
->RemoveItem(this);
443 if (fBaseType
== kUnknownNode
)
448 case kExecutableNode
:
450 case kQueryTemplateNode
:
451 case kVirtualDirectoryNode
:
454 fNode
= new BFile(&fEntryRef
,
455 (uint32
)(writable
? O_RDWR
: O_RDONLY
));
464 fNode
= new BDirectory(&fEntryRef
);
466 if (fBaseType
== kDirectoryNode
467 && static_cast<BDirectory
*>(fNode
)->IsRootDirectory()) {
468 // promote from directory to volume
469 fBaseType
= kVolumeNode
;
475 BEntry
entry(&fEntryRef
);
476 fNode
= new BSymLink(&entry
);
485 // this can only happen if GetStat failed before,
486 // in which case we shouldn't be here
488 // ToDo: Obviously, we can also be here if the type could not
489 // be determined, for example for block devices (so the TRESPASS()
490 // macro shouldn't be used here)!
491 return fStatus
= B_ERROR
;
494 fStatus
= fNode
->InitCheck();
495 if (fStatus
!= B_OK
) {
498 // original code snoozed an error here and returned B_OK
502 fWritable
= writable
;
504 if (fMimeType
.Length() <= 0)
505 FinishSettingUpType();
507 #ifdef CHECK_OPEN_MODEL_LEAKS
509 if (!writableOpenModelList
) {
511 writableOpenModelList
= new BObjectList
<Model
>(100);
513 writableOpenModelList
->AddItem(this);
515 if (!readOnlyOpenModelList
) {
517 readOnlyOpenModelList
= new BObjectList
<Model
>(100);
519 readOnlyOpenModelList
->AddItem(this);
523 if (gLocalizedNamePreferred
)
524 CacheLocalizedName();
534 PRINT(("closing node for %s\n", Name()));
537 #ifdef CHECK_OPEN_MODEL_LEAKS
538 if (writableOpenModelList
!= NULL
)
539 writableOpenModelList
->RemoveItem(this);
541 if (readOnlyOpenModelList
!= NULL
)
542 readOnlyOpenModelList
->RemoveItem(this);
551 Model::IsNodeOpen() const
553 return fNode
!= NULL
;
559 Model::IsNodeOpenForWriting() const
561 return fNode
!= NULL
&& fWritable
;
566 Model::SetupBaseType()
568 switch (fStatBuf
.st_mode
& S_IFMT
) {
571 fBaseType
= kDirectoryNode
;
576 if ((fStatBuf
.st_mode
& S_IXUSR
) != 0) {
578 fBaseType
= kExecutableNode
;
581 fBaseType
= kPlainNode
;
587 fBaseType
= kLinkNode
;
591 fBaseType
= kUnknownNode
;
598 Model::CacheLocalizedName()
600 if (!fLocalizedNameIsCached
) {
601 fLocalizedNameIsCached
= true;
602 if (BLocaleRoster::Default()->GetLocalizedFileName(
603 fLocalizedName
, fEntryRef
, true) == B_OK
)
604 fHasLocalizedName
= true;
606 fHasLocalizedName
= false;
612 Model::FinishSettingUpType()
614 char mimeString
[B_MIME_TYPE_LENGTH
];
617 // While we are reading the node, do a little snooping to see if it even
618 // makes sense to look for a node-based icon. This serves as a hint to the
619 // icon cache, allowing it to not hit the disk again for models that do not
620 // have an icon defined by the node.
621 if (IsNodeOpen() && fBaseType
!= kLinkNode
&& !CheckNodeIconHint(fNode
))
622 fIconFrom
= kUnknownNotFromNode
;
624 if (fBaseType
!= kDirectoryNode
625 && fBaseType
!= kVolumeNode
626 && fBaseType
!= kLinkNode
628 BNodeInfo
info(fNode
);
630 // check if a specific mime type is set
631 if (info
.GetType(mimeString
) == B_OK
) {
632 // node has a specific mime type
633 fMimeType
= mimeString
;
634 if (strcmp(mimeString
, B_QUERY_MIMETYPE
) == 0)
635 fBaseType
= kQueryNode
;
636 else if (strcmp(mimeString
, B_QUERY_TEMPLATE_MIMETYPE
) == 0)
637 fBaseType
= kQueryTemplateNode
;
638 else if (strcmp(mimeString
, kVirtualDirectoryMimeType
) == 0)
639 fBaseType
= kVirtualDirectoryNode
;
641 if (info
.GetPreferredApp(mimeString
) == B_OK
) {
642 if (fPreferredAppName
)
643 DeletePreferredAppVolumeNameLinkTo();
646 fPreferredAppName
= strdup(mimeString
);
653 entry
.SetTo(&fEntryRef
);
654 if (entry
.InitCheck() == B_OK
) {
655 if (FSIsTrashDir(&entry
))
656 fBaseType
= kTrashNode
;
657 else if (FSIsDeskDir(&entry
))
658 fBaseType
= kDesktopNode
;
661 fMimeType
= B_DIR_MIMETYPE
;
662 // should use a shared string here
664 BNodeInfo
info(fNode
);
665 if (info
.GetType(mimeString
) == B_OK
)
666 fMimeType
= mimeString
;
668 if (fIconFrom
== kUnknownNotFromNode
669 && WellKnowEntryList::Match(NodeRef())
670 > (directory_which
)-1) {
671 // one of home, beos, system, boot, etc.
672 fIconFrom
= kTrackerSupplied
;
679 if (NodeRef()->node
== fEntryRef
.directory
680 && NodeRef()->device
== fEntryRef
.device
) {
681 // promote from volume to file system root
682 fBaseType
= kRootNode
;
683 fMimeType
= B_ROOT_MIMETYPE
;
687 // volumes have to have a B_VOLUME_MIMETYPE type
688 fMimeType
= B_VOLUME_MIMETYPE
;
689 if (fIconFrom
== kUnknownNotFromNode
) {
690 if (WellKnowEntryList::Match(NodeRef()) > (directory_which
)-1)
691 fIconFrom
= kTrackerSupplied
;
696 char name
[B_FILE_NAME_LENGTH
];
697 BVolume
volume(NodeRef()->device
);
698 if (volume
.InitCheck() == B_OK
&& volume
.GetName(name
) == B_OK
) {
699 if (fVolumeName
!= NULL
)
700 DeletePreferredAppVolumeNameLinkTo();
702 fVolumeName
= strdup(name
);
706 PRINT(("get volume name failed for %s\n", fEntryRef
.name
));
712 fMimeType
= B_LINK_MIMETYPE
;
713 // should use a shared string here
716 case kExecutableNode
:
718 char signature
[B_MIME_TYPE_LENGTH
];
719 if (GetAppSignatureFromAttr(dynamic_cast<BFile
*>(fNode
),
720 signature
) == B_OK
) {
721 if (fPreferredAppName
)
722 DeletePreferredAppVolumeNameLinkTo();
725 fPreferredAppName
= strdup(signature
);
728 if (fMimeType
.Length() <= 0)
729 fMimeType
= B_APP_MIME_TYPE
;
730 // should use a shared string here
734 if (fMimeType
.Length() <= 0)
735 fMimeType
= B_FILE_MIMETYPE
;
742 Model::ResetIconFrom()
744 BModelOpener
opener(this);
746 if (InitCheck() != B_OK
)
749 // mirror the logic from FinishSettingUpType
750 if ((fBaseType
== kDirectoryNode
|| fBaseType
== kVolumeNode
751 || fBaseType
== kTrashNode
|| fBaseType
== kDesktopNode
)
752 && !CheckNodeIconHint(fNode
)) {
753 BDirectory
* directory
= dynamic_cast<BDirectory
*>(fNode
);
754 if (WellKnowEntryList::Match(NodeRef()) > (directory_which
)-1) {
755 fIconFrom
= kTrackerSupplied
;
757 } else if (directory
!= NULL
&& directory
->IsRootDirectory()) {
762 fIconFrom
= kUnknownSource
;
767 Model::PreferredAppSignature() const
769 if (IsVolume() || IsSymLink())
772 return fPreferredAppName
? fPreferredAppName
: "";
777 Model::SetPreferredAppSignature(const char* signature
)
779 ASSERT(!IsVolume() && !IsSymLink());
780 ASSERT(signature
!= fPreferredAppName
);
781 // self assignment should not be an option
783 free(fPreferredAppName
);
785 fPreferredAppName
= strdup(signature
);
787 fPreferredAppName
= NULL
;
792 Model::ResolveIfLink() const
805 Model::ResolveIfLink()
818 Model::SetLinkTo(Model
* model
)
821 ASSERT(!fLinkTo
|| (fLinkTo
!= model
));
829 Model::GetPreferredAppForBrokenSymLink(BString
&result
)
831 if (!IsSymLink() || LinkTo()) {
836 BModelOpener
opener(this);
837 BNodeInfo
info(fNode
);
839 = info
.GetPreferredApp(result
.LockBuffer(B_MIME_TYPE_LENGTH
));
840 result
.UnlockBuffer();
843 // Tracker will have to do
844 result
= kTrackerSignature
;
849 // #pragma mark - Node monitor updating methods
853 Model::UpdateEntryRef(const node_ref
* dirNode
, const char* name
)
856 if (fVolumeName
!= NULL
)
857 DeletePreferredAppVolumeNameLinkTo();
859 fVolumeName
= strdup(name
);
862 fEntryRef
.device
= dirNode
->device
;
863 fEntryRef
.directory
= dirNode
->node
;
865 if (fEntryRef
.name
!= NULL
&& strcmp(fEntryRef
.name
, name
) == 0)
868 fEntryRef
.set_name(name
);
873 Model::WatchVolumeAndMountPoint(uint32
, BHandler
* target
)
877 if (fEntryRef
.name
!= NULL
&& fVolumeName
!= NULL
878 && strcmp(fEntryRef
.name
, "boot") == 0) {
879 // watch mount point for boot volume
880 BString
bootMountPoint("/");
881 bootMountPoint
+= fVolumeName
;
882 BEntry
mountPointEntry(bootMountPoint
.String());
883 Model
mountPointModel(&mountPointEntry
);
885 TTracker::WatchNode(mountPointModel
.NodeRef(),
886 B_WATCH_NAME
| B_WATCH_STAT
| B_WATCH_ATTR
, target
);
889 return TTracker::WatchNode(NodeRef(),
890 B_WATCH_NAME
| B_WATCH_STAT
| B_WATCH_ATTR
, target
);
895 Model::AttrChanged(const char* attrName
)
897 // called on an attribute changed node monitor
898 // sync up cached values of mime type and preferred app and
899 // return true if icon needs updating
901 ASSERT(IsNodeOpen());
903 && (strcmp(attrName
, kAttrIcon
) == 0
904 || strcmp(attrName
, kAttrMiniIcon
) == 0
905 || strcmp(attrName
, kAttrLargeIcon
) == 0)) {
910 || strcmp(attrName
, kAttrMIMEType
) == 0
911 || strcmp(attrName
, kAttrPreferredApp
) == 0) {
912 char mimeString
[B_MIME_TYPE_LENGTH
];
913 BNodeInfo
info(fNode
);
914 if (info
.GetType(mimeString
) != B_OK
)
917 // node has a specific mime type
918 fMimeType
= mimeString
;
919 if (!IsVolume() && !IsSymLink()
920 && info
.GetPreferredApp(mimeString
) == B_OK
) {
921 SetPreferredAppSignature(mimeString
);
926 if (fIconFrom
!= kNode
) {
927 PRINT(("%s, %s:updating icon because file type changed\n",
928 Name(), attrName
!= NULL
? attrName
: ""));
930 PRINT(("Not updating icon even though type changed "
931 "because icon is from node.\n"));
935 return fIconFrom
!= kNode
;
936 // update icon unless it is coming from a node
939 return attrName
== NULL
;
946 ASSERT(IsNodeOpen());
947 mode_t oldMode
= fStatBuf
.st_mode
;
948 fStatus
= fNode
->GetStat(&fStatBuf
);
950 if (oldMode
!= fStatBuf
.st_mode
) {
951 bool forWriting
= IsNodeOpenForWriting();
954 // the node type can't change with a stat update...
955 OpenNodeCommon(forWriting
);
963 // #pragma mark - Mime handling methods
967 Model::IsDropTarget(const Model
* forDocument
, bool traverse
) const
969 switch (CanHandleDrops()) {
980 if (forDocument
== NULL
)
984 BEntry
entry(forDocument
->EntryRef(), true);
985 if (entry
.InitCheck() != B_OK
)
988 BFile
file(&entry
, O_RDONLY
);
989 BNodeInfo
mime(&file
);
991 if (mime
.InitCheck() != B_OK
)
994 char mimeType
[B_MIME_TYPE_LENGTH
];
995 mime
.GetType(mimeType
);
997 return SupportsMimeType(mimeType
, 0) != kDoesNotSupportType
;
1000 // do some mime-based matching
1001 const char* documentMimeType
= forDocument
->MimeType();
1002 if (documentMimeType
== NULL
)
1005 return SupportsMimeType(documentMimeType
, 0) != kDoesNotSupportType
;
1009 Model::CanHandleResult
1010 Model::CanHandleDrops() const
1012 if (IsDirectory()) {
1013 // directories take anything
1014 // resolve permissions here
1019 // descend into symlink and try again on it's target
1021 BEntry
entry(&fEntryRef
, true);
1022 if (entry
.InitCheck() != B_OK
)
1023 return kCannotHandle
;
1025 if (entry
== BEntry(EntryRef()))
1026 // self-referencing link, avoid infinite recursion
1027 return kCannotHandle
;
1029 Model
model(&entry
);
1030 if (model
.InitCheck() != B_OK
)
1031 return kCannotHandle
;
1033 return model
.CanHandleDrops();
1037 return kNeedToCheckType
;
1039 return kCannotHandle
;
1044 IsSuperHandlerSignature(const char* signature
)
1046 return strcasecmp(signature
, B_FILE_MIMETYPE
) == 0;
1058 MatchMimeTypeString(/*const */BString
* documentType
, const char* handlerType
)
1060 // perform a mime type wildcard match
1061 // handler types of the form "text"
1062 // handle every handled type with same supertype,
1063 // for everything else a full string match is used
1065 int32 supertypeOnlyLength
= 0;
1066 const char* tmp
= strstr(handlerType
, "/");
1069 // no subtype - supertype string only
1070 supertypeOnlyLength
= (int32
)strlen(handlerType
);
1073 if (supertypeOnlyLength
) {
1074 // compare just the supertype
1075 tmp
= strstr(documentType
->String(), "/");
1076 if (tmp
&& (tmp
- documentType
->String() == supertypeOnlyLength
)) {
1077 if (documentType
->ICompare(handlerType
, supertypeOnlyLength
) == 0)
1078 return kMatchSupertype
;
1084 if (documentType
->ICompare(handlerType
) == 0)
1092 Model::SupportsMimeType(const char* type
, const BObjectList
<BString
>* list
,
1093 bool exactReason
) const
1095 ASSERT((type
== 0) != (list
== 0));
1096 // pass in one or the other
1098 int32 result
= kDoesNotSupportType
;
1100 BFile
file(EntryRef(), O_RDONLY
);
1101 BAppFileInfo
handlerInfo(&file
);
1104 if (handlerInfo
.GetSupportedTypes(&message
) != B_OK
)
1105 return kDoesNotSupportType
;
1107 for (int32 index
= 0; ; index
++) {
1108 // check if this model lists the type of dropped document as supported
1110 const char* mimeSignature
;
1111 ssize_t bufferLength
;
1113 if (message
.FindData("types", 'CSTR', index
,
1114 (const void**)&mimeSignature
, &bufferLength
)) {
1118 if (IsSuperHandlerSignature(mimeSignature
)) {
1120 return kSuperhandlerModel
;
1122 if (result
== kDoesNotSupportType
)
1123 result
= kSuperhandlerModel
;
1128 if (type
!= NULL
|| (list
!= NULL
&& list
->IsEmpty())) {
1129 BString
typeString(type
);
1130 match
= MatchMimeTypeString(&typeString
, mimeSignature
);
1132 match
= WhileEachListItem(const_cast<BObjectList
<BString
>*>(list
),
1133 MatchMimeTypeString
, mimeSignature
);
1134 // const_cast shouldnt be here, have to have it until
1137 if (match
== kMatch
)
1138 // supports the actual type, it can't get any better
1139 return kModelSupportsType
;
1140 else if (match
== kMatchSupertype
) {
1142 return kModelSupportsSupertype
;
1144 // we already know this model supports the file as a supertype,
1145 // now find out if it matches the type
1146 result
= kModelSupportsSupertype
;
1155 Model::IsDropTargetForList(const BObjectList
<BString
>* list
) const
1157 switch (CanHandleDrops()) {
1168 return SupportsMimeType(0, list
) != kDoesNotSupportType
;
1173 Model::IsSuperHandler() const
1175 ASSERT(CanHandleDrops() == kNeedToCheckType
);
1177 BFile
file(EntryRef(), O_RDONLY
);
1178 BAppFileInfo
handlerInfo(&file
);
1181 if (handlerInfo
.GetSupportedTypes(&message
) != B_OK
)
1184 for (int32 index
= 0; ; index
++) {
1185 const char* mimeSignature
;
1186 ssize_t bufferLength
;
1188 if (message
.FindData("types", 'CSTR', index
,
1189 (const void**)&mimeSignature
, &bufferLength
)) {
1193 if (IsSuperHandlerSignature(mimeSignature
))
1201 Model::GetEntry(BEntry
* entry
) const
1203 entry
->SetTo(EntryRef());
1208 Model::GetPath(BPath
* path
) const
1210 BEntry
entry(EntryRef());
1211 entry
.GetPath(path
);
1216 Model::Mimeset(bool force
)
1218 BString oldType
= MimeType();
1222 update_mime_info(path
.Path(), 0, 1, force
? 2 : 0);
1223 ModelNodeLazyOpener
opener(this);
1227 return !oldType
.ICompare(MimeType());
1232 Model::WriteAttr(const char* attr
, type_code type
, off_t offset
,
1233 const void* buffer
, size_t length
)
1235 BModelWriteOpener
opener(this);
1239 ssize_t result
= fNode
->WriteAttr(attr
, type
, offset
, buffer
, length
);
1245 Model::WriteAttrKillForeign(const char* attr
, const char* foreignAttr
,
1246 type_code type
, off_t offset
, const void* buffer
, size_t length
)
1248 BModelWriteOpener
opener(this);
1252 ssize_t result
= fNode
->WriteAttr(attr
, type
, offset
, buffer
, length
);
1253 if (result
== (ssize_t
)length
)
1254 // nuke attribute in opposite endianness
1255 fNode
->RemoveAttr(foreignAttr
);
1261 Model::GetLongVersionString(BString
&result
, version_kind kind
)
1263 BFile
file(EntryRef(), O_RDONLY
);
1264 status_t error
= file
.InitCheck();
1268 BAppFileInfo
info(&file
);
1269 error
= info
.InitCheck();
1273 version_info version
;
1274 error
= info
.GetVersionInfo(&version
, kind
);
1278 result
= version
.long_info
;
1283 Model::GetVersionString(BString
&result
, version_kind kind
)
1285 BFile
file(EntryRef(), O_RDONLY
);
1286 status_t error
= file
.InitCheck();
1290 BAppFileInfo
info(&file
);
1291 error
= info
.InitCheck();
1295 version_info version
;
1296 error
= info
.GetVersionInfo(&version
, kind
);
1300 result
.SetToFormat("%" B_PRId32
".%" B_PRId32
".%" B_PRId32
, version
.major
,
1301 version
.middle
, version
.minor
);
1309 Model::PrintToStream(int32 level
, bool deep
)
1311 PRINT(("model name %s, entry name %s, inode %" B_PRIdINO
", dev %"
1312 B_PRIdDEV
", directory inode %" B_PRIdINO
"\n",
1313 Name() ? Name() : "**empty name**",
1314 EntryRef()->name
? EntryRef()->name
: "**empty ref name**",
1317 EntryRef()->directory
));
1318 PRINT(("type %s \n", MimeType()));
1320 PRINT(("model type: "));
1321 switch (fBaseType
) {
1330 case kQueryTemplateNode
:
1331 PRINT(("query template\n"));
1334 case kExecutableNode
:
1338 case kDirectoryNode
:
1353 PRINT(("volume, name %s\n", fVolumeName
? fVolumeName
: ""));
1356 case kVirtualDirectoryNode
:
1357 PRINT(("virtual directory\n"));
1361 PRINT(("unknown\n"));
1369 PRINT(("preferred app %s\n",
1370 fPreferredAppName
? fPreferredAppName
: ""));
1373 PRINT(("icon from: "));
1374 switch (IconFrom()) {
1375 case kUnknownSource
:
1376 PRINT(("unknown\n"));
1379 case kUnknownNotFromNode
:
1380 PRINT(("unknown but not from a node\n"));
1383 case kTrackerDefault
:
1384 PRINT(("tracker default\n"));
1387 case kTrackerSupplied
:
1388 PRINT(("tracker supplied\n"));
1392 PRINT(("metamime\n"));
1395 case kPreferredAppForType
:
1396 PRINT(("preferred app for type\n"));
1399 case kPreferredAppForNode
:
1400 PRINT(("preferred app for node\n"));
1408 PRINT(("volume\n"));
1415 PRINT(("model %s opened %s \n", !IsNodeOpen() ? "not " : "",
1416 IsNodeOpenForWriting() ? "for writing" : ""));
1420 fNode
->GetNodeRef(&nodeRef
);
1421 PRINT(("node ref of open Node %" B_PRIdINO
" %" B_PRIdDEV
"\n",
1422 nodeRef
.node
, nodeRef
.device
));
1425 if (deep
&& IsSymLink()) {
1426 BEntry
tmpEntry(EntryRef(), true);
1427 Model
tmp(&tmpEntry
);
1428 PRINT(("symlink to:\n"));
1429 tmp
.PrintToStream();
1431 TrackIconSource(B_MINI_ICON
);
1432 TrackIconSource(B_LARGE_ICON
);
1437 Model::TrackIconSource(icon_size size
)
1439 PRINT(("tracking %s icon\n", size
== B_LARGE_ICON
? "large" : "small"));
1441 if (size
== B_MINI_ICON
)
1442 rect
.Set(0, 0, B_MINI_ICON
- 1, B_MINI_ICON
- 1);
1444 rect
.Set(0, 0, B_LARGE_ICON
- 1, B_LARGE_ICON
- 1);
1446 BBitmap
bitmap(rect
, B_CMAP8
);
1448 BModelOpener
opener(this);
1450 if (Node() == NULL
) {
1451 PRINT(("track icon error - no node\n"));
1456 PRINT(("tracking symlink icon\n"));
1458 fLinkTo
->TrackIconSource(size
);
1463 if (fBaseType
== kVolumeNode
) {
1464 BVolume
volume(NodeRef()->device
);
1465 status_t result
= volume
.GetIcon(&bitmap
, size
);
1466 PRINT(("getting icon from volume %s\n", strerror(result
)));
1468 BNodeInfo
nodeInfo(Node());
1470 status_t err
= nodeInfo
.GetIcon(&bitmap
, size
);
1472 // file knew which icon to use, we are done
1473 PRINT(("track icon - got icon from file\n"));
1477 char preferredApp
[B_MIME_TYPE_LENGTH
];
1478 err
= nodeInfo
.GetPreferredApp(preferredApp
);
1479 if (err
== B_OK
&& preferredApp
[0]) {
1480 BMimeType
preferredAppType(preferredApp
);
1481 err
= preferredAppType
.GetIconForType(MimeType(), &bitmap
, size
);
1484 ("track icon - got icon for type %s from preferred "
1485 "app %s for file\n", MimeType(), preferredApp
));
1490 BMimeType
mimeType(MimeType());
1491 err
= mimeType
.GetIcon(&bitmap
, size
);
1493 // the system knew what icon to use for the type, we are done
1494 PRINT(("track icon - signature %s, got icon from system\n",
1499 err
= mimeType
.GetPreferredApp(preferredApp
);
1501 // no preferred App for document, give up
1502 PRINT(("track icon - signature %s, no prefered app, error %s\n",
1503 MimeType(), strerror(err
)));
1507 BMimeType
preferredAppType(preferredApp
);
1508 err
= preferredAppType
.GetIconForType(MimeType(), &bitmap
, size
);
1510 // the preferred app knew icon to use for the type, we are done
1512 ("track icon - signature %s, got icon from preferred "
1513 "app %s\n", MimeType(), preferredApp
));
1517 ("track icon - signature %s, preferred app %s, no icon, "
1518 "error %s\n", MimeType(), preferredApp
, strerror(err
)));
1524 #ifdef CHECK_OPEN_MODEL_LEAKS
1526 namespace BPrivate
{
1531 DumpOpenModels(bool extensive
)
1533 if (readOnlyOpenModelList
) {
1534 int32 count
= readOnlyOpenModelList
->CountItems();
1535 printf("%ld models open read-only:\n", count
);
1536 printf("==========================\n");
1537 for (int32 index
= 0; index
< count
; index
++) {
1539 printf("---------------------------\n");
1540 readOnlyOpenModelList
->ItemAt(index
)->PrintToStream();
1542 printf("%s\n", readOnlyOpenModelList
->ItemAt(index
)->Name());
1546 if (writableOpenModelList
) {
1547 int32 count
= writableOpenModelList
->CountItems();
1548 printf("%ld models open writable:\n", count
);
1549 printf("models open writable:\n");
1550 printf("======================\n");
1551 for (int32 index
= 0; index
< count
; index
++) {
1553 printf("---------------------------\n");
1554 writableOpenModelList
->ItemAt(index
)->PrintToStream();
1556 printf("%s\n", writableOpenModelList
->ItemAt(index
)->Name());
1563 InitOpenModelDumping()
1565 readOnlyOpenModelList
= 0;
1566 writableOpenModelList
= 0;
1569 } // namespace BPrivate
1571 #endif // CHECK_OPEN_MODEL_LEAKS