1/*
2 * Copyright (C) 2010 Stephan A��mus <superstippi@gmx.de>
3 * Copyright (C) 2010 Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
4 *
5 * Distributed under the terms of the MIT licence.
6 */
7
8#include "ApplicationView.h"
9
10#include <stdio.h>
11
12#include <Alert.h>
13#include <Bitmap.h>
14#include <Button.h>
15#include <Clipboard.h>
16#include <Directory.h>
17#include <Entry.h>
18#include <FindDirectory.h>
19#include <GroupLayoutBuilder.h>
20#include <MenuItem.h>
21#include <NodeInfo.h>
22#include <NodeMonitor.h>
23#include <PopUpMenu.h>
24#include <Roster.h>
25#include <SpaceLayoutItem.h>
26#include <StatusBar.h>
27#include <StringView.h>
28
29
30class IconView : public BView {
31public:
32	IconView(const BEntry& entry)
33		:
34		BView("Download icon", B_WILL_DRAW),
35		fIconBitmap(BRect(0, 0, 31, 31), 0, B_RGBA32),
36		fDimmedIcon(false)
37	{
38		SetDrawingMode(B_OP_OVER);
39		SetTo(entry);
40	}
41
42	IconView()
43		:
44		BView("Download icon", B_WILL_DRAW),
45		fIconBitmap(BRect(0, 0, 31, 31), 0, B_RGBA32),
46		fDimmedIcon(false)
47	{
48		SetDrawingMode(B_OP_OVER);
49		memset(fIconBitmap.Bits(), 0, fIconBitmap.BitsLength());
50	}
51
52	IconView(const BMessage* archive)
53		:
54		BView("Download icon", B_WILL_DRAW),
55		fIconBitmap((BMessage*)archive),
56		fDimmedIcon(true)
57	{
58		SetDrawingMode(B_OP_OVER);
59	}
60
61	void SetTo(const BEntry& entry)
62	{
63		BNode node(&entry);
64		BNodeInfo info(&node);
65		info.GetTrackerIcon(&fIconBitmap, B_LARGE_ICON);
66		Invalidate();
67	}
68
69	void SetIconDimmed(bool iconDimmed)
70	{
71		if (fDimmedIcon != iconDimmed) {
72			fDimmedIcon = iconDimmed;
73			Invalidate();
74		}
75	}
76
77	bool IsIconDimmed() const
78	{
79		return fDimmedIcon;
80	}
81
82	status_t SaveSettings(BMessage* archive)
83	{
84		return fIconBitmap.Archive(archive);
85	}
86
87	virtual void AttachedToWindow()
88	{
89		SetViewColor(Parent()->ViewColor());
90	}
91
92	virtual void Draw(BRect updateRect)
93	{
94		if (fDimmedIcon) {
95			SetDrawingMode(B_OP_ALPHA);
96			SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
97			SetHighColor(0, 0, 0, 100);
98		}
99		DrawBitmapAsync(&fIconBitmap);
100	}
101
102	virtual BSize MinSize()
103	{
104		return BSize(fIconBitmap.Bounds().Width(), fIconBitmap.Bounds().Height());
105	}
106
107	virtual BSize PreferredSize()
108	{
109		return MinSize();
110	}
111
112	virtual BSize MaxSize()
113	{
114		return MinSize();
115	}
116
117private:
118	BBitmap	fIconBitmap;
119	bool	fDimmedIcon;
120};
121
122
123class SmallButton : public BButton {
124public:
125	SmallButton(const char* label, BMessage* message = NULL)
126		:
127		BButton(label, message)
128	{
129		BFont font;
130		GetFont(&font);
131		float size = ceilf(font.Size() * 0.8);
132		font.SetSize(max_c(8, size));
133		SetFont(&font, B_FONT_SIZE);
134	}
135};
136
137
138// #pragma mark - ApplicationView
139
140
141ApplicationView::ApplicationView(const char* name, const char* icon,
142		const char* description)
143	:
144	BGroupView(B_HORIZONTAL, 8)
145{
146	Init(NULL);
147
148	fNameView->SetText(name);
149	fInfoView->SetText(description);
150}
151
152
153ApplicationView::ApplicationView(const BMessage* archive)
154	:
155	BGroupView(B_HORIZONTAL, 8)
156{
157	Init(archive);
158	BString temp;
159	archive->FindString("appname",&temp);
160	fNameView->SetText(temp);
161	archive->FindString("appdesc",&temp);
162	float ver = 0.0;
163	archive->FindFloat("appver", ver);
164	int size = 0;
165	archive->FindInt32("appsize", size);
166	temp << " Version: " << ver << " Size: " << size;
167	fInfoView->SetText(temp);
168}
169
170
171bool
172ApplicationView::Init(const BMessage* archive)
173{
174	SetViewColor(245, 245, 245);
175	SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE | B_WILL_DRAW);
176
177	if (archive) {
178			fIconView = new IconView(archive);
179	} else
180		fIconView = new IconView();
181
182	if (archive) {
183		fTopButton = new SmallButton("Info", new BMessage('NADA'));
184		fBottomButton = new SmallButton("Install", new BMessage('NADA'));
185	}
186
187	fInfoView = new BStringView("info view", "");
188	fNameView = new BStringView("name view", "");
189
190	BGroupLayout* layout = GroupLayout();
191	layout->SetInsets(8, 5, 5, 6);
192	layout->AddView(fIconView);
193	BView* verticalGroup = BGroupLayoutBuilder(B_VERTICAL, 3)
194		.Add(fNameView)
195		.Add(fInfoView)
196		.TopView()
197	;
198	verticalGroup->SetViewColor(ViewColor());
199	layout->AddView(verticalGroup);
200	if (fTopButton && fBottomButton) {
201		verticalGroup = BGroupLayoutBuilder(B_VERTICAL, 3)
202			.Add(fTopButton)
203			.Add(fBottomButton)
204			.TopView()
205		;
206	}
207	verticalGroup->SetViewColor(ViewColor());
208	layout->AddView(verticalGroup);
209
210	BFont font;
211	fInfoView->GetFont(&font);
212	float fontSize = font.Size() * 0.8f;
213	font.SetSize(max_c(8.0f, fontSize));
214	fInfoView->SetFont(&font, B_FONT_SIZE);
215	fInfoView->SetHighColor(tint_color(fInfoView->LowColor(),
216		B_DARKEN_4_TINT));
217	fInfoView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
218
219	fNameView->GetFont(&font);
220	font.SetSize(font.Size() * 2.0f);
221	fNameView->SetFont(&font, B_FONT_SIZE);
222	fNameView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
223
224	return true;
225}
226
227
228void
229ApplicationView::AttachedToWindow()
230{
231	if (fTopButton)
232		fTopButton->SetTarget(this);
233	if (fBottomButton)
234		fBottomButton->SetTarget(this);
235}
236
237
238void
239ApplicationView::AllAttached()
240{
241	SetViewColor(B_TRANSPARENT_COLOR);
242	SetLowColor(245, 245, 245);
243	SetHighColor(tint_color(LowColor(), B_DARKEN_1_TINT));
244}
245
246
247void
248ApplicationView::Draw(BRect updateRect)
249{
250	BRect bounds(Bounds());
251	bounds.bottom--;
252	FillRect(bounds, B_SOLID_LOW);
253	bounds.bottom++;
254	StrokeLine(bounds.LeftBottom(), bounds.RightBottom());
255}
256
257
258void
259ApplicationView::MessageReceived(BMessage* message)
260{
261	switch (message->what) {
262		case B_NODE_MONITOR:
263		{
264			int32 opCode;
265			if (message->FindInt32("opcode", &opCode) != B_OK)
266				break;
267			switch (opCode) {
268				case B_ENTRY_MOVED:
269				{
270					// Follow the entry to the new location
271					dev_t device;
272					ino_t directory;
273					const char* name;
274					if (message->FindInt32("device",
275							reinterpret_cast<int32*>(&device)) != B_OK
276						|| message->FindInt64("to directory",
277							reinterpret_cast<int64*>(&directory)) != B_OK
278						|| message->FindString("name", &name) != B_OK
279						|| strlen(name) == 0) {
280						break;
281					}
282
283					Window()->PostMessage(SAVE_SETTINGS);
284					break;
285				}
286				case B_ATTR_CHANGED:
287				{
288					fIconView->SetIconDimmed(false);
289					break;
290				}
291			}
292			break;
293		}
294
295		default:
296			BGroupView::MessageReceived(message);
297	}
298}
299
300
301void
302ApplicationView::ShowContextMenu(BPoint screenWhere)
303{
304	screenWhere += BPoint(2, 2);
305
306	BPopUpMenu* contextMenu = new BPopUpMenu("download context");
307	BMenuItem* copyURL = new BMenuItem("Copy URL to clipboard",
308		new BMessage('NADA'));
309	contextMenu->AddItem(copyURL);
310	BMenuItem* openFolder = new BMenuItem("Open containing folder",
311		new BMessage('NADA'));
312	contextMenu->AddItem(openFolder);
313
314	contextMenu->SetTargetForItems(this);
315	contextMenu->Go(screenWhere, true, true, true);
316}
317
318