xref: /haiku/src/kits/tracker/Model.h (revision 529cd177b573aaba391c8adc9c9f5ad76a14bf81)
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 &);
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 	void GetPreferredAppForBrokenSymLink(BString &result);
130 		// special purpose call - if a symlink is unresolvable, it makes
131 		// sense to be able to get at it's preferred handler which may be
132 		// different from the Tracker. Used by the network neighborhood.
133 
134 	// type getters
135 	bool IsFile() const;
136 	bool IsDirectory() const;
137 	bool IsQuery() const;
138 	bool IsQueryTemplate() const;
139 	bool IsContainer() const;
140 	bool IsExecutable() const;
141 	bool IsSymLink() const;
142 	bool IsRoot() const;
143 	bool IsTrash() const;
144 	bool IsDesktop() const;
145 	bool IsVolume() const;
146 	bool IsVirtualDirectory() const;
147 
148 	IconSource IconFrom() const;
149 	void SetIconFrom(IconSource);
150 		// where is this model getting it's icon from
151 
152 	void ResetIconFrom();
153 		// called from the attribute changed calls to force a lookup of
154 		// a new icon
155 
156 	// symlink handling calls, mainly used by the IconCache
157 	const Model* ResolveIfLink() const;
158 	Model* ResolveIfLink();
159 		// works on anything
160 	Model* LinkTo() const;
161 		// fast, works only on symlinks
162 	void SetLinkTo(Model*);
163 
164 	status_t GetLongVersionString(BString &, version_kind);
165 	status_t GetVersionString(BString &, version_kind);
166 	status_t AttrAsString(BString &, int64* value,
167 		const char* attributeName, uint32 attributeType);
168 
169 	// Node monitor update call
170 	void UpdateEntryRef(const node_ref* dirRef, const char* name);
171 	bool AttrChanged(const char* attrName);
172 		// returns true if pose needs to update it's icon, etc.
173 		// pass null to force full update
174 	bool StatChanged();
175 		// returns true if pose needs to update it's icon
176 
177 	status_t WatchVolumeAndMountPoint(uint32, BHandler*);
178 		// correctly handles boot volume name watching
179 
180 	bool IsDropTarget(const Model* forDocument = 0,
181 		bool traverse = false) const;
182 		// if nonzero <forDocument> passed, mime info is used to
183 		// resolve if document can be opened
184 		// if zero, all executables, directories and volumes pass
185 		// if traverse, dereference symlinks
186 	bool IsDropTargetForList(const BObjectList<BString>* list) const;
187 		// <list> contains mime types of all documents about to be handled
188 		// by model
189 
190 #if DEBUG
191 	void PrintToStream(int32 level = 1, bool deep = false);
192 	void TrackIconSource(icon_size);
193 #endif
194 
195 	bool IsSuperHandler() const;
196 	int32 SupportsMimeType(const char* type,
197 		const BObjectList<BString>* list, bool exactReason = false) const;
198 		// pass in one string in <type> or a bunch in <list>
199 		// if <exactReason> false, returns as soon as it figures out that
200 		// app supports a given type, if true, returns an exact reason
201 
202 	// get rid of this??
203 	ssize_t WriteAttr(const char* attr, type_code type, off_t,
204 		const void* buffer, size_t );
205 		// cover call, creates a writable node and writes out attributes
206 		// into it; work around for file nodes not being writeable
207 	ssize_t WriteAttrKillForeign(const char* attr,
208 		const char* foreignAttr, type_code type, off_t,
209 		const void* buffer, size_t);
210 
211 	bool Mimeset(bool force);
212 		// returns true if mime type changed
213 
214 	bool HasLocalizedName() const;
215 
216 private:
217 	status_t OpenNodeCommon(bool writable);
218 	void SetupBaseType();
219 	void FinishSettingUpType();
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:
298 		BModelOpener(Model* model)
299 		:	ModelNodeLazyOpener(model, false, false)
300 		{
301 		}
302 };
303 
304 class BModelWriteOpener : public ModelNodeLazyOpener {
305 	public:
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*
325 Model::MimeType() const
326 {
327 	return fMimeType.String();
328 }
329 
330 
331 inline const entry_ref*
332 Model::EntryRef() const
333 {
334 	return &fEntryRef;
335 }
336 
337 
338 inline const node_ref*
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*
347 Model::Node() const
348 {
349 	return fNode;
350 }
351 
352 
353 inline const StatStruct*
354 Model::StatBuf() const
355 {
356 	return &fStatBuf;
357 }
358 
359 
360 inline IconSource
361 Model::IconFrom() const
362 {
363 	return (IconSource)fIconFrom;
364 }
365 
366 
367 inline void
368 Model::SetIconFrom(IconSource from)
369 {
370 	fIconFrom = from;
371 }
372 
373 
374 inline Model*
375 Model::LinkTo() const
376 {
377 	ASSERT(IsSymLink());
378 	return fLinkTo;
379 }
380 
381 
382 inline bool
383 Model::IsFile() const
384 {
385 	return fBaseType == kPlainNode
386 		|| fBaseType == kQueryNode
387 		|| fBaseType == kQueryTemplateNode
388 		|| fBaseType == kExecutableNode
389 		|| fBaseType == kVirtualDirectoryNode;
390 }
391 
392 
393 inline bool
394 Model::IsVolume() const
395 {
396 	return fBaseType == kVolumeNode;
397 }
398 
399 
400 inline bool
401 Model::IsDirectory() const
402 {
403 	return fBaseType == kDirectoryNode
404 		|| fBaseType == kVolumeNode
405 		|| fBaseType == kRootNode
406 		|| fBaseType == kTrashNode
407 		|| fBaseType == kDesktopNode;
408 }
409 
410 
411 inline bool
412 Model::IsQuery() const
413 {
414 	return fBaseType == kQueryNode;
415 }
416 
417 
418 inline bool
419 Model::IsQueryTemplate() const
420 {
421 	return fBaseType == kQueryTemplateNode;
422 }
423 
424 
425 inline bool
426 Model::IsContainer() const
427 {
428 	// I guess as in should show container window -
429 	// volumes show the volume window
430 	return IsQuery() || IsDirectory() || IsVirtualDirectory();
431 }
432 
433 
434 inline bool
435 Model::IsRoot() const
436 {
437 	return fBaseType == kRootNode;
438 }
439 
440 
441 inline bool
442 Model::IsTrash() const
443 {
444 	return fBaseType == kTrashNode;
445 }
446 
447 
448 inline bool
449 Model::IsDesktop() const
450 {
451 	return fBaseType == kDesktopNode;
452 }
453 
454 
455 inline bool
456 Model::IsExecutable() const
457 {
458 	return fBaseType == kExecutableNode;
459 }
460 
461 
462 inline bool
463 Model::IsSymLink() const
464 {
465 	return fBaseType == kLinkNode;
466 }
467 
468 
469 inline bool
470 Model::IsVirtualDirectory() const
471 {
472 	return fBaseType == kVirtualDirectoryNode;
473 }
474 
475 
476 inline bool
477 Model::HasLocalizedName() const
478 {
479 	return fHasLocalizedName;
480 }
481 
482 
483 inline
484 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable,
485 	bool openLater)
486 	:
487 	fModel(model),
488 	fWasOpen(model->IsNodeOpen()),
489 	fWasOpenForWriting(model->IsNodeOpenForWriting())
490 {
491 	if (!openLater)
492 		OpenNode(writable);
493 }
494 
495 
496 inline
497 ModelNodeLazyOpener::~ModelNodeLazyOpener()
498 {
499 	if (!fModel->IsNodeOpen())
500 		return;
501 	if (!fWasOpen)
502 		fModel->CloseNode();
503 	else if (!fWasOpenForWriting)
504 		fModel->OpenNode();
505 }
506 
507 
508 inline bool
509 ModelNodeLazyOpener::IsOpen() const
510 {
511 	return fModel->IsNodeOpen();
512 }
513 
514 
515 inline bool
516 ModelNodeLazyOpener::IsOpenForWriting() const
517 {
518 	return fModel->IsNodeOpenForWriting();
519 }
520 
521 
522 inline bool
523 ModelNodeLazyOpener::IsOpen(bool forWriting) const
524 {
525 	return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen();
526 }
527 
528 
529 inline Model*
530 ModelNodeLazyOpener::TargetModel() const
531 {
532 	return fModel;
533 }
534 
535 
536 inline status_t
537 ModelNodeLazyOpener::OpenNode(bool writable)
538 {
539 	if (writable) {
540 		if (!fModel->IsNodeOpenForWriting())
541 			return fModel->OpenNode(true);
542 	} else if (!fModel->IsNodeOpen())
543 		return fModel->OpenNode();
544 
545 	return B_OK;
546 }
547 
548 } // namespace BPrivate
549 
550 
551 #endif	// _NU_MODEL_H
552