xref: /haiku/src/kits/tracker/Model.h (revision 90ae2e54f6ccaca73c011a2aa4cdd660417108ad)
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 
145 		IconSource IconFrom() const;
146 		void SetIconFrom(IconSource);
147 			// where is this model getting it's icon from
148 
149 		void ResetIconFrom();
150 			// called from the attribute changed calls to force a lookup of
151 			// a new icon
152 
153 		// symlink handling calls, mainly used by the IconCache
154 		const Model* ResolveIfLink() const;
155 		Model* ResolveIfLink();
156 			// works on anything
157 		Model* LinkTo() const;
158 			// fast, works only on symlinks
159 		void SetLinkTo(Model*);
160 
161 		status_t GetLongVersionString(BString &, version_kind);
162 		status_t GetVersionString(BString &, version_kind);
163 		status_t AttrAsString(BString &, int64* value,
164 			const char* attributeName, uint32 attributeType);
165 
166 		// Node monitor update call
167 		void UpdateEntryRef(const node_ref* dirRef, const char* name);
168 		bool AttrChanged(const char*);
169 			// returns true if pose needs to update it's icon, etc.
170 			// pass null to force full update
171 		bool StatChanged();
172 			// returns true if pose needs to update it's icon
173 
174 		status_t WatchVolumeAndMountPoint(uint32, BHandler*);
175 			// correctly handles boot volume name watching
176 
177 		bool IsDropTarget(const Model* forDocument = 0,
178 			bool traverse = false) const;
179 			// if nonzero <forDocument> passed, mime info is used to
180 			// resolve if document can be opened
181 			// if zero, all executables, directories and volumes pass
182 			// if traverse, dereference symlinks
183 		bool IsDropTargetForList(const BObjectList<BString>* list) const;
184 			// <list> contains mime types of all documents about to be handled
185 			// by model
186 
187 	#if DEBUG
188 		void PrintToStream(int32 level = 1, bool deep = false);
189 		void TrackIconSource(icon_size);
190 	#endif
191 
192 		bool IsSuperHandler() const;
193 		int32 SupportsMimeType(const char* type,
194 			const BObjectList<BString>* list, bool exactReason = false) const;
195 			// pass in one string in <type> or a bunch in <list>
196 			// if <exactReason> false, returns as soon as it figures out that
197 			// app supports a given type, if true, returns an exact reason
198 
199 		// get rid of this??
200 		ssize_t WriteAttr(const char* attr, type_code type, off_t,
201 			const void* buffer, size_t );
202 			// cover call, creates a writable node and writes out attributes
203 			// into it; work around for file nodes not being writeable
204 		ssize_t WriteAttrKillForeign(const char* attr,
205 			const char* foreignAttr, type_code type, off_t,
206 			const void* buffer, size_t);
207 
208 		bool Mimeset(bool force);
209 			// returns true if mime type changed
210 
211 		bool HasLocalizedName() const;
212 
213 	private:
214 		status_t OpenNodeCommon(bool writable);
215 		void SetupBaseType();
216 		void FinishSettingUpType();
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 			kUnknownNode
243 		};
244 
245 		entry_ref fEntryRef;
246 		StatStruct fStatBuf;
247 		BString fMimeType;
248 			// should use string that may be shared for common types
249 
250 		// bit of overloading hackery here to save on footprint
251 		union {
252 			char* fPreferredAppName;	// used if we are neither a volume
253 										// nor a symlink
254 			char* fVolumeName;			// used if we are a volume
255 			Model* fLinkTo;				// used if we are a symlink
256 		};
257 
258 		uint8 fBaseType;
259 		uint8 fIconFrom;
260 		bool fWritable;
261 		BNode* fNode;
262 		status_t fStatus;
263 		BString fLocalizedName;
264 		bool fHasLocalizedName;
265 		bool fLocalizedNameIsCached;
266 };
267 
268 
269 class ModelNodeLazyOpener {
270 	// a utility open state manager, usefull to allocate on stack
271 	// and have close up model when done, etc.
272 	public:
273 		// consider failing when open does not succeed
274 
275 		ModelNodeLazyOpener(Model* model, bool writable = false,
276 			bool openLater = true);
277 		~ModelNodeLazyOpener();
278 
279 		bool IsOpen() const;
280 		bool IsOpenForWriting() const;
281 		bool IsOpen(bool forWriting) const;
282 		Model* TargetModel() const;
283 		status_t OpenNode(bool writable = false);
284 
285 	private:
286 		Model* fModel;
287 		bool fWasOpen;
288 		bool fWasOpenForWriting;
289 };
290 
291 // handy flavors of openers
292 class BModelOpener : public ModelNodeLazyOpener {
293 	public:
294 		BModelOpener(Model* model)
295 		:	ModelNodeLazyOpener(model, false, false)
296 		{
297 		}
298 };
299 
300 class BModelWriteOpener : public ModelNodeLazyOpener {
301 	public:
302 		BModelWriteOpener(Model* model)
303 		:	ModelNodeLazyOpener(model, true, false)
304 		{
305 		}
306 };
307 
308 
309 #if DEBUG
310 // #define CHECK_OPEN_MODEL_LEAKS
311 #endif
312 
313 #ifdef CHECK_OPEN_MODEL_LEAKS
314 void DumpOpenModels(bool extensive);
315 void InitOpenModelDumping();
316 #endif
317 
318 // inlines follow -----------------------------------
319 
320 inline const char*
321 Model::MimeType() const
322 {
323 	return fMimeType.String();
324 }
325 
326 
327 inline const entry_ref*
328 Model::EntryRef() const
329 {
330 	return &fEntryRef;
331 }
332 
333 
334 inline const node_ref*
335 Model::NodeRef() const
336 {
337 	// the stat structure begins with a node_ref
338 	return (node_ref*)&fStatBuf;
339 }
340 
341 
342 inline BNode*
343 Model::Node() const
344 {
345 	return fNode;
346 }
347 
348 
349 inline const StatStruct*
350 Model::StatBuf() const
351 {
352 	return &fStatBuf;
353 }
354 
355 
356 inline IconSource
357 Model::IconFrom() const
358 {
359 	return (IconSource)fIconFrom;
360 }
361 
362 
363 inline void
364 Model::SetIconFrom(IconSource from)
365 {
366 	fIconFrom = from;
367 }
368 
369 
370 inline Model*
371 Model::LinkTo() const
372 {
373 	ASSERT(IsSymLink());
374 	return fLinkTo;
375 }
376 
377 
378 inline bool
379 Model::IsFile() const
380 {
381 	return fBaseType == kPlainNode
382 		|| fBaseType == kQueryNode
383 		|| fBaseType == kQueryTemplateNode
384 		|| fBaseType == kExecutableNode;
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();
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::HasLocalizedName() const
466 {
467 	return fHasLocalizedName;
468 }
469 
470 
471 inline
472 ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable,
473 	bool openLater)
474 	:	fModel(model),
475 		fWasOpen(model->IsNodeOpen()),
476 		fWasOpenForWriting(model->IsNodeOpenForWriting())
477 {
478 	if (!openLater)
479 		OpenNode(writable);
480 }
481 
482 
483 inline
484 ModelNodeLazyOpener::~ModelNodeLazyOpener()
485 {
486 	if (!fModel->IsNodeOpen())
487 		return;
488 	if (!fWasOpen)
489 		fModel->CloseNode();
490 	else if (!fWasOpenForWriting)
491 		fModel->OpenNode();
492 }
493 
494 
495 inline bool
496 ModelNodeLazyOpener::IsOpen() const
497 {
498 	return fModel->IsNodeOpen();
499 }
500 
501 
502 inline bool
503 ModelNodeLazyOpener::IsOpenForWriting() const
504 {
505 	return fModel->IsNodeOpenForWriting();
506 }
507 
508 
509 inline bool
510 ModelNodeLazyOpener::IsOpen(bool forWriting) const
511 {
512 	return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen();
513 }
514 
515 
516 inline Model*
517 ModelNodeLazyOpener::TargetModel() const
518 {
519 	return fModel;
520 }
521 
522 
523 inline status_t
524 ModelNodeLazyOpener::OpenNode(bool writable)
525 {
526 	if (writable) {
527 		if (!fModel->IsNodeOpenForWriting())
528 			return fModel->OpenNode(true);
529 	} else if (!fModel->IsNodeOpen())
530 		return fModel->OpenNode();
531 
532 	return B_OK;
533 }
534 
535 } // namespace BPrivate
536 
537 #endif	// _NU_MODEL_H
538