xref: /haiku/src/kits/tracker/Model.h (revision 3d4afef9cba2f328e238089d4609d00d4b1524f3)
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 	bool CheckNodeIconHint() const;
216 	bool CheckAppIconHint() const;
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 		kVirtualDirectoryNode,
243 		kUnknownNode
244 	};
245 
246 	entry_ref fEntryRef;
247 	StatStruct fStatBuf;
248 	BString fMimeType;
249 		// should use string that may be shared for common types
250 
251 	// bit of overloading hackery here to save on footprint
252 	union {
253 		char* fPreferredAppName;	// used if we are neither a volume
254 									// nor a symlink
255 		char* fVolumeName;			// used if we are a volume
256 		Model* fLinkTo;				// used if we are a symlink
257 	};
258 
259 	uint8 fBaseType;
260 	uint8 fIconFrom;
261 	bool fWritable;
262 	BNode* fNode;
263 	status_t fStatus;
264 	BString fLocalizedName;
265 	bool fHasLocalizedName;
266 	bool fLocalizedNameIsCached;
267 };
268 
269 
270 class ModelNodeLazyOpener {
271 	// a utility open state manager, usefull to allocate on stack
272 	// and have close up model when done, etc.
273 	public:
274 		// consider failing when open does not succeed
275 
276 		ModelNodeLazyOpener(Model* model, bool writable = false,
277 			bool openLater = true);
278 		~ModelNodeLazyOpener();
279 
280 		bool IsOpen() const;
281 		bool IsOpenForWriting() const;
282 		bool IsOpen(bool forWriting) const;
283 		Model* TargetModel() const;
284 		status_t OpenNode(bool writable = false);
285 
286 	private:
287 		Model* fModel;
288 		bool fWasOpen;
289 		bool fWasOpenForWriting;
290 };
291 
292 // handy flavors of openers
293 class BModelOpener : public ModelNodeLazyOpener {
294 	public:
295 		BModelOpener(Model* model)
296 		:	ModelNodeLazyOpener(model, false, false)
297 		{
298 		}
299 };
300 
301 class BModelWriteOpener : public ModelNodeLazyOpener {
302 	public:
303 		BModelWriteOpener(Model* model)
304 		:	ModelNodeLazyOpener(model, true, false)
305 		{
306 		}
307 };
308 
309 
310 #if DEBUG
311 // #define CHECK_OPEN_MODEL_LEAKS
312 #endif
313 
314 #ifdef CHECK_OPEN_MODEL_LEAKS
315 void DumpOpenModels(bool extensive);
316 void InitOpenModelDumping();
317 #endif
318 
319 // inlines follow -----------------------------------
320 
321 inline const char*
322 Model::MimeType() const
323 {
324 	return fMimeType.String();
325 }
326 
327 
328 inline const entry_ref*
329 Model::EntryRef() const
330 {
331 	return &fEntryRef;
332 }
333 
334 
335 inline const node_ref*
336 Model::NodeRef() const
337 {
338 	// the stat structure begins with a node_ref
339 	return (node_ref*)&fStatBuf;
340 }
341 
342 
343 inline BNode*
344 Model::Node() const
345 {
346 	return fNode;
347 }
348 
349 
350 inline const StatStruct*
351 Model::StatBuf() const
352 {
353 	return &fStatBuf;
354 }
355 
356 
357 inline IconSource
358 Model::IconFrom() const
359 {
360 	return (IconSource)fIconFrom;
361 }
362 
363 
364 inline void
365 Model::SetIconFrom(IconSource from)
366 {
367 	fIconFrom = from;
368 }
369 
370 
371 inline Model*
372 Model::LinkTo() const
373 {
374 	ASSERT(IsSymLink());
375 	return fLinkTo;
376 }
377 
378 
379 inline bool
380 Model::IsFile() const
381 {
382 	return fBaseType == kPlainNode
383 		|| fBaseType == kQueryNode
384 		|| fBaseType == kQueryTemplateNode
385 		|| fBaseType == kExecutableNode
386 		|| fBaseType == kVirtualDirectoryNode;
387 }
388 
389 
390 inline bool
391 Model::IsVolume() const
392 {
393 	return fBaseType == kVolumeNode;
394 }
395 
396 
397 inline bool
398 Model::IsDirectory() const
399 {
400 	return fBaseType == kDirectoryNode
401 		|| fBaseType == kVolumeNode
402 		|| fBaseType == kRootNode
403 		|| fBaseType == kTrashNode
404 		|| fBaseType == kDesktopNode;
405 }
406 
407 
408 inline bool
409 Model::IsQuery() const
410 {
411 	return fBaseType == kQueryNode;
412 }
413 
414 
415 inline bool
416 Model::IsQueryTemplate() const
417 {
418 	return fBaseType == kQueryTemplateNode;
419 }
420 
421 
422 inline bool
423 Model::IsContainer() const
424 {
425 	// I guess as in should show container window -
426 	// volumes show the volume window
427 	return IsQuery() || IsDirectory() || IsVirtualDirectory();
428 }
429 
430 
431 inline bool
432 Model::IsRoot() const
433 {
434 	return fBaseType == kRootNode;
435 }
436 
437 
438 inline bool
439 Model::IsTrash() const
440 {
441 	return fBaseType == kTrashNode;
442 }
443 
444 
445 inline bool
446 Model::IsDesktop() const
447 {
448 	return fBaseType == kDesktopNode;
449 }
450 
451 
452 inline bool
453 Model::IsExecutable() const
454 {
455 	return fBaseType == kExecutableNode;
456 }
457 
458 
459 inline bool
460 Model::IsSymLink() const
461 {
462 	return fBaseType == kLinkNode;
463 }
464 
465 
466 inline bool
467 Model::IsVirtualDirectory() const
468 {
469 	return fBaseType == kVirtualDirectoryNode;
470 }
471 
472 
473 inline bool
474 Model::HasLocalizedName() const
475 {
476 	return fHasLocalizedName;
477 }
478 
479 
480 inline
481 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable,
482 	bool openLater)
483 	:
484 	fModel(model),
485 	fWasOpen(model->IsNodeOpen()),
486 	fWasOpenForWriting(model->IsNodeOpenForWriting())
487 {
488 	if (!openLater)
489 		OpenNode(writable);
490 }
491 
492 
493 inline
494 ModelNodeLazyOpener::~ModelNodeLazyOpener()
495 {
496 	if (!fModel->IsNodeOpen())
497 		return;
498 	if (!fWasOpen)
499 		fModel->CloseNode();
500 	else if (!fWasOpenForWriting)
501 		fModel->OpenNode();
502 }
503 
504 
505 inline bool
506 ModelNodeLazyOpener::IsOpen() const
507 {
508 	return fModel->IsNodeOpen();
509 }
510 
511 
512 inline bool
513 ModelNodeLazyOpener::IsOpenForWriting() const
514 {
515 	return fModel->IsNodeOpenForWriting();
516 }
517 
518 
519 inline bool
520 ModelNodeLazyOpener::IsOpen(bool forWriting) const
521 {
522 	return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen();
523 }
524 
525 
526 inline Model*
527 ModelNodeLazyOpener::TargetModel() const
528 {
529 	return fModel;
530 }
531 
532 
533 inline status_t
534 ModelNodeLazyOpener::OpenNode(bool writable)
535 {
536 	if (writable) {
537 		if (!fModel->IsNodeOpenForWriting())
538 			return fModel->OpenNode(true);
539 	} else if (!fModel->IsNodeOpen())
540 		return fModel->OpenNode();
541 
542 	return B_OK;
543 }
544 
545 } // namespace BPrivate
546 
547 
548 #endif	// _NU_MODEL_H
549