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