xref: /haiku/src/kits/tracker/Model.h (revision 9522c1e4f21b0292084467c927e4169770db1329)
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 class Model {
78 public:
79 	Model();
80 	Model(const Model &);
81 	Model(const BEntry* entry, bool open = false, bool writable = false);
82 	Model(const entry_ref*, bool traverse = false, bool open = false,
83 		bool writable = false);
84 	Model(const node_ref* dirNode, const node_ref* node, const char* name,
85 		bool open = false, bool writable = false);
86 	~Model();
87 
88 	Model& operator=(const Model&);
89 
90 	status_t InitCheck() const;
91 
92 	status_t SetTo(const BEntry*, bool open = false,
93 		bool writable = false);
94 	status_t SetTo(const entry_ref*, bool traverse = false,
95 		bool open = false, bool writable = false);
96 	status_t SetTo(const node_ref* dirNode, const node_ref* node,
97 		const char* name, bool open = false, bool writable = false);
98 
99 	int CompareFolderNamesFirst(const Model* compareModel) const;
100 
101 	// node management
102 	status_t OpenNode(bool writable = false);
103 		// also used to switch from read-only to writable
104 	void CloseNode();
105 	bool IsNodeOpen() const;
106 	bool IsNodeOpenForWriting() const;
107 
108 	status_t UpdateStatAndOpenNode(bool writable = false);
109 		// like OpenNode, called on zombie poses to check if they turned
110 		// real, starts by rereading the stat structure
111 
112 	// basic getters
113 	const char* Name() const;
114 	const entry_ref* EntryRef() const;
115 	const node_ref* NodeRef() const;
116 	const StatStruct* StatBuf() const;
117 
118 	BNode* Node() const;
119 		// returns NULL if not open
120 	void GetPath(BPath*) const;
121 	void GetEntry(BEntry*) const;
122 
123 	const char* MimeType() const;
124 	const char* PreferredAppSignature() const;
125 		// only not-null if not default for type and not self for app
126 	void SetPreferredAppSignature(const char*);
127 
128 	void GetPreferredAppForBrokenSymLink(BString &result);
129 		// special purpose call - if a symlink is unresolvable, it makes
130 		// sense to be able to get at it's preferred handler which may be
131 		// different from the Tracker. Used by the network neighborhood.
132 
133 	// type getters
134 	bool IsFile() const;
135 	bool IsDirectory() const;
136 	bool IsQuery() const;
137 	bool IsQueryTemplate() const;
138 	bool IsContainer() const;
139 	bool IsExecutable() const;
140 	bool IsSymLink() const;
141 	bool IsRoot() const;
142 	bool IsTrash() const;
143 	bool IsDesktop() const;
144 	bool IsVolume() const;
145 	bool IsVirtualDirectory() const;
146 
147 	IconSource IconFrom() const;
148 	void SetIconFrom(IconSource);
149 		// where is this model getting it's icon from
150 
151 	void ResetIconFrom();
152 		// called from the attribute changed calls to force a lookup of
153 		// a new icon
154 
155 	// symlink handling calls, mainly used by the IconCache
156 	const Model* ResolveIfLink() const;
157 	Model* ResolveIfLink();
158 		// works on anything
159 	Model* LinkTo() const;
160 		// fast, works only on symlinks
161 	void SetLinkTo(Model*);
162 
163 	status_t GetLongVersionString(BString &, version_kind);
164 	status_t GetVersionString(BString &, version_kind);
165 	status_t AttrAsString(BString &, int64* value,
166 		const char* attributeName, uint32 attributeType);
167 
168 	// Node monitor update call
169 	void UpdateEntryRef(const node_ref* dirRef, const char* name);
170 	bool AttrChanged(const char*);
171 		// returns true if pose needs to update it's icon, etc.
172 		// pass null to force full update
173 	bool StatChanged();
174 		// returns true if pose needs to update it's icon
175 
176 	status_t WatchVolumeAndMountPoint(uint32, BHandler*);
177 		// correctly handles boot volume name watching
178 
179 	bool IsDropTarget(const Model* forDocument = 0,
180 		bool traverse = false) const;
181 		// if nonzero <forDocument> passed, mime info is used to
182 		// resolve if document can be opened
183 		// if zero, all executables, directories and volumes pass
184 		// if traverse, dereference symlinks
185 	bool IsDropTargetForList(const BObjectList<BString>* list) const;
186 		// <list> contains mime types of all documents about to be handled
187 		// by model
188 
189 #if DEBUG
190 	void PrintToStream(int32 level = 1, bool deep = false);
191 	void TrackIconSource(icon_size);
192 #endif
193 
194 	bool IsSuperHandler() const;
195 	int32 SupportsMimeType(const char* type,
196 		const BObjectList<BString>* list, bool exactReason = false) const;
197 		// pass in one string in <type> or a bunch in <list>
198 		// if <exactReason> false, returns as soon as it figures out that
199 		// app supports a given type, if true, returns an exact reason
200 
201 	// get rid of this??
202 	ssize_t WriteAttr(const char* attr, type_code type, off_t,
203 		const void* buffer, size_t );
204 		// cover call, creates a writable node and writes out attributes
205 		// into it; work around for file nodes not being writeable
206 	ssize_t WriteAttrKillForeign(const char* attr,
207 		const char* foreignAttr, type_code type, off_t,
208 		const void* buffer, size_t);
209 
210 	bool Mimeset(bool force);
211 		// returns true if mime type changed
212 
213 	bool HasLocalizedName() const;
214 
215 private:
216 	status_t OpenNodeCommon(bool writable);
217 	void SetupBaseType();
218 	void FinishSettingUpType();
219 	void DeletePreferredAppVolumeNameLinkTo();
220 	void CacheLocalizedName();
221 
222 	status_t FetchOneQuery(const BQuery*, BHandler* target,
223 		BObjectList<BQuery>*, BVolume*);
224 
225 	enum CanHandleResult {
226 		kCanHandle,
227 		kCannotHandle,
228 		kNeedToCheckType
229 	};
230 
231 	CanHandleResult CanHandleDrops() const;
232 
233 	enum NodeType {
234 		kPlainNode,
235 		kExecutableNode,
236 		kDirectoryNode,
237 		kLinkNode,
238 		kQueryNode,
239 		kQueryTemplateNode,
240 		kVolumeNode,
241 		kRootNode,
242 		kTrashNode,
243 		kDesktopNode,
244 		kVirtualDirectoryNode,
245 		kUnknownNode
246 	};
247 
248 	entry_ref fEntryRef;
249 	StatStruct fStatBuf;
250 	BString fMimeType;
251 		// should use string that may be shared for common types
252 
253 	// bit of overloading hackery here to save on footprint
254 	union {
255 		char* fPreferredAppName;	// used if we are neither a volume
256 									// nor a symlink
257 		char* fVolumeName;			// used if we are a volume
258 		Model* fLinkTo;				// used if we are a symlink
259 	};
260 
261 	uint8 fBaseType;
262 	uint8 fIconFrom;
263 	bool fWritable;
264 	BNode* fNode;
265 	status_t fStatus;
266 	BString fLocalizedName;
267 	bool fHasLocalizedName;
268 	bool fLocalizedNameIsCached;
269 };
270 
271 
272 class ModelNodeLazyOpener {
273 	// a utility open state manager, usefull to allocate on stack
274 	// and have close up model when done, etc.
275 	public:
276 		// consider failing when open does not succeed
277 
278 		ModelNodeLazyOpener(Model* model, bool writable = false,
279 			bool openLater = true);
280 		~ModelNodeLazyOpener();
281 
282 		bool IsOpen() const;
283 		bool IsOpenForWriting() const;
284 		bool IsOpen(bool forWriting) const;
285 		Model* TargetModel() const;
286 		status_t OpenNode(bool writable = false);
287 
288 	private:
289 		Model* fModel;
290 		bool fWasOpen;
291 		bool fWasOpenForWriting;
292 };
293 
294 // handy flavors of openers
295 class BModelOpener : public ModelNodeLazyOpener {
296 	public:
297 		BModelOpener(Model* model)
298 		:	ModelNodeLazyOpener(model, false, false)
299 		{
300 		}
301 };
302 
303 class BModelWriteOpener : public ModelNodeLazyOpener {
304 	public:
305 		BModelWriteOpener(Model* model)
306 		:	ModelNodeLazyOpener(model, true, false)
307 		{
308 		}
309 };
310 
311 
312 #if DEBUG
313 // #define CHECK_OPEN_MODEL_LEAKS
314 #endif
315 
316 #ifdef CHECK_OPEN_MODEL_LEAKS
317 void DumpOpenModels(bool extensive);
318 void InitOpenModelDumping();
319 #endif
320 
321 // inlines follow -----------------------------------
322 
323 inline const char*
324 Model::MimeType() const
325 {
326 	return fMimeType.String();
327 }
328 
329 
330 inline const entry_ref*
331 Model::EntryRef() const
332 {
333 	return &fEntryRef;
334 }
335 
336 
337 inline const node_ref*
338 Model::NodeRef() const
339 {
340 	// the stat structure begins with a node_ref
341 	return (node_ref*)&fStatBuf;
342 }
343 
344 
345 inline BNode*
346 Model::Node() const
347 {
348 	return fNode;
349 }
350 
351 
352 inline const StatStruct*
353 Model::StatBuf() const
354 {
355 	return &fStatBuf;
356 }
357 
358 
359 inline IconSource
360 Model::IconFrom() const
361 {
362 	return (IconSource)fIconFrom;
363 }
364 
365 
366 inline void
367 Model::SetIconFrom(IconSource from)
368 {
369 	fIconFrom = from;
370 }
371 
372 
373 inline Model*
374 Model::LinkTo() const
375 {
376 	ASSERT(IsSymLink());
377 	return fLinkTo;
378 }
379 
380 
381 inline bool
382 Model::IsFile() const
383 {
384 	return fBaseType == kPlainNode
385 		|| fBaseType == kQueryNode
386 		|| fBaseType == kQueryTemplateNode
387 		|| fBaseType == kExecutableNode
388 		|| fBaseType == kVirtualDirectoryNode;
389 }
390 
391 
392 inline bool
393 Model::IsVolume() const
394 {
395 	return fBaseType == kVolumeNode;
396 }
397 
398 
399 inline bool
400 Model::IsDirectory() const
401 {
402 	return fBaseType == kDirectoryNode
403 		|| fBaseType == kVolumeNode
404 		|| fBaseType == kRootNode
405 		|| fBaseType == kTrashNode
406 		|| fBaseType == kDesktopNode;
407 }
408 
409 
410 inline bool
411 Model::IsQuery() const
412 {
413 	return fBaseType == kQueryNode;
414 }
415 
416 
417 inline bool
418 Model::IsQueryTemplate() const
419 {
420 	return fBaseType == kQueryTemplateNode;
421 }
422 
423 
424 inline bool
425 Model::IsContainer() const
426 {
427 	// I guess as in should show container window -
428 	// volumes show the volume window
429 	return IsQuery() || IsDirectory() || IsVirtualDirectory();
430 }
431 
432 
433 inline bool
434 Model::IsRoot() const
435 {
436 	return fBaseType == kRootNode;
437 }
438 
439 
440 inline bool
441 Model::IsTrash() const
442 {
443 	return fBaseType == kTrashNode;
444 }
445 
446 
447 inline bool
448 Model::IsDesktop() const
449 {
450 	return fBaseType == kDesktopNode;
451 }
452 
453 
454 inline bool
455 Model::IsExecutable() const
456 {
457 	return fBaseType == kExecutableNode;
458 }
459 
460 
461 inline bool
462 Model::IsSymLink() const
463 {
464 	return fBaseType == kLinkNode;
465 }
466 
467 
468 inline bool
469 Model::IsVirtualDirectory() const
470 {
471 	return fBaseType == kVirtualDirectoryNode;
472 }
473 
474 
475 inline bool
476 Model::HasLocalizedName() const
477 {
478 	return fHasLocalizedName;
479 }
480 
481 
482 inline
483 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable,
484 	bool openLater)
485 	:	fModel(model),
486 		fWasOpen(model->IsNodeOpen()),
487 		fWasOpenForWriting(model->IsNodeOpenForWriting())
488 {
489 	if (!openLater)
490 		OpenNode(writable);
491 }
492 
493 
494 inline
495 ModelNodeLazyOpener::~ModelNodeLazyOpener()
496 {
497 	if (!fModel->IsNodeOpen())
498 		return;
499 	if (!fWasOpen)
500 		fModel->CloseNode();
501 	else if (!fWasOpenForWriting)
502 		fModel->OpenNode();
503 }
504 
505 
506 inline bool
507 ModelNodeLazyOpener::IsOpen() const
508 {
509 	return fModel->IsNodeOpen();
510 }
511 
512 
513 inline bool
514 ModelNodeLazyOpener::IsOpenForWriting() const
515 {
516 	return fModel->IsNodeOpenForWriting();
517 }
518 
519 
520 inline bool
521 ModelNodeLazyOpener::IsOpen(bool forWriting) const
522 {
523 	return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen();
524 }
525 
526 
527 inline Model*
528 ModelNodeLazyOpener::TargetModel() const
529 {
530 	return fModel;
531 }
532 
533 
534 inline status_t
535 ModelNodeLazyOpener::OpenNode(bool writable)
536 {
537 	if (writable) {
538 		if (!fModel->IsNodeOpenForWriting())
539 			return fModel->OpenNode(true);
540 	} else if (!fModel->IsNodeOpen())
541 		return fModel->OpenNode();
542 
543 	return B_OK;
544 }
545 
546 } // namespace BPrivate
547 
548 
549 #endif	// _NU_MODEL_H
550