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