102be5353SAxel Dörfler/*
202be5353SAxel DörflerOpen Tracker License
302be5353SAxel Dörfler
402be5353SAxel DörflerTerms and Conditions
502be5353SAxel Dörfler
602be5353SAxel DörflerCopyright (c) 1991-2000, Be Incorporated. All rights reserved.
702be5353SAxel Dörfler
802be5353SAxel DörflerPermission is hereby granted, free of charge, to any person obtaining a copy of
902be5353SAxel Dörflerthis software and associated documentation files (the "Software"), to deal in
1002be5353SAxel Dörflerthe Software without restriction, including without limitation the rights to
1102be5353SAxel Dörfleruse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
1202be5353SAxel Dörflerof the Software, and to permit persons to whom the Software is furnished to do
1302be5353SAxel Dörflerso, subject to the following conditions:
1402be5353SAxel Dörfler
1502be5353SAxel DörflerThe above copyright notice and this permission notice applies to all licensees
1602be5353SAxel Dörflerand shall be included in all copies or substantial portions of the Software.
1702be5353SAxel Dörfler
1802be5353SAxel DörflerTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1902be5353SAxel DörflerIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
2002be5353SAxel DörflerFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2102be5353SAxel DörflerBE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2202be5353SAxel DörflerAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
2302be5353SAxel DörflerWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2402be5353SAxel Dörfler
2502be5353SAxel DörflerExcept as contained in this notice, the name of Be Incorporated shall not be
2602be5353SAxel Dörflerused in advertising or otherwise to promote the sale, use or other dealings in
2702be5353SAxel Dörflerthis Software without prior written authorization from Be Incorporated.
2802be5353SAxel Dörfler
2902be5353SAxel DörflerTracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
3002be5353SAxel Dörflerof Be Incorporated in the United States and other countries. Other brand product
3102be5353SAxel Dörflernames are registered trademarks or trademarks of their respective holders.
3202be5353SAxel DörflerAll rights reserved.
3302be5353SAxel Dörfler*/
3402be5353SAxel Dörfler
354f459891SAxel Dörfler
364f459891SAxel Dörfler#include "InfoWindow.h"
37994b2356SStephan Aßmus
38994b2356SStephan Aßmus#include <string.h>
39994b2356SStephan Aßmus#include <stdio.h>
40994b2356SStephan Aßmus#include <stdlib.h>
414f459891SAxel Dörfler
4202be5353SAxel Dörfler#include <Alert.h>
434ed28a57SAlexandre Deckner#include <Catalog.h>
4402be5353SAxel Dörfler#include <Debug.h>
4502be5353SAxel Dörfler#include <Directory.h>
4602be5353SAxel Dörfler#include <File.h>
4702be5353SAxel Dörfler#include <Font.h>
484ed28a57SAlexandre Deckner#include <Locale.h>
4902be5353SAxel Dörfler#include <MenuField.h>
5002be5353SAxel Dörfler#include <Mime.h>
5102be5353SAxel Dörfler#include <NodeInfo.h>
52a5dc8f86SPhilippe Saint-Pierre#include <NodeMonitor.h>
5302be5353SAxel Dörfler#include <Path.h>
5402be5353SAxel Dörfler#include <PopUpMenu.h>
5502be5353SAxel Dörfler#include <Region.h>
5602be5353SAxel Dörfler#include <Roster.h>
5702be5353SAxel Dörfler#include <Screen.h>
5802be5353SAxel Dörfler#include <ScrollView.h>
597457ccb4SAugustin Cavalier#include <StringFormat.h>
6002be5353SAxel Dörfler#include <SymLink.h>
6102be5353SAxel Dörfler#include <TextView.h>
6202be5353SAxel Dörfler#include <Volume.h>
6302be5353SAxel Dörfler#include <VolumeRoster.h>
6402be5353SAxel Dörfler
65994b2356SStephan Aßmus#include "Attributes.h"
66994b2356SStephan Aßmus#include "AutoLock.h"
67994b2356SStephan Aßmus#include "Commands.h"
68994b2356SStephan Aßmus#include "DialogPane.h"
69994b2356SStephan Aßmus#include "FSUtils.h"
70994b2356SStephan Aßmus#include "IconCache.h"
71994b2356SStephan Aßmus#include "IconMenuItem.h"
72994b2356SStephan Aßmus#include "Model.h"
73994b2356SStephan Aßmus#include "NavMenu.h"
74994b2356SStephan Aßmus#include "PoseView.h"
754ed28a57SAlexandre Deckner#include "StringForSize.h"
76994b2356SStephan Aßmus#include "Tracker.h"
77994b2356SStephan Aßmus#include "WidgetAttributeText.h"
7802be5353SAxel Dörfler
7902be5353SAxel Dörfler
80546208a5SOliver Tappe#undef B_TRANSLATION_CONTEXT
81546208a5SOliver Tappe#define B_TRANSLATION_CONTEXT "InfoWindow"
824ed28a57SAlexandre Deckner
834ed28a57SAlexandre Deckner
84aded7d13SAxel Dörflernamespace BPrivate {
85aded7d13SAxel Dörfler
86aded7d13SAxel Dörfler// States for tracking the mouse
87aded7d13SAxel Dörflerenum track_state {
88aded7d13SAxel Dörfler	no_track = 0,
89aded7d13SAxel Dörfler	link_track,
90aded7d13SAxel Dörfler	path_track,
91aded7d13SAxel Dörfler	icon_track,
92aded7d13SAxel Dörfler	size_track,
93ff43bcbfSJohn Scipione	open_only_track
94ff43bcbfSJohn Scipione		// This is for items that can be opened, but can't be
95ff43bcbfSJohn Scipione		// drag and dropped or renamed (Trash, Desktop Folder...)
96aded7d13SAxel Dörfler};
97aded7d13SAxel Dörfler
98ff43bcbfSJohn Scipione
99aded7d13SAxel Dörflerclass TrackingView : public BControl {
100ff43bcbfSJohn Scipionepublic:
101ff43bcbfSJohn Scipione	TrackingView(BRect, const char* str, BMessage* message);
102aded7d13SAxel Dörfler
103ff43bcbfSJohn Scipione	virtual void MouseDown(BPoint);
104ff43bcbfSJohn Scipione	virtual void MouseMoved(BPoint where, uint32 transit, const BMessage*);
105ff43bcbfSJohn Scipione	virtual void MouseUp(BPoint);
106ff43bcbfSJohn Scipione	virtual void Draw(BRect);
107aded7d13SAxel Dörfler
108ff43bcbfSJohn Scipioneprivate:
109ff43bcbfSJohn Scipione	bool fMouseDown;
110ff43bcbfSJohn Scipione	bool fMouseInView;
111aded7d13SAxel Dörfler};
112aded7d13SAxel Dörfler
113ff43bcbfSJohn Scipione
114c716766bSKarsten Heimrichclass AttributeView : public BView {
115ff43bcbfSJohn Scipionepublic:
116ff43bcbfSJohn Scipione	AttributeView(BRect, Model*);
117ff43bcbfSJohn Scipione	~AttributeView();
118ff43bcbfSJohn Scipione
119ff43bcbfSJohn Scipione	void ModelChanged(Model*, BMessage*);
120ff43bcbfSJohn Scipione	void ReLinkTargetModel(Model*);
121ff43bcbfSJohn Scipione	void BeginEditingTitle();
122ff43bcbfSJohn Scipione	void FinishEditingTitle(bool);
123c5b4dc40Slooncraz	float CurrentFontHeight();
124ff43bcbfSJohn Scipione
125ff43bcbfSJohn Scipione	BTextView* TextView() const { return fTitleEditView; }
126ff43bcbfSJohn Scipione
127ff43bcbfSJohn Scipione	static filter_result TextViewFilter(BMessage*, BHandler**,
128ff43bcbfSJohn Scipione		BMessageFilter*);
129ff43bcbfSJohn Scipione
130ff43bcbfSJohn Scipione	off_t LastSize() const;
131ff43bcbfSJohn Scipione	void SetLastSize(off_t);
132ff43bcbfSJohn Scipione
133ff43bcbfSJohn Scipione	void SetSizeString(const char*);
134ff43bcbfSJohn Scipione
135ff43bcbfSJohn Scipione	status_t BuildContextMenu(BMenu* parent);
136ff43bcbfSJohn Scipione
137ff43bcbfSJohn Scipione	void SetPermissionsSwitchState(int32 state);
138ff43bcbfSJohn Scipione
139ff43bcbfSJohn Scipioneprotected:
140ff43bcbfSJohn Scipione	virtual void MouseDown(BPoint where);
141ff43bcbfSJohn Scipione	virtual void MouseMoved(BPoint where, uint32, const BMessage* dragMessage);
142ff43bcbfSJohn Scipione	virtual void MouseUp(BPoint where);
143ff43bcbfSJohn Scipione	virtual void MessageReceived(BMessage* message);
144ff43bcbfSJohn Scipione	virtual void AttachedToWindow();
145ff43bcbfSJohn Scipione	virtual void Draw(BRect);
146ff43bcbfSJohn Scipione	virtual void Pulse();
147ff43bcbfSJohn Scipione	virtual void MakeFocus(bool focus);
148ff43bcbfSJohn Scipione	virtual void WindowActivated(bool active);
149ff43bcbfSJohn Scipione
150ff43bcbfSJohn Scipioneprivate:
151ff43bcbfSJohn Scipione	void InitStrings(const Model*);
152ff43bcbfSJohn Scipione	void CheckAndSetSize();
153ff43bcbfSJohn Scipione	void OpenLinkSource();
154ff43bcbfSJohn Scipione	void OpenLinkTarget();
155ff43bcbfSJohn Scipione
156ff43bcbfSJohn Scipione	BString fPathStr;
157ff43bcbfSJohn Scipione	BString fLinkToStr;
158ff43bcbfSJohn Scipione	BString fSizeString;
159ff43bcbfSJohn Scipione	BString fModifiedStr;
160ff43bcbfSJohn Scipione	BString fCreatedStr;
161ff43bcbfSJohn Scipione	BString fKindStr;
162ff43bcbfSJohn Scipione	BString fDescStr;
163ff43bcbfSJohn Scipione
164ff43bcbfSJohn Scipione	off_t fFreeBytes;
165ff43bcbfSJohn Scipione	off_t fLastSize;
166ff43bcbfSJohn Scipione
167ff43bcbfSJohn Scipione	BRect fPathRect;
168ff43bcbfSJohn Scipione	BRect fLinkRect;
169ff43bcbfSJohn Scipione	BRect fDescRect;
170ff43bcbfSJohn Scipione	BRect fTitleRect;
171ff43bcbfSJohn Scipione	BRect fIconRect;
172ff43bcbfSJohn Scipione	BRect fSizeRect;
173ff43bcbfSJohn Scipione	BPoint fClickPoint;
174ff43bcbfSJohn Scipione	float fDivider;
175ff43bcbfSJohn Scipione
176ff43bcbfSJohn Scipione	BMenuField* fPreferredAppMenu;
177ff43bcbfSJohn Scipione	Model* fModel;
178ff43bcbfSJohn Scipione	Model* fIconModel;
179ff43bcbfSJohn Scipione	BBitmap* fIcon;
180ff43bcbfSJohn Scipione	bool fMouseDown;
181ff43bcbfSJohn Scipione	bool fDragging;
182ff43bcbfSJohn Scipione	bool fDoubleClick;
183ff43bcbfSJohn Scipione	track_state fTrackingState;
184ff43bcbfSJohn Scipione	bool fIsDropTarget;
185ff43bcbfSJohn Scipione	BTextView* fTitleEditView;
186ff43bcbfSJohn Scipione	PaneSwitch* fPermissionsSwitch;
187ff43bcbfSJohn Scipione	BWindow* fPathWindow;
188ff43bcbfSJohn Scipione	BWindow* fLinkWindow;
189ff43bcbfSJohn Scipione	BWindow* fDescWindow;
190c5b4dc40Slooncraz	color_which fCurrentLinkColorWhich;
191c5b4dc40Slooncraz	color_which fCurrentPathColorWhich;
192ff43bcbfSJohn Scipione
193ff43bcbfSJohn Scipione	typedef BView _inherited;
194aded7d13SAxel Dörfler};
195aded7d13SAxel Dörfler
196aded7d13SAxel Dörfler}	// namespace BPrivate
197aded7d13SAxel Dörfler
198ff43bcbfSJohn Scipione
19902be5353SAxel Dörflerconst float kDrawMargin = 3.0f;
20002be5353SAxel Dörflerconst float kBorderMargin = 15.0f;
20102be5353SAxel Dörflerconst float kBorderWidth = 32.0f;
20202be5353SAxel Dörfler
20302be5353SAxel Dörfler// Offsets taken from TAlertView::Draw in BAlert.cpp
20402be5353SAxel Dörflerconst float kIconHorizOffset = 18.0f;
20502be5353SAxel Dörflerconst float kIconVertOffset = 6.0f;
20602be5353SAxel Dörfler
20702be5353SAxel Dörfler// Amount you have to move the mouse before a drag starts
20802be5353SAxel Dörflerconst float kDragSlop = 3.0f;
20902be5353SAxel Dörfler
21002be5353SAxel Dörflerconst uint32 kSetPreferredApp = 'setp';
21102be5353SAxel Dörflerconst uint32 kSelectNewSymTarget = 'snew';
21202be5353SAxel Dörflerconst uint32 kNewTargetSelected = 'selc';
21302be5353SAxel Dörflerconst uint32 kRecalculateSize = 'resz';
21402be5353SAxel Dörflerconst uint32 kSetLinkTarget = 'link';
21502be5353SAxel Dörflerconst uint32 kPermissionsSelected = 'sepe';
21602be5353SAxel Dörflerconst uint32 kOpenLinkSource = 'opls';
21702be5353SAxel Dörflerconst uint32 kOpenLinkTarget = 'oplt';
21802be5353SAxel Dörfler
21902be5353SAxel Dörflerconst uint32 kPaneSwitchClosed = 0;
22002be5353SAxel Dörflerconst uint32 kPaneSwitchOpen = 2;
22102be5353SAxel Dörfler
22202be5353SAxel Dörfler
22302be5353SAxel Dörflerstatic void
224b05aa8b5SJohn ScipioneOpenParentAndSelectOriginal(const entry_ref* ref)
22502be5353SAxel Dörfler{
22602be5353SAxel Dörfler	BEntry entry(ref);
22702be5353SAxel Dörfler	node_ref node;
22802be5353SAxel Dörfler	entry.GetNodeRef(&node);
229c716766bSKarsten Heimrich
23002be5353SAxel Dörfler	BEntry parent;
23102be5353SAxel Dörfler	entry.GetParent(&parent);
23202be5353SAxel Dörfler	entry_ref parentRef;
23302be5353SAxel Dörfler	parent.GetRef(&parentRef);
23402be5353SAxel Dörfler
23502be5353SAxel Dörfler	BMessage message(B_REFS_RECEIVED);
23602be5353SAxel Dörfler	message.AddRef("refs", &parentRef);
23702be5353SAxel Dörfler	message.AddData("nodeRefToSelect", B_RAW_TYPE, &node, sizeof(node_ref));
238c716766bSKarsten Heimrich
23902be5353SAxel Dörfler	be_app->PostMessage(&message);
24002be5353SAxel Dörfler}
24102be5353SAxel Dörfler
24202be5353SAxel Dörfler
243b05aa8b5SJohn Scipionestatic BWindow*
244b05aa8b5SJohn ScipioneOpenToolTipWindow(BScreen& screen, BRect rect, const char* name,
245b05aa8b5SJohn Scipione	const char* string, BMessenger target, BMessage* message)
24602be5353SAxel Dörfler{
247aded7d13SAxel Dörfler	font_height fontHeight;
248aded7d13SAxel Dörfler	be_plain_font->GetHeight(&fontHeight);
249aded7d13SAxel Dörfler	float height = ceilf(fontHeight.ascent + fontHeight.descent);
250aded7d13SAxel Dörfler	rect.top = floorf(rect.top + (rect.Height() - height) / 2.0f);
251aded7d13SAxel Dörfler	rect.bottom = rect.top + height;
252aded7d13SAxel Dörfler
253aded7d13SAxel Dörfler	rect.right = rect.left + ceilf(be_plain_font->StringWidth(string)) + 4;
254aded7d13SAxel Dörfler	if (rect.left < 0)
255aded7d13SAxel Dörfler		rect.OffsetBy(-rect.left, 0);
256aded7d13SAxel Dörfler	else if (rect.right > screen.Frame().right)
257aded7d13SAxel Dörfler		rect.OffsetBy(screen.Frame().right - rect.right, 0);
258aded7d13SAxel Dörfler
259b05aa8b5SJohn Scipione	BWindow* window = new BWindow(rect, name, B_BORDERED_WINDOW_LOOK,
26002be5353SAxel Dörfler		B_FLOATING_ALL_WINDOW_FEEL,
26102be5353SAxel Dörfler		B_NOT_MOVABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE
26202be5353SAxel Dörfler		| B_NOT_RESIZABLE | B_AVOID_FOCUS | B_NO_WORKSPACE_ACTIVATION
26302be5353SAxel Dörfler		| B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS);
26402be5353SAxel Dörfler
265b05aa8b5SJohn Scipione	TrackingView* trackingView = new TrackingView(window->Bounds(),
266aded7d13SAxel Dörfler		string, message);
26702be5353SAxel Dörfler	trackingView->SetTarget(target);
26802be5353SAxel Dörfler	window->AddChild(trackingView);
26902be5353SAxel Dörfler
27002be5353SAxel Dörfler	window->Sync();
27102be5353SAxel Dörfler	window->Show();
27202be5353SAxel Dörfler
27302be5353SAxel Dörfler	return window;
27402be5353SAxel Dörfler}
27502be5353SAxel Dörfler
27602be5353SAxel Dörfler
277eed35bacSJohn Scipione//	#pragma mark - BInfoWindow
27802be5353SAxel Dörfler
27902be5353SAxel Dörfler
280a51764c5SJohn ScipioneBInfoWindow::BInfoWindow(Model* model, int32 group_index,
281a51764c5SJohn Scipione	LockingList<BWindow>* list)
282ff43bcbfSJohn Scipione	:
2838742c1d0SAugustin Cavalier	BWindow(BInfoWindow::InfoWindowRect(),
2840cf86704SAxel Dörfler		"InfoWindow", B_TITLED_WINDOW,
2850cf86704SAxel Dörfler		B_NOT_RESIZABLE | B_NOT_ZOOMABLE, B_CURRENT_WORKSPACE),
2860cf86704SAxel Dörfler	fModel(model),
2870cf86704SAxel Dörfler	fStopCalc(false),
2880cf86704SAxel Dörfler	fIndex(group_index),
2890cf86704SAxel Dörfler	fCalcThreadID(-1),
2900cf86704SAxel Dörfler	fWindowList(list),
2910cf86704SAxel Dörfler	fPermissionsView(NULL),
2920cf86704SAxel Dörfler	fFilePanel(NULL),
2930cf86704SAxel Dörfler	fFilePanelOpen(false)
29402be5353SAxel Dörfler{
295ff43bcbfSJohn Scipione	SetPulseRate(1000000);
296ff43bcbfSJohn Scipione		// we use pulse to check freebytes on volume
2970cf86704SAxel Dörfler
298a5dc8f86SPhilippe Saint-Pierre	TTracker::WatchNode(model->NodeRef(), B_WATCH_ALL | B_WATCH_MOUNT, this);
29902be5353SAxel Dörfler
30002be5353SAxel Dörfler	// window list is Locked by Tracker around this constructor
301d7e68211SJohn Scipione	if (list != NULL)
30202be5353SAxel Dörfler		list->AddItem(this);
30302be5353SAxel Dörfler
30477e2c2daSJonas Sundström	AddShortcut('E', 0, new BMessage(kEditItem));
30502be5353SAxel Dörfler	AddShortcut('O', 0, new BMessage(kOpenSelection));
30602be5353SAxel Dörfler	AddShortcut('U', 0, new BMessage(kUnmountVolume));
30702be5353SAxel Dörfler	AddShortcut('P', 0, new BMessage(kPermissionsSelected));
30802be5353SAxel Dörfler
30902be5353SAxel Dörfler	Run();
31002be5353SAxel Dörfler}
31102be5353SAxel Dörfler
31202be5353SAxel Dörfler
31302be5353SAxel DörflerBInfoWindow::~BInfoWindow()
31402be5353SAxel Dörfler{
31502be5353SAxel Dörfler	// Check to make sure the file panel is destroyed
31602be5353SAxel Dörfler	delete fFilePanel;
31702be5353SAxel Dörfler	delete fModel;
31802be5353SAxel Dörfler}
31902be5353SAxel Dörfler
32002be5353SAxel Dörfler
32102be5353SAxel DörflerBRect
3228742c1d0SAugustin CavalierBInfoWindow::InfoWindowRect()
32302be5353SAxel Dörfler{
324c5b4dc40Slooncraz	// starting size of window
32502be5353SAxel Dörfler	return BRect(70, 50, 385, 240);
32602be5353SAxel Dörfler}
32702be5353SAxel Dörfler
32802be5353SAxel Dörfler
32902be5353SAxel Dörflervoid
33002be5353SAxel DörflerBInfoWindow::Quit()
33102be5353SAxel Dörfler{
33202be5353SAxel Dörfler	stop_watching(this);
33302be5353SAxel Dörfler
33402be5353SAxel Dörfler	if (fWindowList) {
33502be5353SAxel Dörfler		AutoLock<LockingList<BWindow> > lock(fWindowList);
33602be5353SAxel Dörfler		fWindowList->RemoveItem(this);
33702be5353SAxel Dörfler	}
33802be5353SAxel Dörfler
33902be5353SAxel Dörfler	fStopCalc = true;
34002be5353SAxel Dörfler
34102be5353SAxel Dörfler	// wait until CalcSize thread has terminated before closing window
34202be5353SAxel Dörfler	status_t result;
34302be5353SAxel Dörfler	wait_for_thread(fCalcThreadID, &result);
34402be5353SAxel Dörfler
34502be5353SAxel Dörfler	_inherited::Quit();
34602be5353SAxel Dörfler}
34702be5353SAxel Dörfler
34802be5353SAxel Dörfler
34902be5353SAxel Dörflerbool
350b05aa8b5SJohn ScipioneBInfoWindow::IsShowing(const node_ref* node) const
35102be5353SAxel Dörfler{
35202be5353SAxel Dörfler	return *TargetModel()->NodeRef() == *node;
35302be5353SAxel Dörfler}
35402be5353SAxel Dörfler
35502be5353SAxel Dörfler
35602be5353SAxel Dörflervoid
35702be5353SAxel DörflerBInfoWindow::Show()
35802be5353SAxel Dörfler{
35902be5353SAxel Dörfler	BModelOpener modelOpener(TargetModel());
36002be5353SAxel Dörfler	if (TargetModel()->InitCheck() != B_OK) {
36102be5353SAxel Dörfler		Close();
36202be5353SAxel Dörfler		return;
36302be5353SAxel Dörfler	}
36402be5353SAxel Dörfler
36502be5353SAxel Dörfler	AutoLock<BWindow> lock(this);
36602be5353SAxel Dörfler
367c5b4dc40Slooncraz	const BFont* font = be_plain_font;
368c5b4dc40Slooncraz	float width = font->StringWidth("This is a really long string which we"
369c5b4dc40Slooncraz		"will use to find the window width");
370c5b4dc40Slooncraz
3715f8edc9cSTsimblist	// window height depends on file type
372756c36e7SAdrien Destugues	int lines = 9;
3735f8edc9cSTsimblist	if (fModel->IsExecutable())
374d54cb434SHumdinger		lines++;
3755f8edc9cSTsimblist	float height = font->Size() * (lines * 2 + 1);
3765f8edc9cSTsimblist
377c5b4dc40Slooncraz	ResizeTo(width, height);
378c5b4dc40Slooncraz
37902be5353SAxel Dörfler	BRect attrRect(Bounds());
38002be5353SAxel Dörfler	fAttributeView = new AttributeView(attrRect, TargetModel());
38102be5353SAxel Dörfler	AddChild(fAttributeView);
38202be5353SAxel Dörfler
38302be5353SAxel Dörfler	// position window appropriately based on index
3848742c1d0SAugustin Cavalier	BRect windRect(InfoWindowRect());
38502be5353SAxel Dörfler	if ((fIndex + 2) % 2 == 1) {
38602be5353SAxel Dörfler		windRect.OffsetBy(320, 0);
38702be5353SAxel Dörfler		fIndex--;
38802be5353SAxel Dörfler	}
38902be5353SAxel Dörfler
39002be5353SAxel Dörfler	windRect.OffsetBy(fIndex * 8, fIndex * 8);
39102be5353SAxel Dörfler
39202be5353SAxel Dörfler	// make sure window is visible on screen
39302be5353SAxel Dörfler	BScreen screen(this);
39402be5353SAxel Dörfler	if (!windRect.Intersects(screen.Frame()))
39502be5353SAxel Dörfler		windRect.OffsetTo(50, 50);
39602be5353SAxel Dörfler
39702be5353SAxel Dörfler	MoveTo(windRect.LeftTop());
39802be5353SAxel Dörfler
39902be5353SAxel Dörfler	// volume case is handled by view
4000cf86704SAxel Dörfler	if (!TargetModel()->IsVolume() && !TargetModel()->IsRoot()) {
40102be5353SAxel Dörfler		if (TargetModel()->IsDirectory()) {
40202be5353SAxel Dörfler			// if this is a folder then spawn thread to calculate size
403ff43bcbfSJohn Scipione			SetSizeString(B_TRANSLATE("calculating" B_UTF8_ELLIPSIS));
404a5dc8f86SPhilippe Saint-Pierre			fCalcThreadID = spawn_thread(BInfoWindow::CalcSize, "CalcSize",
405a5dc8f86SPhilippe Saint-Pierre				B_NORMAL_PRIORITY, this);
406a5dc8f86SPhilippe Saint-Pierre			resume_thread(fCalcThreadID);
40702be5353SAxel Dörfler		} else {
40802be5353SAxel Dörfler			fAttributeView->SetLastSize(TargetModel()->StatBuf()->st_size);
40902be5353SAxel Dörfler
41002be5353SAxel Dörfler			BString sizeStr;
41102be5353SAxel Dörfler			GetSizeString(sizeStr, fAttributeView->LastSize(), 0);
412ff43bcbfSJohn Scipione			SetSizeString(sizeStr.String());
41302be5353SAxel Dörfler		}
41402be5353SAxel Dörfler	}
41502be5353SAxel Dörfler
4164ed28a57SAlexandre Deckner	BString buffer(B_TRANSLATE_COMMENT("%name info", "InfoWindow Title"));
4174ed28a57SAlexandre Deckner	buffer.ReplaceFirst("%name", TargetModel()->Name());
41802be5353SAxel Dörfler	SetTitle(buffer.String());
41902be5353SAxel Dörfler
42002be5353SAxel Dörfler	lock.Unlock();
42102be5353SAxel Dörfler	_inherited::Show();
42202be5353SAxel Dörfler}
42302be5353SAxel Dörfler
42402be5353SAxel Dörfler
42502be5353SAxel Dörflervoid
426b05aa8b5SJohn ScipioneBInfoWindow::MessageReceived(BMessage* message)
42702be5353SAxel Dörfler{
42802be5353SAxel Dörfler	switch (message->what) {
429c716766bSKarsten Heimrich		case kRestoreState:
43002be5353SAxel Dörfler			Show();
43102be5353SAxel Dörfler			break;
43202be5353SAxel Dörfler
43302be5353SAxel Dörfler		case kOpenSelection:
43402be5353SAxel Dörfler		{
43502be5353SAxel Dörfler			BMessage refsMessage(B_REFS_RECEIVED);
43602be5353SAxel Dörfler			refsMessage.AddRef("refs", fModel->EntryRef());
437c716766bSKarsten Heimrich
43802be5353SAxel Dörfler			// add a messenger to the launch message that will be used to
43902be5353SAxel Dörfler			// dispatch scripting calls from apps to the PoseView
44002be5353SAxel Dörfler			refsMessage.AddMessenger("TrackerViewToken", BMessenger(this));
44102be5353SAxel Dörfler			be_app->PostMessage(&refsMessage);
44202be5353SAxel Dörfler			break;
44302be5353SAxel Dörfler		}
44402be5353SAxel Dörfler
44502be5353SAxel Dörfler		case kEditItem:
44602be5353SAxel Dörfler		{
44702be5353SAxel Dörfler			BEntry entry(fModel->EntryRef());
44877e2c2daSJonas Sundström			if (!fModel->HasLocalizedName()
4494072c4f1SAdrien Destugues				&& ConfirmChangeIfWellKnownDirectory(&entry, kRename)) {
45002be5353SAxel Dörfler				fAttributeView->BeginEditingTitle();
4514072c4f1SAdrien Destugues			}
45202be5353SAxel Dörfler			break;
45302be5353SAxel Dörfler		}
45402be5353SAxel Dörfler
45502be5353SAxel Dörfler		case kIdentifyEntry:
45602be5353SAxel Dörfler		{
45702be5353SAxel Dörfler			bool force = (modifiers() & B_OPTION_KEY) != 0;
45802be5353SAxel Dörfler			BEntry entry;
45902be5353SAxel Dörfler			if (entry.SetTo(fModel->EntryRef(), true) == B_OK) {
46002be5353SAxel Dörfler				BPath path;
461c716766bSKarsten Heimrich				if (entry.GetPath(&path) == B_OK)
46202be5353SAxel Dörfler					update_mime_info(path.Path(), true, false, force ? 2 : 1);
46302be5353SAxel Dörfler			}
46402be5353SAxel Dörfler			break;
46502be5353SAxel Dörfler		}
46602be5353SAxel Dörfler
46702be5353SAxel Dörfler		case kRecalculateSize:
46802be5353SAxel Dörfler		{
469a5dc8f86SPhilippe Saint-Pierre			fStopCalc = true;
470a5dc8f86SPhilippe Saint-Pierre			// Wait until any current CalcSize thread has terminated before
471a5dc8f86SPhilippe Saint-Pierre			// starting a new one
472a5dc8f86SPhilippe Saint-Pierre			status_t result;
473a5dc8f86SPhilippe Saint-Pierre			wait_for_thread(fCalcThreadID, &result);
474a5dc8f86SPhilippe Saint-Pierre
475a5dc8f86SPhilippe Saint-Pierre			// Start recalculating..
476a5dc8f86SPhilippe Saint-Pierre			fStopCalc = false;
477ff43bcbfSJohn Scipione			SetSizeString(B_TRANSLATE("calculating" B_UTF8_ELLIPSIS));
478994b2356SStephan Aßmus			fCalcThreadID = spawn_thread(BInfoWindow::CalcSize, "CalcSize",
479a5dc8f86SPhilippe Saint-Pierre				B_NORMAL_PRIORITY, this);
480a5dc8f86SPhilippe Saint-Pierre			resume_thread(fCalcThreadID);
48102be5353SAxel Dörfler			break;
48202be5353SAxel Dörfler		}
48302be5353SAxel Dörfler
484c716766bSKarsten Heimrich		case kSetLinkTarget:
48502be5353SAxel Dörfler			OpenFilePanel(fModel->EntryRef());
48602be5353SAxel Dörfler			break;
48702be5353SAxel Dörfler
48802be5353SAxel Dörfler		// An item was dropped into the window
48902be5353SAxel Dörfler		case B_SIMPLE_DATA:
49002be5353SAxel Dörfler			// If we are not a SymLink, just ignore the request
491c716766bSKarsten Heimrich			if (!fModel->IsSymLink())
49202be5353SAxel Dörfler				break;
49302be5353SAxel Dörfler			// supposed to fall through
49402be5353SAxel Dörfler		// An item was selected from the file panel
495ff43bcbfSJohn Scipione		// fall-through
49602be5353SAxel Dörfler		case kNewTargetSelected:
49702be5353SAxel Dörfler		{
49802be5353SAxel Dörfler			// Extract the BEntry, and set its full path to the string value
49902be5353SAxel Dörfler			BEntry targetEntry;
50002be5353SAxel Dörfler			entry_ref ref;
50102be5353SAxel Dörfler			BPath path;
50202be5353SAxel Dörfler
50302be5353SAxel Dörfler			if (message->FindRef("refs", &ref) == B_OK
50402be5353SAxel Dörfler				&& targetEntry.SetTo(&ref, true) == B_OK
50502be5353SAxel Dörfler				&& targetEntry.Exists()) {
50602be5353SAxel Dörfler				// We now have to re-target the broken symlink. Unfortunately,
50702be5353SAxel Dörfler				// there's no way to change the target of an existing symlink.
50802be5353SAxel Dörfler				// So we have to delete the old one and create a new one.
509a51764c5SJohn Scipione				// First, stop watching the broken node
510a51764c5SJohn Scipione				// (we don't want this window to quit when the node
511a51764c5SJohn Scipione				// is removed.)
51202be5353SAxel Dörfler				stop_watching(this);
51302be5353SAxel Dörfler
51402be5353SAxel Dörfler				// Get the parent
51502be5353SAxel Dörfler				BDirectory parent;
51602be5353SAxel Dörfler				BEntry tmpEntry(TargetModel()->EntryRef());
51702be5353SAxel Dörfler				if (tmpEntry.GetParent(&parent) != B_OK)
51802be5353SAxel Dörfler					break;
51902be5353SAxel Dörfler
52002be5353SAxel Dörfler				// Preserve the name
52102be5353SAxel Dörfler				BString name(TargetModel()->Name());
52202be5353SAxel Dörfler
52302be5353SAxel Dörfler				// Extract path for new target
52402be5353SAxel Dörfler				BEntry target(&ref);
52502be5353SAxel Dörfler				BPath targetPath;
52602be5353SAxel Dörfler				if (target.GetPath(&targetPath) != B_OK)
52702be5353SAxel Dörfler					break;
52802be5353SAxel Dörfler
52902be5353SAxel Dörfler				// Preserve the original attributes
53002be5353SAxel Dörfler				AttributeStreamMemoryNode memoryNode;
53102be5353SAxel Dörfler				{
53202be5353SAxel Dörfler					BModelOpener opener(TargetModel());
53302be5353SAxel Dörfler					AttributeStreamFileNode original(TargetModel()->Node());
53402be5353SAxel Dörfler					memoryNode << original;
53502be5353SAxel Dörfler				}
53602be5353SAxel Dörfler
53702be5353SAxel Dörfler				// Delete the broken node.
53802be5353SAxel Dörfler				BEntry oldEntry(TargetModel()->EntryRef());
53902be5353SAxel Dörfler				oldEntry.Remove();
54002be5353SAxel Dörfler
54102be5353SAxel Dörfler				// Create new node
54202be5353SAxel Dörfler				BSymLink link;
54302be5353SAxel Dörfler				parent.CreateSymLink(name.String(), targetPath.Path(), &link);
54402be5353SAxel Dörfler
54502be5353SAxel Dörfler				// Update our Model()
54602be5353SAxel Dörfler				BEntry symEntry(&parent, name.String());
54702be5353SAxel Dörfler				fModel->SetTo(&symEntry);
54802be5353SAxel Dörfler
54902be5353SAxel Dörfler				BModelWriteOpener opener(TargetModel());
55002be5353SAxel Dörfler
55102be5353SAxel Dörfler				// Copy the attributes back
55202be5353SAxel Dörfler				AttributeStreamFileNode newNode(TargetModel()->Node());
55302be5353SAxel Dörfler				newNode << memoryNode;
55402be5353SAxel Dörfler
555a5dc8f86SPhilippe Saint-Pierre				// Start watching this again
556994b2356SStephan Aßmus				TTracker::WatchNode(TargetModel()->NodeRef(),
557a5dc8f86SPhilippe Saint-Pierre					B_WATCH_ALL | B_WATCH_MOUNT, this);
55802be5353SAxel Dörfler
559c716766bSKarsten Heimrich				// Tell the attribute view about this new model
56002be5353SAxel Dörfler				fAttributeView->ReLinkTargetModel(TargetModel());
56102be5353SAxel Dörfler			}
56202be5353SAxel Dörfler			break;
56302be5353SAxel Dörfler		}
56402be5353SAxel Dörfler
565c716766bSKarsten Heimrich		case B_CANCEL:
56602be5353SAxel Dörfler			// File panel window has closed
56702be5353SAxel Dörfler			delete fFilePanel;
56802be5353SAxel Dörfler			fFilePanel = NULL;
56902be5353SAxel Dörfler			// It's no longer open
57002be5353SAxel Dörfler			fFilePanelOpen = false;
57102be5353SAxel Dörfler			break;
57202be5353SAxel Dörfler
57302be5353SAxel Dörfler		case kUnmountVolume:
57402be5353SAxel Dörfler			// Sanity check that this isn't the boot volume
57502be5353SAxel Dörfler			// (The unmount menu item has been disabled in this
57602be5353SAxel Dörfler			// case, but the shortcut is still active)
57702be5353SAxel Dörfler			if (fModel->IsVolume()) {
57802be5353SAxel Dörfler				BVolume boot;
57902be5353SAxel Dörfler				BVolumeRoster().GetBootVolume(&boot);
58002be5353SAxel Dörfler				BVolume volume(fModel->NodeRef()->device);
58102be5353SAxel Dörfler				if (volume != boot) {
5829cc03189SJohn Scipione					TTracker* tracker = dynamic_cast<TTracker*>(be_app);
5839cc03189SJohn Scipione					if (tracker != NULL)
5849cc03189SJohn Scipione						tracker->SaveAllPoseLocations();
58502be5353SAxel Dörfler
58602be5353SAxel Dörfler					BMessage unmountMessage(kUnmountVolume);
58702be5353SAxel Dörfler					unmountMessage.AddInt32("device_id", volume.Device());
58802be5353SAxel Dörfler					be_app->PostMessage(&unmountMessage);
58902be5353SAxel Dörfler				}
59002be5353SAxel Dörfler			}
59102be5353SAxel Dörfler			break;
59202be5353SAxel Dörfler
593c716766bSKarsten Heimrich		case kEmptyTrash:
59402be5353SAxel Dörfler			FSEmptyTrash();
59502be5353SAxel Dörfler			break;
59602be5353SAxel Dörfler
597a5dc8f86SPhilippe Saint-Pierre		case B_NODE_MONITOR:
59802be5353SAxel Dörfler			switch (message->FindInt32("opcode")) {
59902be5353SAxel Dörfler				case B_ENTRY_REMOVED:
600d7e68211SJohn Scipione				{
601d7e68211SJohn Scipione					node_ref itemNode;
602d7e68211SJohn Scipione					message->FindInt32("device", &itemNode.device);
603d7e68211SJohn Scipione					message->FindInt64("node", &itemNode.node);
604d7e68211SJohn Scipione					// our window itself may be deleted
605d7e68211SJohn Scipione					if (*TargetModel()->NodeRef() == itemNode)
606d7e68211SJohn Scipione						Close();
607d7e68211SJohn Scipione					break;
608d7e68211SJohn Scipione				}
60902be5353SAxel Dörfler
61002be5353SAxel Dörfler				case B_ENTRY_MOVED:
61102be5353SAxel Dörfler				case B_STAT_CHANGED:
612c716766bSKarsten Heimrich				case B_ATTR_CHANGED:
61302be5353SAxel Dörfler					fAttributeView->ModelChanged(TargetModel(), message);
614a51764c5SJohn Scipione						// must be called before the
615a51764c5SJohn Scipione						// FilePermissionView::ModelChanged()
616a51764c5SJohn Scipione						// call, because it changes the model...
617a51764c5SJohn Scipione						// (bad style!)
61802be5353SAxel Dörfler
61902be5353SAxel Dörfler					if (fPermissionsView != NULL)
62002be5353SAxel Dörfler						fPermissionsView->ModelChanged(TargetModel());
62102be5353SAxel Dörfler					break;
62202be5353SAxel Dörfler
62302be5353SAxel Dörfler				case B_DEVICE_UNMOUNTED:
624ff43bcbfSJohn Scipione				{
625ff43bcbfSJohn Scipione					// We were watching a volume that is no longer
626ff43bcbfSJohn Scipione					// mounted, we might as well quit
627ff43bcbfSJohn Scipione					node_ref itemNode;
628ff43bcbfSJohn Scipione					// Only the device information is available
629ff43bcbfSJohn Scipione					message->FindInt32("device", &itemNode.device);
630ff43bcbfSJohn Scipione					if (TargetModel()->NodeRef()->device == itemNode.device)
631ff43bcbfSJohn Scipione						Close();
632ff43bcbfSJohn Scipione					break;
633ff43bcbfSJohn Scipione				}
63402be5353SAxel Dörfler
635c716766bSKarsten Heimrich				default:
63602be5353SAxel Dörfler					break;
63702be5353SAxel Dörfler			}
63802be5353SAxel Dörfler			break;
63902be5353SAxel Dörfler
64002be5353SAxel Dörfler		case kPermissionsSelected:
641c5b4dc40Slooncraz		{
642c5b4dc40Slooncraz			BRect permissionsBounds(kBorderWidth + 1,
643d7e68211SJohn Scipione						fAttributeView->Bounds().bottom,
644d7e68211SJohn Scipione						fAttributeView->Bounds().right,
645756c36e7SAdrien Destugues						fAttributeView->Bounds().bottom + 103);
64602be5353SAxel Dörfler
647c5b4dc40Slooncraz			if (fPermissionsView == NULL) {
648c5b4dc40Slooncraz				// Only true on first call.
649c5b4dc40Slooncraz				fPermissionsView = new FilePermissionsView(
650c5b4dc40Slooncraz					permissionsBounds, fModel);
651c5b4dc40Slooncraz				ResizeBy(0, permissionsBounds.Height());
65202be5353SAxel Dörfler				fAttributeView->AddChild(fPermissionsView);
65302be5353SAxel Dörfler				fAttributeView->SetPermissionsSwitchState(kPaneSwitchOpen);
65402be5353SAxel Dörfler			} else if (fPermissionsView->IsHidden()) {
65502be5353SAxel Dörfler				fPermissionsView->ModelChanged(fModel);
65602be5353SAxel Dörfler				fPermissionsView->Show();
657c5b4dc40Slooncraz				ResizeBy(0, permissionsBounds.Height());
65802be5353SAxel Dörfler				fAttributeView->SetPermissionsSwitchState(kPaneSwitchOpen);
65902be5353SAxel Dörfler			} else {
66002be5353SAxel Dörfler				fPermissionsView->Hide();
661c5b4dc40Slooncraz				ResizeBy(0, -permissionsBounds.Height());
66202be5353SAxel Dörfler				fAttributeView->SetPermissionsSwitchState(kPaneSwitchClosed);
66302be5353SAxel Dörfler			}
66402be5353SAxel Dörfler			break;
665c5b4dc40Slooncraz		}
66602be5353SAxel Dörfler
66702be5353SAxel Dörfler		default:
66802be5353SAxel Dörfler			_inherited::MessageReceived(message);
66902be5353SAxel Dörfler			break;
67002be5353SAxel Dörfler	}
67102be5353SAxel Dörfler}
67202be5353SAxel Dörfler
67302be5353SAxel Dörfler
67402be5353SAxel Dörflervoid
6755b6e8d49SJohn ScipioneBInfoWindow::GetSizeString(BString& result, off_t size, int32 fileCount)
67602be5353SAxel Dörfler{
6777457ccb4SAugustin Cavalier	static BStringFormat sizeFormat(B_TRANSLATE(
678961fdd8cSAdrien Destugues		"{0, plural, one{(# byte)} other{(# bytes)}}"));
6797457ccb4SAugustin Cavalier	static BStringFormat countFormat(B_TRANSLATE(
680961fdd8cSAdrien Destugues		"{0, plural, one{for # file} other{for # files}}"));
68153382a8aSAdrien Destugues
682961fdd8cSAdrien Destugues	char sizeBuffer[128];
6834ed28a57SAlexandre Deckner	result << string_for_size((double)size, sizeBuffer, sizeof(sizeBuffer));
6844ed28a57SAlexandre Deckner
685b599c219SPhilippe Houdoin	if (size >= kKBSize) {
68653382a8aSAdrien Destugues		result << " ";
6875b6e8d49SJohn Scipione
688961fdd8cSAdrien Destugues		sizeFormat.Format(result, size);
6894ed28a57SAlexandre Deckner			// "bytes" translation could come from string_for_size
6904ed28a57SAlexandre Deckner			// which could be part of the localekit itself
6914ed28a57SAlexandre Deckner	}
69202be5353SAxel Dörfler
6934ed28a57SAlexandre Deckner	if (fileCount != 0) {
69453382a8aSAdrien Destugues		result << " ";
695961fdd8cSAdrien Destugues		countFormat.Format(result, fileCount);
6964ed28a57SAlexandre Deckner	}
69702be5353SAxel Dörfler}
69802be5353SAxel Dörfler
69902be5353SAxel Dörfler
70002be5353SAxel Dörflerint32
701b05aa8b5SJohn ScipioneBInfoWindow::CalcSize(void* castToWindow)
70202be5353SAxel Dörfler{
703b05aa8b5SJohn Scipione	BInfoWindow* window = static_cast<BInfoWindow*>(castToWindow);
70402be5353SAxel Dörfler	BDirectory dir(window->TargetModel()->EntryRef());
70502be5353SAxel Dörfler	BDirectory trashDir;
706c716766bSKarsten Heimrich	FSGetTrashDir(&trashDir, window->TargetModel()->EntryRef()->device);
70702be5353SAxel Dörfler	if (dir.InitCheck() != B_OK) {
70802be5353SAxel Dörfler		if (window->StopCalc())
70902be5353SAxel Dörfler			return B_ERROR;
7100cf86704SAxel Dörfler
71102be5353SAxel Dörfler		AutoLock<BWindow> lock(window);
71202be5353SAxel Dörfler		if (!lock)
71302be5353SAxel Dörfler			return B_ERROR;
71402be5353SAxel Dörfler
715ff43bcbfSJohn Scipione		window->SetSizeString(B_TRANSLATE("Error calculating folder size."));
71602be5353SAxel Dörfler		return B_ERROR;
71702be5353SAxel Dörfler	}
7180cf86704SAxel Dörfler
71902be5353SAxel Dörfler	BEntry dirEntry, trashEntry;
72002be5353SAxel Dörfler	dir.GetEntry(&dirEntry);
72102be5353SAxel Dörfler	trashDir.GetEntry(&trashEntry);
72202be5353SAxel Dörfler
72302be5353SAxel Dörfler	BString sizeString;
72402be5353SAxel Dörfler
72502be5353SAxel Dörfler	// check if user has asked for trash dir info
72602be5353SAxel Dörfler	if (dirEntry != trashEntry) {
72702be5353SAxel Dörfler		// if not, perform normal info calculations
72802be5353SAxel Dörfler		off_t size = 0;
72902be5353SAxel Dörfler		int32 fileCount = 0;
73002be5353SAxel Dörfler		int32 dirCount = 0;
7313cc5c3ffSStephan Aßmus		CopyLoopControl loopControl;
7323cc5c3ffSStephan Aßmus		FSRecursiveCalcSize(window, &loopControl, &dir, &size, &fileCount,
7333cc5c3ffSStephan Aßmus			&dirCount);
7340cf86704SAxel Dörfler
73502be5353SAxel Dörfler		// got the size value, update the size string
73602be5353SAxel Dörfler		GetSizeString(sizeString, size, fileCount);
737ff43bcbfSJohn Scipione	} else {
73802be5353SAxel Dörfler		// in the trash case, iterate through and sum up
73902be5353SAxel Dörfler		// size/counts for all present trash dirs
74002be5353SAxel Dörfler		off_t totalSize = 0, currentSize;
74102be5353SAxel Dörfler		int32 totalFileCount = 0, currentFileCount;
74202be5353SAxel Dörfler		int32 totalDirCount = 0, currentDirCount;
74302be5353SAxel Dörfler		BVolumeRoster volRoster;
74402be5353SAxel Dörfler		volRoster.Rewind();
74502be5353SAxel Dörfler		BVolume volume;
74602be5353SAxel Dörfler		while (volRoster.GetNextVolume(&volume) == B_OK) {
74702be5353SAxel Dörfler			if (!volume.IsPersistent())
74802be5353SAxel Dörfler				continue;
74902be5353SAxel Dörfler
75002be5353SAxel Dörfler			currentSize = 0;
75102be5353SAxel Dörfler			currentFileCount = 0;
75202be5353SAxel Dörfler			currentDirCount = 0;
7530cf86704SAxel Dörfler
75402be5353SAxel Dörfler			BDirectory trashDir;
75502be5353SAxel Dörfler			if (FSGetTrashDir(&trashDir, volume.Device()) == B_OK) {
7563cc5c3ffSStephan Aßmus				CopyLoopControl loopControl;
7573cc5c3ffSStephan Aßmus				FSRecursiveCalcSize(window, &loopControl, &trashDir,
7583cc5c3ffSStephan Aßmus					&currentSize, &currentFileCount, &currentDirCount);
75902be5353SAxel Dörfler				totalSize += currentSize;
76002be5353SAxel Dörfler				totalFileCount += currentFileCount;
76102be5353SAxel Dörfler				totalDirCount += currentDirCount;
76202be5353SAxel Dörfler			}
763c716766bSKarsten Heimrich		}
76402be5353SAxel Dörfler		GetSizeString(sizeString, totalSize, totalFileCount);
76502be5353SAxel Dörfler	}
7660cf86704SAxel Dörfler
7673cc5c3ffSStephan Aßmus	if (window->StopCalc()) {
76802be5353SAxel Dörfler		// window closed, bail
76902be5353SAxel Dörfler		return B_OK;
7703cc5c3ffSStephan Aßmus	}
7710cf86704SAxel Dörfler
77202be5353SAxel Dörfler	AutoLock<BWindow> lock(window);
773c716766bSKarsten Heimrich	if (lock.IsLocked())
774ff43bcbfSJohn Scipione		window->SetSizeString(sizeString.String());
7750cf86704SAxel Dörfler
77602be5353SAxel Dörfler	return B_OK;
77702be5353SAxel Dörfler}
77802be5353SAxel Dörfler
77902be5353SAxel Dörfler
78002be5353SAxel Dörflervoid
781ff43bcbfSJohn ScipioneBInfoWindow::SetSizeString(const char* sizeString)
78202be5353SAxel Dörfler{
783a51764c5SJohn Scipione	AttributeView* view
784ff43bcbfSJohn Scipione		= dynamic_cast<AttributeView*>(FindView("attr_view"));
785ff43bcbfSJohn Scipione	if (view != NULL)
786ff43bcbfSJohn Scipione		view->SetSizeString(sizeString);
78702be5353SAxel Dörfler}
78802be5353SAxel Dörfler
78902be5353SAxel Dörfler
79002be5353SAxel Dörflervoid
791b05aa8b5SJohn ScipioneBInfoWindow::OpenFilePanel(const entry_ref* ref)
79202be5353SAxel Dörfler{
79302be5353SAxel Dörfler	// Open a file dialog box to allow the user to select a new target
79402be5353SAxel Dörfler	// for the sym link
79502be5353SAxel Dörfler	if (fFilePanel == NULL) {
79602be5353SAxel Dörfler		BMessenger runner(this);
79705ea8535SKarsten Heimrich		BMessage message(kNewTargetSelected);
79802be5353SAxel Dörfler		fFilePanel = new BFilePanel(B_OPEN_PANEL, &runner, ref,
79902be5353SAxel Dörfler			B_FILE_NODE | B_SYMLINK_NODE | B_DIRECTORY_NODE,
80005ea8535SKarsten Heimrich			false, &message);
80102be5353SAxel Dörfler
80202be5353SAxel Dörfler		if (fFilePanel != NULL) {
803a51764c5SJohn Scipione			fFilePanel->SetButtonLabel(B_DEFAULT_BUTTON,
804a51764c5SJohn Scipione				B_TRANSLATE("Select"));
80502be5353SAxel Dörfler			fFilePanel->Window()->ResizeTo(500, 300);
806504f70a6SJohn Scipione			BString title(B_TRANSLATE_COMMENT("Link \"%name\" to:",
807504f70a6SJohn Scipione				"File dialog title for new sym link"));
8084ed28a57SAlexandre Deckner			title.ReplaceFirst("%name", fModel->Name());
80902be5353SAxel Dörfler			fFilePanel->Window()->SetTitle(title.String());
81002be5353SAxel Dörfler			fFilePanel->Show();
81102be5353SAxel Dörfler			fFilePanelOpen = true;
81202be5353SAxel Dörfler		}
81302be5353SAxel Dörfler	} else if (!fFilePanelOpen) {
81402be5353SAxel Dörfler		fFilePanel->Show();
81502be5353SAxel Dörfler		fFilePanelOpen = true;
81602be5353SAxel Dörfler	} else {
81702be5353SAxel Dörfler		fFilePanelOpen = true;
81802be5353SAxel Dörfler		fFilePanel->Window()->Activate(true);
81902be5353SAxel Dörfler	}
82002be5353SAxel Dörfler}
82102be5353SAxel Dörfler
82202be5353SAxel Dörfler
823ff43bcbfSJohn Scipione//	#pragma mark - AttributeView
82402be5353SAxel Dörfler
82502be5353SAxel Dörfler
826b05aa8b5SJohn ScipioneAttributeView::AttributeView(BRect rect, Model* model)
827ff43bcbfSJohn Scipione	:
828ff43bcbfSJohn Scipione	BView(rect, "attr_view", B_FOLLOW_ALL_SIDES,
829a51764c5SJohn Scipione		B_WILL_DRAW | B_PULSE_NEEDED),
8300cf86704SAxel Dörfler	fDivider(0),
8310cf86704SAxel Dörfler	fPreferredAppMenu(NULL),
8320cf86704SAxel Dörfler	fModel(model),
8330cf86704SAxel Dörfler	fIconModel(model),
8340cf86704SAxel Dörfler	fMouseDown(false),
8350cf86704SAxel Dörfler	fDragging(false),
8360cf86704SAxel Dörfler	fDoubleClick(false),
8370cf86704SAxel Dörfler	fTrackingState(no_track),
8380cf86704SAxel Dörfler	fIsDropTarget(false),
8390cf86704SAxel Dörfler	fTitleEditView(NULL),
8400cf86704SAxel Dörfler	fPathWindow(NULL),
8410cf86704SAxel Dörfler	fLinkWindow(NULL),
842c5b4dc40Slooncraz	fDescWindow(NULL),
843c5b4dc40Slooncraz	fCurrentLinkColorWhich(B_LINK_TEXT_COLOR),
844c5b4dc40Slooncraz	fCurrentPathColorWhich(fCurrentLinkColorWhich)
84502be5353SAxel Dörfler{
84602be5353SAxel Dörfler	// Set view color to standard background grey
847c5b4dc40Slooncraz	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
848c5b4dc40Slooncraz	SetFont(be_plain_font);
84902be5353SAxel Dörfler	// If the model is a symlink, then we deference the model to
85002be5353SAxel Dörfler	// get the targets icon
85102be5353SAxel Dörfler	if (fModel->IsSymLink()) {
852b05aa8b5SJohn Scipione		Model* resolvedModel = new Model(model->EntryRef(), true, true);
85302be5353SAxel Dörfler		if (resolvedModel->InitCheck() == B_OK)
85402be5353SAxel Dörfler			fIconModel = resolvedModel;
85502be5353SAxel Dörfler		// broken link, just show the symlink
856aa11dcaeSPhilippe Saint-Pierre		else
857aa11dcaeSPhilippe Saint-Pierre			delete resolvedModel;
85802be5353SAxel Dörfler	}
85902be5353SAxel Dörfler
86002be5353SAxel Dörfler	// Create the rect for displaying the icon
86102be5353SAxel Dörfler	fIconRect.Set(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1);
86202be5353SAxel Dörfler	// Offset taken from BAlert
86302be5353SAxel Dörfler	fIconRect.OffsetBy(kIconHorizOffset, kIconVertOffset);
86402be5353SAxel Dörfler
86502be5353SAxel Dörfler	// The title rect
86602be5353SAxel Dörfler	// The magic numbers are used to properly calculate the rect so that
86702be5353SAxel Dörfler	// when the editing text view is displayed, the position of the text
868c716766bSKarsten Heimrich	// does not change.
86902be5353SAxel Dörfler	BFont currentFont;
87002be5353SAxel Dörfler	font_height fontMetrics;
87102be5353SAxel Dörfler	GetFont(&currentFont);
87202be5353SAxel Dörfler	currentFont.GetHeight(&fontMetrics);
87302be5353SAxel Dörfler
87402be5353SAxel Dörfler	fTitleRect.left = fIconRect.right + 5;
87502be5353SAxel Dörfler	fTitleRect.top = 0;
87602be5353SAxel Dörfler	fTitleRect.bottom = fontMetrics.ascent + 1;
877a51764c5SJohn Scipione	fTitleRect.right = min_c(
878a51764c5SJohn Scipione		fTitleRect.left + currentFont.StringWidth(fModel->Name()),
879a51764c5SJohn Scipione		Bounds().Width() - 5);
88002be5353SAxel Dörfler	// Offset so that it centers with the icon
881a51764c5SJohn Scipione	fTitleRect.OffsetBy(0,
882a51764c5SJohn Scipione		fIconRect.top + ((fIconRect.Height() - fTitleRect.Height()) / 2));
88302be5353SAxel Dörfler	// Make some room for the border for when we are in edit mode
88402be5353SAxel Dörfler	// (Negative numbers increase the size of the rect)
88502be5353SAxel Dörfler	fTitleRect.InsetBy(-1, -2);
88602be5353SAxel Dörfler
88702be5353SAxel Dörfler	fFreeBytes = -1;
888ff43bcbfSJohn Scipione	fSizeString = "";
88902be5353SAxel Dörfler	fSizeRect.Set(0, 0, 0, 0);
8900cf86704SAxel Dörfler
89102be5353SAxel Dörfler	// Find offset for attributes, might be overiden below if there
89202be5353SAxel Dörfler	// is a prefered handle menu displayed
893c5b4dc40Slooncraz	currentFont.SetSize(currentFont.Size() - 2);
894c5b4dc40Slooncraz	fDivider = currentFont.StringWidth(B_TRANSLATE("Description:"))
8954ed28a57SAlexandre Deckner		+ kBorderMargin + kBorderWidth + 1;
89602be5353SAxel Dörfler	// Add a preferred handler pop-up menu if this item
89702be5353SAxel Dörfler	// is a file...This goes in place of the Link To:
89802be5353SAxel Dörfler	// string...
89902be5353SAxel Dörfler	if (model->IsFile()) {
90002be5353SAxel Dörfler		BMimeType mime(fModel->MimeType());
90102be5353SAxel Dörfler		BNodeInfo nodeInfo(fModel->Node());
9020cf86704SAxel Dörfler
90302be5353SAxel Dörfler		// But don't add the menu if the file is executable
90402be5353SAxel Dörfler		if (!fModel->IsExecutable()) {
90502be5353SAxel Dörfler			float lineHeight = CurrentFontHeight();
9060cf86704SAxel Dörfler
90702be5353SAxel Dörfler			BRect preferredAppRect(kBorderWidth + kBorderMargin,
90802be5353SAxel Dörfler				fTitleRect.bottom + (lineHeight * 7),
90902be5353SAxel Dörfler				Bounds().Width() - 5, fTitleRect.bottom + (lineHeight * 8));
910a51764c5SJohn Scipione			fPreferredAppMenu = new BMenuField(preferredAppRect, "", "",
911a51764c5SJohn Scipione				new BPopUpMenu(""));
912d54cb434SHumdinger			currentFont.SetSize(currentFont.Size() + 2);
913a51764c5SJohn Scipione			fDivider = currentFont.StringWidth(B_TRANSLATE("Opens with:"))
914a51764c5SJohn Scipione				+ 5;
91502be5353SAxel Dörfler			fPreferredAppMenu->SetDivider(fDivider);
91602be5353SAxel Dörfler			fDivider += (preferredAppRect.left - 2);
91702be5353SAxel Dörfler			fPreferredAppMenu->SetFont(&currentFont);
918c5b4dc40Slooncraz			fPreferredAppMenu->SetHighUIColor(B_PANEL_TEXT_COLOR);
9194ed28a57SAlexandre Deckner			fPreferredAppMenu->SetLabel(B_TRANSLATE("Opens with:"));
9200cf86704SAxel Dörfler
92102be5353SAxel Dörfler			char prefSignature[B_MIME_TYPE_LENGTH];
92202be5353SAxel Dörfler			nodeInfo.GetPreferredApp(prefSignature);
9230cf86704SAxel Dörfler
92402be5353SAxel Dörfler			BMessage supportingAppList;
92502be5353SAxel Dörfler			mime.GetSupportingApps(&supportingAppList);
92602be5353SAxel Dörfler
92702be5353SAxel Dörfler			// Add the default menu item and set it to marked
928b05aa8b5SJohn Scipione			BMenuItem* result;
9294ed28a57SAlexandre Deckner			result = new BMenuItem(B_TRANSLATE("Default application"),
9304ed28a57SAlexandre Deckner				new BMessage(kSetPreferredApp));
93102be5353SAxel Dörfler			result->SetTarget(this);
93202be5353SAxel Dörfler			fPreferredAppMenu->Menu()->AddItem(result);
93302be5353SAxel Dörfler			result->SetMarked(true);
9340cf86704SAxel Dörfler
93502be5353SAxel Dörfler			for (int32 index = 0; ; index++) {
936b05aa8b5SJohn Scipione				const char* signature;
937a51764c5SJohn Scipione				if (supportingAppList.FindString("applications", index,
938a51764c5SJohn Scipione						&signature) != B_OK) {
93902be5353SAxel Dörfler					break;
940a51764c5SJohn Scipione				}
9410cf86704SAxel Dörfler
94202be5353SAxel Dörfler				// Only add separator item if there are more items
943