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	bool ShouldUseWellKnownIcon() const;
216	bool CheckAppIconHint() const;
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		kVirtualDirectoryNode,
243		kUnknownNode
244	};
245
246	entry_ref fEntryRef;
247	StatStruct fStatBuf;
248	BString fMimeType;
249		// should use string that may be shared for common types
250
251	// bit of overloading hackery here to save on footprint
252	union {
253		char* fPreferredAppName;	// used if we are neither a volume
254									// nor a symlink
255		char* fVolumeName;			// used if we are a volume
256		Model* fLinkTo;				// used if we are a symlink
257	};
258
259	uint8 fBaseType;
260	uint8 fIconFrom;
261	bool fWritable;
262	BNode* fNode;
263	status_t fStatus;
264	BString fLocalizedName;
265	bool fHasLocalizedName;
266	bool fLocalizedNameIsCached;
267};
268
269
270class ModelNodeLazyOpener {
271	// a utility open state manager, usefull to allocate on stack
272	// and have close up model when done, etc.
273	public:
274		// consider failing when open does not succeed
275
276		ModelNodeLazyOpener(Model* model, bool writable = false,
277			bool openLater = true);
278		~ModelNodeLazyOpener();
279
280		bool IsOpen() const;
281		bool IsOpenForWriting() const;
282		bool IsOpen(bool forWriting) const;
283		Model* TargetModel() const;
284		status_t OpenNode(bool writable = false);
285
286	private:
287		Model* fModel;
288		bool fWasOpen;
289		bool fWasOpenForWriting;
290};
291
292// handy flavors of openers
293class BModelOpener : public ModelNodeLazyOpener {
294	public:
295		BModelOpener(Model* model)
296		:	ModelNodeLazyOpener(model, false, false)
297		{
298		}
299};
300
301class BModelWriteOpener : public ModelNodeLazyOpener {
302	public:
303		BModelWriteOpener(Model* model)
304		:	ModelNodeLazyOpener(model, true, false)
305		{
306		}
307};
308
309
310#if DEBUG
311// #define CHECK_OPEN_MODEL_LEAKS
312#endif
313
314#ifdef CHECK_OPEN_MODEL_LEAKS
315void DumpOpenModels(bool extensive);
316void InitOpenModelDumping();
317#endif
318
319// inlines follow -----------------------------------
320
321inline const char*
322Model::MimeType() const
323{
324	return fMimeType.String();
325}
326
327
328inline const entry_ref*
329Model::EntryRef() const
330{
331	return &fEntryRef;
332}
333
334
335inline const node_ref*
336Model::NodeRef() const
337{
338	// the stat structure begins with a node_ref
339	return (node_ref*)&fStatBuf;
340}
341
342
343inline BNode*
344Model::Node() const
345{
346	return fNode;
347}
348
349
350inline const StatStruct*
351Model::StatBuf() const
352{
353	return &fStatBuf;
354}
355
356
357inline IconSource
358Model::IconFrom() const
359{
360	return (IconSource)fIconFrom;
361}
362
363
364inline void
365Model::SetIconFrom(IconSource from)
366{
367	fIconFrom = from;
368}
369
370
371inline Model*
372Model::LinkTo() const
373{
374	ASSERT(IsSymLink());
375	return fLinkTo;
376}
377
378
379inline bool
380Model::IsFile() const
381{
382	return fBaseType == kPlainNode
383		|| fBaseType == kQueryNode
384		|| fBaseType == kQueryTemplateNode
385		|| fBaseType == kExecutableNode
386		|| fBaseType == kVirtualDirectoryNode;
387}
388
389
390inline bool
391Model::IsVolume() const
392{
393	return fBaseType == kVolumeNode;
394}
395
396
397inline bool
398Model::IsDirectory() const
399{
400	return fBaseType == kDirectoryNode
401		|| fBaseType == kVolumeNode
402		|| fBaseType == kRootNode
403		|| fBaseType == kTrashNode
404		|| fBaseType == kDesktopNode;
405}
406
407
408inline bool
409Model::IsQuery() const
410{
411	return fBaseType == kQueryNode;
412}
413
414
415inline bool
416Model::IsQueryTemplate() const
417{
418	return fBaseType == kQueryTemplateNode;
419}
420
421
422inline bool
423Model::IsContainer() const
424{
425	// I guess as in should show container window -
426	// volumes show the volume window
427	return IsQuery() || IsDirectory() || IsVirtualDirectory();
428}
429
430
431inline bool
432Model::IsRoot() const
433{
434	return fBaseType == kRootNode;
435}
436
437
438inline bool
439Model::IsTrash() const
440{
441	return fBaseType == kTrashNode;
442}
443
444
445inline bool
446Model::IsDesktop() const
447{
448	return fBaseType == kDesktopNode;
449}
450
451
452inline bool
453Model::IsExecutable() const
454{
455	return fBaseType == kExecutableNode;
456}
457
458
459inline bool
460Model::IsSymLink() const
461{
462	return fBaseType == kLinkNode;
463}
464
465
466inline bool
467Model::IsVirtualDirectory() const
468{
469	return fBaseType == kVirtualDirectoryNode;
470}
471
472
473inline bool
474Model::HasLocalizedName() const
475{
476	return fHasLocalizedName;
477}
478
479
480inline
481ModelNodeLazyOpener::ModelNodeLazyOpener(Model* model, bool writable,
482	bool openLater)
483	:
484	fModel(model),
485	fWasOpen(model->IsNodeOpen()),
486	fWasOpenForWriting(model->IsNodeOpenForWriting())
487{
488	if (!openLater)
489		OpenNode(writable);
490}
491
492
493inline
494ModelNodeLazyOpener::~ModelNodeLazyOpener()
495{
496	if (!fModel->IsNodeOpen())
497		return;
498	if (!fWasOpen)
499		fModel->CloseNode();
500	else if (!fWasOpenForWriting)
501		fModel->OpenNode();
502}
503
504
505inline bool
506ModelNodeLazyOpener::IsOpen() const
507{
508	return fModel->IsNodeOpen();
509}
510
511
512inline bool
513ModelNodeLazyOpener::IsOpenForWriting() const
514{
515	return fModel->IsNodeOpenForWriting();
516}
517
518
519inline bool
520ModelNodeLazyOpener::IsOpen(bool forWriting) const
521{
522	return forWriting ? fModel->IsNodeOpenForWriting() : fModel->IsNodeOpen();
523}
524
525
526inline Model*
527ModelNodeLazyOpener::TargetModel() const
528{
529	return fModel;
530}
531
532
533inline status_t
534ModelNodeLazyOpener::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
548#endif	// _NU_MODEL_H
549