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