xref: /haiku/src/kits/tracker/Model.h (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 IsFile() const;
131 	bool IsDirectory() const;
132 	bool IsQuery() const;
133 	bool IsQueryTemplate() const;
134 	bool IsContainer() const;
135 	bool IsExecutable() const;
136 	bool IsSymLink() const;
137 	bool IsRoot() const;
138 	bool IsTrash() const;
139 	bool IsDesktop() const;
140 	bool IsVolume() const;
141 	bool IsVirtualDirectory() 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,
162 		const char* attributeName, uint32 attributeType);
163 
164 	// Node monitor update call
165 	void UpdateEntryRef(const node_ref* dirRef, const char* name);
166 	bool AttrChanged(const char* attrName);
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,
192 		const BObjectList<BString>* list, 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,
203 		const char* foreignAttr, type_code type, off_t,
204 		const void* buffer, size_t);
205 
206 	bool Mimeset(bool force);
207 		// returns true if mime type changed
208 
209 	bool HasLocalizedName() const;
210 
211 private:
212 	status_t OpenNodeCommon(bool writable);
213 	void SetupBaseType();
214 	void FinishSettingUpType();
215 	void DeletePreferredAppVolumeNameLinkTo();
216 	void CacheLocalizedName();
217 
218 	status_t FetchOneQuery(const BQuery*, BHandler* target,
219 		BObjectList<BQuery>*, BVolume*);
220 
221 	enum CanHandleResult {
222 		kCanHandle,
223 		kCannotHandle,
224 		kNeedToCheckType
225 	};
226 
227 	CanHandleResult CanHandleDrops() const;
228 
229 	enum NodeType {
230 		kPlainNode,
231 		kExecutableNode,
232 		kDirectoryNode,
233 		kLinkNode,
234 		kQueryNode,
235 		kQueryTemplateNode,
236 		kVolumeNode,
237 		kRootNode,
238 		kTrashNode,
239 		kDesktopNode,
240 		kVirtualDirectoryNode,
241 		kUnknownNode
242 	};
243 
244 	entry_ref fEntryRef;
245 	StatStruct fStatBuf;
246 	BString fMimeType;
247 		// should use string that may be shared for common types
248 
249 	// bit of overloading hackery here to save on footprint
250 	union {
251 		char* fPreferredAppName;	// used if we are neither a volume
252 									// nor a symlink
253 		char* fVolumeName;			// used if we are a volume
254 		Model* fLinkTo;				// used if we are a symlink
255 	};
256 
257 	uint8 fBaseType;
258 	uint8 fIconFrom;
259 	bool fWritable;
260 	BNode* fNode;
261 	status_t fStatus;
262 	BString fLocalizedName;
263 	bool fHasLocalizedName;
264 	bool fLocalizedNameIsCached;
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 		|| fBaseType == kVirtualDirectoryNode;
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() || IsVirtualDirectory();
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::IsVirtualDirectory() const
466 {
467 	return fBaseType == kVirtualDirectoryNode;
468 }
469 
470 
471 inline bool
472 Model::HasLocalizedName() const
473 {
474 	return fHasLocalizedName;
475 }
476 
477 
478 inline
479 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable,
480 	bool openLater)
481 	:
482 	fModel(model),
483 	fWasOpen(model->IsNodeOpen()),
484 	fWasOpenForWriting(model->IsNodeOpenForWriting())
485 {
486 	if (!openLater)
487 		OpenNode(writable);
488 }
489 
490 
491 inline
492 ModelNodeLazyOpener::~ModelNodeLazyOpener()
493 {
494 	if (!fModel->IsNodeOpen())
495 		return;
496 	if (!fWasOpen)
497 		fModel->CloseNode();
498 	else if (!fWasOpenForWriting)
499 		fModel->OpenNode();
500 }
501 
502 
503 inline bool
504 ModelNodeLazyOpener::IsOpen() const
505 {
506 	return fModel->IsNodeOpen();
507 }
508 
509 
510 inline bool
511 ModelNodeLazyOpener::IsOpenForWriting() const
512 {
513 	return fModel->IsNodeOpenForWriting();
514 }
515 
516 
517 inline bool
518 ModelNodeLazyOpener::IsOpen(bool forWriting) const
519 {
520 	return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen();
521 }
522 
523 
524 inline Model*
525 ModelNodeLazyOpener::TargetModel() const
526 {
527 	return fModel;
528 }
529 
530 
531 inline status_t
532 ModelNodeLazyOpener::OpenNode(bool writable)
533 {
534 	if (writable) {
535 		if (!fModel->IsNodeOpenForWriting())
536 			return fModel->OpenNode(true);
537 	} else if (!fModel->IsNodeOpen())
538 		return fModel->OpenNode();
539 
540 	return B_OK;
541 }
542 
543 } // namespace BPrivate
544 
545 
546 #endif	// _NU_MODEL_H
547