xref: /haiku/src/kits/tracker/TemplatesMenu.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 
36 #include <Application.h>
37 #include <Catalog.h>
38 #include <Directory.h>
39 #include <FindDirectory.h>
40 #include <Locale.h>
41 #include <MenuItem.h>
42 #include <Message.h>
43 #include <Mime.h>
44 #include <NodeInfo.h>
45 #include <Path.h>
46 #include <Query.h>
47 #include <Roster.h>
48 #include <String.h>
49 
50 #include <kernel/fs_attr.h>
51 
52 #include "Attributes.h"
53 #include "Commands.h"
54 
55 #include "IconMenuItem.h"
56 #include "MimeTypes.h"
57 #include "TemplatesMenu.h"
58 
59 #undef B_TRANSLATION_CONTEXT
60 #define B_TRANSLATION_CONTEXT "TemplatesMenu"
61 
62 
63 namespace BPrivate {
64 
65 const char* kTemplatesDirectory = "Tracker/Tracker New Templates";
66 
67 } // namespace BPrivate
68 
69 
70 //	#pragma mark - TemplatesMenu
71 
72 
73 TemplatesMenu::TemplatesMenu(const BMessenger& target, const char* label)
74 	:
75 	BMenu(label),
76 	fTarget(target),
77 	fOpenItem(NULL),
78 	fTemplateCount(0)
79 {
80 }
81 
82 
83 TemplatesMenu::~TemplatesMenu()
84 {
85 }
86 
87 
88 void
89 TemplatesMenu::AttachedToWindow()
90 {
91 	BuildMenu();
92 	BMenu::AttachedToWindow();
93 	SetTargetForItems(fTarget);
94 }
95 
96 
97 status_t
98 TemplatesMenu::SetTargetForItems(BHandler* target)
99 {
100 	status_t result = BMenu::SetTargetForItems(target);
101 	if (result != B_OK)
102 		return result;
103 
104 	for (int i = 0; i < CountItems(); i++) {
105 		BMenu* submenu = ItemAt(i)->Submenu();
106 		if (submenu != NULL) {
107 			result = SetTargetForSubmenuItems(submenu, target);
108 			if (result != B_OK)
109 				return result;
110 		}
111 	}
112 
113 	if (fOpenItem)
114 		fOpenItem->SetTarget(be_app_messenger);
115 
116 	return result;
117 }
118 
119 
120 status_t
121 TemplatesMenu::SetTargetForItems(BMessenger messenger)
122 {
123 	status_t result = BMenu::SetTargetForItems(messenger);
124 	if (result != B_OK)
125 		return result;
126 
127 	for (int i = 0; i < CountItems(); i++) {
128 		BMenu* submenu = ItemAt(i)->Submenu();
129 		if (submenu != NULL) {
130 			result = SetTargetForSubmenuItems(submenu, messenger);
131 			if (result != B_OK)
132 				return result;
133 		}
134 	}
135 
136 	if (fOpenItem)
137 		fOpenItem->SetTarget(be_app_messenger);
138 
139 	return result;
140 }
141 
142 
143 bool
144 TemplatesMenu::BuildMenu(bool addItems)
145 {
146 	// clear everything...
147 	fOpenItem = NULL;
148 	fTemplateCount = CountItems();
149 	while (fTemplateCount--)
150 		delete RemoveItem((int32)0);
151 
152 	// add the folder
153 	IconMenuItem* menuItem = new IconMenuItem(B_TRANSLATE("New folder"),
154 		new BMessage(kNewFolder), B_DIR_MIMETYPE, B_MINI_ICON);
155 	AddItem(menuItem);
156 	menuItem->SetShortcut('N', 0);
157 	AddSeparatorItem();
158 
159 	// the templates folder
160 	BPath path;
161 	find_directory (B_USER_SETTINGS_DIRECTORY, &path, true);
162 	path.Append(kTemplatesDirectory);
163 	mkdir(path.Path(), 0777);
164 
165 	fTemplateCount = 0;
166 	fTemplateCount += IterateTemplateDirectory(addItems, &path, this);
167 
168 	// this is the message sent to open the templates folder
169 	BDirectory templatesDir(path.Path());
170 	BMessage* message = new BMessage(B_REFS_RECEIVED);
171 	BEntry entry;
172 	entry_ref dirRef;
173 	if (templatesDir.GetEntry(&entry) == B_OK)
174 		entry.GetRef(&dirRef);
175 
176 	message->AddRef("refs", &dirRef);
177 
178 	// add item to show templates folder
179 	fOpenItem = new BMenuItem(B_TRANSLATE("Edit templates" B_UTF8_ELLIPSIS), message);
180 	AddItem(fOpenItem);
181 
182 	if (dirRef == entry_ref())
183 		fOpenItem->SetEnabled(false);
184 
185 	return fTemplateCount > 0;
186 }
187 
188 
189 BMenuItem*
190 TemplatesMenu::NewSubmenuItem(BPath subdirPath)
191 {
192 	// add item to create new submenu folder
193 	BDirectory templatesDir(subdirPath.Path());
194 	BEntry entry;
195 	entry_ref dirRef;
196 	if (templatesDir.GetEntry(&entry) == B_OK)
197 		entry.GetRef(&dirRef);
198 	BMessage* message = new BMessage(kNewTemplateSubmenu);
199 	message->AddRef("refs", &dirRef);
200 	BMenuItem* submenuItem = new BMenuItem(B_TRANSLATE("Add new submenu" B_UTF8_ELLIPSIS), message);
201 
202 	if (dirRef == entry_ref())
203 		submenuItem->SetEnabled(false);
204 
205 	return submenuItem;
206 }
207 
208 
209 void
210 TemplatesMenu::UpdateMenuState()
211 {
212 	BuildMenu(false);
213 }
214 
215 
216 int
217 TemplatesMenu::IterateTemplateDirectory(bool addItems, BPath* path, BMenu* menu)
218 {
219 	fTemplateCount = 0;
220 	if (path == NULL || menu == NULL)
221 		return fTemplateCount;
222 
223 	BEntry entry;
224 	BList subMenus;
225 	BList subDirs;
226 	BList files;
227 	BDirectory templatesDir(path->Path());
228 	while (templatesDir.GetNextEntry(&entry) == B_OK) {
229 		BNode node(&entry);
230 		BNodeInfo nodeInfo(&node);
231 		char fileName[B_FILE_NAME_LENGTH];
232 		entry.GetName(fileName);
233 		if (nodeInfo.InitCheck() == B_OK) {
234 			char mimeType[B_MIME_TYPE_LENGTH];
235 			nodeInfo.GetType(mimeType);
236 
237 			BMimeType mime(mimeType);
238 			if (mime.IsValid()) {
239 				fTemplateCount++;
240 
241 				// We are just seeing if there are any items to add to the list.
242 				// Immediately bail and return the result.
243 				if (!addItems)
244 					return fTemplateCount;
245 
246 				entry_ref ref;
247 				entry.GetRef(&ref);
248 
249 				// Check if the template is a directory
250 				BDirectory dir(&entry);
251 				if (dir.InitCheck() == B_OK) {
252 					// check if the directory is a submenu, aka has kAttrTemplateSubMenu
253 					// (_trk/_template_submenu) attribute
254 					attr_info attrInfo;
255 					if (node.GetAttrInfo(kAttrTemplateSubMenu, &attrInfo) == B_OK) {
256 						ssize_t size;
257 						bool value;
258 						size = node.ReadAttr(kAttrTemplateSubMenu, B_BOOL_TYPE, 0, &value,
259 							sizeof(bool));
260 						if (size == sizeof(bool) && value == true) {
261 							// if submenu add it to subMenus list and iterate contents
262 							BPath subdirPath;
263 							if (entry.GetPath(&subdirPath) == B_OK) {
264 								BMenu* subMenu = new BMenu(fileName);
265 								fTemplateCount
266 									+= IterateTemplateDirectory(addItems, &subdirPath, subMenu);
267 								subMenus.AddItem((void*)subMenu);
268 								continue;
269 							}
270 							continue;
271 						}
272 					} else {
273 						// Otherwise add it to subDirs list
274 						BMessage* message = new BMessage(kNewEntryFromTemplate);
275 						message->AddRef("refs_template", &ref);
276 						message->AddString("name", fileName);
277 						subDirs.AddItem(new IconMenuItem(fileName, message, &nodeInfo,
278 							B_MINI_ICON));
279 						continue;
280 					}
281 				}
282 
283 				// Add template files to files list
284 				BMessage* message = new BMessage(kNewEntryFromTemplate);
285 				message->AddRef("refs_template", &ref);
286 				message->AddString("name", fileName);
287 				files.AddItem(new IconMenuItem(fileName, message, &nodeInfo, B_MINI_ICON));
288 			}
289 		}
290 	}
291 
292 	// Add submenus to menu
293 	int32 itemCount = subMenus.CountItems();
294 	for (int32 i = 0; i < itemCount; i++)
295 		menu->AddItem((BMenu*)subMenus.ItemAt(i));
296 
297 	if (itemCount > 0)
298 		menu->AddSeparatorItem();
299 
300 	// Add subdirs to menu
301 	itemCount = subDirs.CountItems();
302 	for (int32 i = 0; i < itemCount; i++)
303 		menu->AddItem((BMenuItem*)subDirs.ItemAt(i));
304 
305 	if (itemCount > 0)
306 		menu->AddSeparatorItem();
307 
308 	// Add files to menu
309 	itemCount = files.CountItems();
310 	for (int32 i = 0; i < itemCount; i++)
311 		menu->AddItem((BMenuItem*)files.ItemAt(i));
312 
313 	if (itemCount > 0)
314 		menu->AddSeparatorItem();
315 
316 	menu->AddItem(NewSubmenuItem(*path));
317 
318 	return fTemplateCount > 0;
319 }
320 
321 
322 status_t
323 TemplatesMenu::SetTargetForSubmenuItems(BMenu* menu, BMessenger messenger)
324 {
325 	if (!menu)
326 		return B_ERROR;
327 
328 	status_t result;
329 
330 	result = menu->SetTargetForItems(messenger);
331 	if (result != B_OK)
332 		return result;
333 
334 	for (int i = 0; i < menu->CountItems(); i++) {
335 		BMenu* submenu = menu->ItemAt(i)->Submenu();
336 		if (submenu != NULL) {
337 			result = SetTargetForSubmenuItems(submenu, messenger);
338 			if (result != B_OK)
339 				return result;
340 		}
341 	}
342 	return result;
343 }
344 
345 
346 status_t
347 TemplatesMenu::SetTargetForSubmenuItems(BMenu* menu, BHandler* target)
348 {
349 	if (!menu || !target)
350 		return B_ERROR;
351 
352 	status_t result;
353 
354 	result = menu->SetTargetForItems(target);
355 	if (result != B_OK)
356 		return result;
357 
358 	for (int i = 0; i < menu->CountItems(); i++) {
359 		BMenu* submenu = menu->ItemAt(i)->Submenu();
360 		if (submenu != NULL) {
361 			result = SetTargetForSubmenuItems(submenu, target);
362 			if (result != B_OK)
363 				return result;
364 		}
365 	}
366 	return result;
367 }
368