1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All 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
51class BPath;
52class BHandler;
53class BEntry;
54class 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
59typedef 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.
63typedef struct stat StatStruct;
64#endif
65
66namespace BPrivate {
67
68enum {
69	kDoesNotSupportType,
70	kSuperhandlerModel,
71	kModelSupportsSupertype,
72	kModelSupportsType,
73	kModelSupportsFile
74};
75
76class 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
269class 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
292class BModelOpener : public ModelNodeLazyOpener {
293	public:
294		BModelOpener(Model* model)
295		:	ModelNodeLazyOpener(model, false, false)
296		{
297		}
298};
299
300class 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
314void DumpOpenModels(bool extensive);
315void InitOpenModelDumping();
316#endif
317
318// inlines follow -----------------------------------
319
320inline const char*
321Model::MimeType() const
322{
323	return fMimeType.String();
324}
325
326
327inline const entry_ref*
328Model::EntryRef() const
329{
330	return &fEntryRef;
331}
332
333
334inline const node_ref*
335Model::NodeRef() const
336{
337	// the stat structure begins with a node_ref
338	return (node_ref*)&fStatBuf;
339}
340
341
342inline BNode*
343Model::Node() const
344{
345	return fNode;
346}
347
348
349inline const StatStruct*
350Model::StatBuf() const
351{
352	return &fStatBuf;
353}
354
355
356inline IconSource
357Model::IconFrom() const
358{
359	return (IconSource)fIconFrom;
360}
361
362
363inline void
364Model::SetIconFrom(IconSource from)
365{
366	fIconFrom = from;
367}
368
369
370inline Model*
371Model::LinkTo() const
372{
373	ASSERT(IsSymLink());
374	return fLinkTo;
375}
376
377
378inline bool
379Model::IsFile() const
380{
381	return fBaseType == kPlainNode
382		|| fBaseType == kQueryNode
383		|| fBaseType == kQueryTemplateNode
384		|| fBaseType == kExecutableNode;
385}
386
387
388inline bool
389Model::IsVolume() const
390{
391	return fBaseType == kVolumeNode;
392}
393
394
395inline bool
396Model::IsDirectory() const
397{
398	return fBaseType == kDirectoryNode
399		|| fBaseType == kVolumeNode
400		|| fBaseType == kRootNode
401		|| fBaseType == kTrashNode
402		|| fBaseType == kDesktopNode;
403}
404
405
406inline bool
407Model::IsQuery() const
408{
409	return fBaseType == kQueryNode;
410}
411
412
413inline bool
414Model::IsQueryTemplate() const
415{
416	return fBaseType == kQueryTemplateNode;
417}
418
419
420inline bool
421Model::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
429inline bool
430Model::IsRoot() const
431{
432	return fBaseType == kRootNode;
433}
434
435
436inline bool
437Model::IsTrash() const
438{
439	return fBaseType == kTrashNode;
440}
441
442
443inline bool
444Model::IsDesktop() const
445{
446	return fBaseType == kDesktopNode;
447}
448
449
450inline bool
451Model::IsExecutable() const
452{
453	return fBaseType == kExecutableNode;
454}
455
456
457inline bool
458Model::IsSymLink() const
459{
460	return fBaseType == kLinkNode;
461}
462
463
464inline bool
465Model::HasLocalizedName() const
466{
467	return fHasLocalizedName;
468}
469
470
471inline
472ModelNodeLazyOpener::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
483inline
484ModelNodeLazyOpener::~ModelNodeLazyOpener()
485{
486	if (!fModel->IsNodeOpen())
487		return;
488	if (!fWasOpen)
489		fModel->CloseNode();
490	else if (!fWasOpenForWriting)
491		fModel->OpenNode();
492}
493
494
495inline bool
496ModelNodeLazyOpener::IsOpen() const
497{
498	return fModel->IsNodeOpen();
499}
500
501
502inline bool
503ModelNodeLazyOpener::IsOpenForWriting() const
504{
505	return fModel->IsNodeOpenForWriting();
506}
507
508
509inline bool
510ModelNodeLazyOpener::IsOpen(bool forWriting) const
511{
512	return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen();
513}
514
515
516inline Model*
517ModelNodeLazyOpener::TargetModel() const
518{
519	return fModel;
520}
521
522
523inline status_t
524ModelNodeLazyOpener::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