xref: /haiku/src/apps/cortex/DormantNodeView/DormantNodeView.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 /*
2  * Copyright (c) 1999-2000, Eric Moon.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions, and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions, and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 // DormantNodeView.cpp
33 
34 #include "DormantNodeView.h"
35 // DormantNodeView
36 #include "DormantNodeWindow.h"
37 #include "DormantNodeListItem.h"
38 // InfoWindow
39 #include "InfoWindowManager.h"
40 
41 // Interface Kit
42 #include <Deskbar.h>
43 #include <Region.h>
44 #include <Screen.h>
45 #include <ScrollBar.h>
46 // Media Kit
47 #include <MediaRoster.h>
48 // Storage Kit
49 #include <Mime.h>
50 
51 __USE_CORTEX_NAMESPACE
52 
53 #include <Debug.h>
54 #define D_ALLOC(x) //PRINT (x)		// ctor/dtor
55 #define D_HOOK(x) //PRINT (x)		// BListView impl.
56 #define D_MESSAGE(x) //PRINT (x)	// MessageReceived()
57 #define D_INTERNAL(x) //PRINT (x)	// internal operations
58 
59 // -------------------------------------------------------- //
60 // ctor/dtor (public)
61 // -------------------------------------------------------- //
62 
63 DormantNodeView::DormantNodeView(
64 	BRect frame,
65 	const char *name,
66 	uint32 resizeMode)
67 	: BListView(frame, name, B_SINGLE_SELECTION_LIST, resizeMode),
68 	  m_lastItemUnder(0) {
69 	D_ALLOC(("DormantNodeView::DormantNodeView()\n"));
70 
71 }
72 
73 DormantNodeView::~DormantNodeView() {
74 	D_ALLOC(("DormantNodeView::~DormantNodeView()\n"));
75 
76 }
77 
78 // -------------------------------------------------------- //
79 // BListView impl. (public)
80 // -------------------------------------------------------- //
81 
82 void DormantNodeView::AttachedToWindow() {
83 	D_HOOK(("DormantNodeView::AttachedToWindow()\n"));
84 
85 	// populate the list
86 	_populateList();
87 
88 	// Start watching the MediaRoster for flavor changes
89 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
90 	if (roster) {
91 		BMessenger messenger(this, Window());
92 		roster->StartWatching(messenger, B_MEDIA_FLAVORS_CHANGED);
93 	}
94 }
95 
96 void DormantNodeView::DetachedFromWindow() {
97 	D_HOOK(("DormantNodeView::DetachedFromWindow()\n"));
98 
99 	// delete the lists contents
100 	_freeList();
101 
102 	// Stop watching the MediaRoster for flavor changes
103 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
104 	if (roster) {
105 		BMessenger messenger(this, Window());
106 		roster->StopWatching(messenger, B_MEDIA_FLAVORS_CHANGED);
107 	}
108 }
109 
110 void DormantNodeView::GetPreferredSize(
111 	float* width,
112 	float* height) {
113 	D_HOOK(("DormantNodeView::GetPreferredSize()\n"));
114 
115 	// calculate the accumulated size of all list items
116 	*width = 0;
117 	*height = 0;
118 	for (int32 i = 0; i < CountItems(); i++) {
119 		DormantNodeListItem *item;
120 		item = dynamic_cast<DormantNodeListItem *>(ItemAt(i));
121 		if (item) {
122 			BRect r = item->getRealFrame(be_plain_font);
123 			if (r.Width() > *width) {
124 				*width = r.Width();
125 			}
126 			*height += r.Height() + 1.0;
127 		}
128 	}
129 }
130 
131 void DormantNodeView::MessageReceived(
132 	BMessage *message) {
133 	D_MESSAGE(("DormantNodeView::MessageReceived()\n"));
134 
135 	switch (message->what) {
136 		case B_MEDIA_FLAVORS_CHANGED: {
137 			D_MESSAGE((" -> B_MEDIA_FLAVORS_CHANGED\n"));
138 
139 			// init & re-populate the list
140 			int32 addOnID = 0;
141 			if (message->FindInt32("be:addon_id", &addOnID) != B_OK) {
142 				D_MESSAGE((" -> messages doesn't contain 'be:addon_id'!\n"));
143 				return;
144 			}
145 			_updateList(addOnID);
146 			break;
147 		}
148 		case InfoWindowManager::M_INFO_WINDOW_REQUESTED: {
149 			D_MESSAGE((" -> InfoWindowManager::M_INFO_WINDOW_REQUESTED)\n"));
150 
151 			DormantNodeListItem *item;
152 			item = dynamic_cast<DormantNodeListItem *>(ItemAt(CurrentSelection()));
153 			if (item) {
154 				InfoWindowManager *manager = InfoWindowManager::Instance();
155 				if (manager && manager->Lock()) {
156 					manager->openWindowFor(item->info());
157 					manager->Unlock();
158 				}
159 			}
160 			break;
161 		}
162 		default: {
163 			_inherited::MessageReceived(message);
164 		}
165 	}
166 }
167 
168 void DormantNodeView::MouseDown(
169 	BPoint point) {
170 	D_HOOK(("DormantNodeView::MouseDown()\n"));
171 
172 	BMessage* message = Window()->CurrentMessage();
173 	int32 buttons = message->FindInt32("buttons");
174 	if (buttons == B_SECONDARY_MOUSE_BUTTON) {
175 		int32 index;
176 		if ((index = IndexOf(point)) >= 0) {
177 			DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(index));
178 			if (item) {
179 				Select(index);
180 				BRect r = item->getRealFrame(be_plain_font);
181 				if (r.Contains(point)) {
182 					item->showContextMenu(point, this);
183 				}
184 			}
185 		}
186 	}
187 
188 	_inherited::MouseDown(point);
189 }
190 
191 void DormantNodeView::MouseMoved(
192 	BPoint point,
193 	uint32 transit,
194 	const BMessage *message) {
195 	D_HOOK(("DormantNodeView::MouseMoved()\n"));
196 
197 	int32 index;
198 	if (!message && ((index = IndexOf(point)) >= 0)) {
199 		DormantNodeListItem *item =
200 			dynamic_cast<DormantNodeListItem *>(ItemAt(index));
201 		DormantNodeListItem *last =
202 			dynamic_cast<DormantNodeListItem *>(m_lastItemUnder);
203 		if (item != NULL) {
204 			BRect r = item->getRealFrame(be_plain_font);
205 			if (r.Contains(point)) {
206 				if (item != last) {
207 					if (last != NULL)
208 						last->MouseOver(this, point, B_EXITED_VIEW);
209 					item->MouseOver(this, point, B_ENTERED_VIEW);
210 					m_lastItemUnder = item;
211 				}
212 				else {
213 					item->MouseOver(this, point, B_INSIDE_VIEW);
214 				}
215 			}
216 		}
217 		else if (last != NULL) {
218 			last->MouseOver(this, point, B_EXITED_VIEW);
219 		}
220 	}
221 
222 	_inherited::MouseMoved(point, transit, message);
223 }
224 
225 bool DormantNodeView::InitiateDrag(
226 	BPoint point,
227 	int32 index,
228 	bool wasSelected) {
229 	D_HOOK(("DormantNodeView::InitiateDrag()\n"));
230 
231 	DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(CurrentSelection()));
232 	if (item) {
233 		BMessage dragMsg(M_INSTANTIATE_NODE);
234 		dragMsg.AddData("which", B_RAW_TYPE,
235 						reinterpret_cast<const void *>(&item->info()),
236 						sizeof(item->info()));
237 		point -= ItemFrame(index).LeftTop();
238 		DragMessage(&dragMsg, item->getDragBitmap(), B_OP_ALPHA, point);
239 		return true;
240 	}
241 	return false;
242 }
243 
244 // -------------------------------------------------------- //
245 // internal operations (private)
246 // -------------------------------------------------------- //
247 
248 void DormantNodeView::_populateList() {
249 	D_INTERNAL(("DormantNodeView::_populateList()\n"));
250 
251 	// init the resizable node-info buffer
252 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
253 	const int32 bufferInc = 64;
254 	int32 bufferSize = bufferInc;
255 	dormant_node_info *infoBuffer = new dormant_node_info[bufferSize];
256 	int32 numNodes;
257 
258 	// fill the buffer
259 	while (true) {
260 		numNodes = bufferSize;
261 		status_t error = roster->GetDormantNodes(infoBuffer, &numNodes);
262 		if (error) {
263 			return;
264 		}
265 		if (numNodes < bufferSize) {
266 			break;
267 		}
268 
269 		// reallocate buffer & try again
270 		delete [] infoBuffer;
271 		bufferSize += bufferInc;
272 		infoBuffer = new dormant_node_info[bufferSize];
273 	}
274 
275 	// populate the list
276 	for (int32 i = 0; i < numNodes; i++) {
277 		DormantNodeListItem *item = new DormantNodeListItem(infoBuffer[i]);
278 		AddItem(item);
279 	}
280 	SortItems(compareName);
281 }
282 
283 void DormantNodeView::_freeList() {
284 	D_HOOK(("DormantNodeView::_freeList()\n"));
285 
286 	// remove and delete all items in the list
287 	while (CountItems() > 0) {
288 		BListItem *item = ItemAt(0);
289 		if (RemoveItem(item)) {
290 			delete item;
291 		}
292 	}
293 }
294 
295 void DormantNodeView::_updateList(
296 	int32 addOnID) {
297 	D_INTERNAL(("DormantNodeView::_updateList(%ld)\n", addOnID));
298 
299 	// init the resizable node-info buffer
300 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
301 	const int32 bufferInc = 64;
302 	int32 bufferSize = bufferInc;
303 	dormant_node_info *infoBuffer = new dormant_node_info[bufferSize];
304 	int32 numNodes;
305 
306 	// fill the buffer
307 	while (true) {
308 		numNodes = bufferSize;
309 		status_t error = roster->GetDormantNodes(infoBuffer, &numNodes);
310 		if (error) {
311 			return;
312 		}
313 		if (numNodes < bufferSize) {
314 			break;
315 		}
316 
317 		// reallocate buffer & try again
318 		delete [] infoBuffer;
319 		bufferSize += bufferInc;
320 		infoBuffer = new dormant_node_info[bufferSize];
321 	}
322 
323 	// sort the list by add-on id to avoid multiple searches through
324 	// the list
325 	SortItems(compareAddOnID);
326 
327 	// Remove all nodes managed by this add-on
328 	int32 start;
329 	for (start = 0; start < CountItems(); start++) {
330 		DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(start));
331 		if (item && (item->info().addon == addOnID)) {
332 			break;
333 		}
334 	}
335 	int32 count = 0;
336 	for (int32 i = start; start < CountItems(); i++) {
337 		DormantNodeListItem *item = dynamic_cast<DormantNodeListItem *>(ItemAt(i));
338 		if (!item || (item->info().addon != addOnID)) {
339 			break;
340 		}
341 		count++;
342 	}
343 	RemoveItems(start, count);
344 
345 	// add the items
346 	for (int32 i = 0; i < numNodes; i++) {
347 		if (infoBuffer[i].addon != addOnID) {
348 			continue;
349 		}
350 		AddItem(new DormantNodeListItem(infoBuffer[i]));
351 	}
352 
353 	SortItems(compareName);
354 }
355 
356 // END -- DormantNodeView.cpp --
357