xref: /haiku/src/kits/tracker/TemplatesMenu.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
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 {
79 }
80 
81 
82 TemplatesMenu::~TemplatesMenu()
83 {
84 }
85 
86 
87 void
88 TemplatesMenu::AttachedToWindow()
89 {
90 	BuildMenu();
91 	BMenu::AttachedToWindow();
92 	SetTargetForItems(fTarget);
93 }
94 
95 
96 status_t
97 TemplatesMenu::SetTargetForItems(BHandler* target)
98 {
99 	status_t result = BMenu::SetTargetForItems(target);
100 	if (result != B_OK)
101 		return result;
102 
103 	for (int i = 0; i < CountItems(); i++) {
104 		BMenu* submenu = ItemAt(i)->Submenu();
105 		if (submenu != NULL) {
106 			result = SetTargetForSubmenuItems(submenu, target);
107 			if (result != B_OK)
108 				return result;
109 		}
110 	}
111 
112 	if (fOpenItem)
113 		fOpenItem->SetTarget(be_app_messenger);
114 
115 	return result;
116 }
117 
118 
119 status_t
120 TemplatesMenu::SetTargetForItems(BMessenger messenger)
121 {
122 	status_t result = BMenu::SetTargetForItems(messenger);
123 	if (result != B_OK)
124 		return result;
125 
126 	for (int i = 0; i < CountItems(); i++) {
127 		BMenu* submenu = ItemAt(i)->Submenu();
128 		if (submenu != NULL) {
129 			result = SetTargetForSubmenuItems(submenu, messenger);
130 			if (result != B_OK)
131 				return result;
132 		}
133 	}
134 
135 	if (fOpenItem)
136 		fOpenItem->SetTarget(be_app_messenger);
137 
138 	return result;
139 }
140 
141 
142 bool
143 TemplatesMenu::BuildMenu(bool addItems)
144 {
145 	// clear everything...
146 	fOpenItem = NULL;
147 	int32 count = CountItems();
148 	while (count--)
149 		delete RemoveItem((int32)0);
150 
151 	// add the folder
152 	IconMenuItem* menuItem = new IconMenuItem(B_TRANSLATE("New folder"),
153 		new BMessage(kNewFolder), B_DIR_MIMETYPE, B_MINI_ICON);
154 	AddItem(menuItem);
155 	menuItem->SetShortcut('N', 0);
156 	AddSeparatorItem();
157 
158 	// the templates folder
159 	BPath path;
160 	find_directory (B_USER_SETTINGS_DIRECTORY, &path, true);
161 	path.Append(kTemplatesDirectory);
162 	mkdir(path.Path(), 0777);
163 
164 	count = 0;
165 	count += IterateTemplateDirectory(addItems, &path, this);
166 
167 	// this is the message sent to open the templates folder
168 	BDirectory templatesDir(path.Path());
169 	BMessage* message = new BMessage(B_REFS_RECEIVED);
170 	BEntry entry;
171 	entry_ref dirRef;
172 	if (templatesDir.GetEntry(&entry) == B_OK)
173 		entry.GetRef(&dirRef);
174 
175 	message->AddRef("refs", &dirRef);
176 
177 	// add item to show templates folder
178 	fOpenItem = new BMenuItem(B_TRANSLATE("Edit templates" B_UTF8_ELLIPSIS), message);
179 	AddItem(fOpenItem);
180 
181 	if (dirRef == entry_ref())
182 		fOpenItem->SetEnabled(false);
183 
184 	return count > 0;
185 }
186 
187 
188 BMenuItem*
189 TemplatesMenu::NewSubmenuItem(BPath subdirPath)
190 {
191 	// add item to create new submenu folder
192 	BDirectory templatesDir(subdirPath.Path());
193 	BEntry entry;
194 	entry_ref dirRef;
195 	if (templatesDir.GetEntry(&entry) == B_OK)
196 		entry.GetRef(&dirRef);
197 	BMessage* message = new BMessage(kNewTemplateSubmenu);
198 	message->AddRef("refs", &dirRef);
199 	BMenuItem* submenuItem = new BMenuItem(B_TRANSLATE("Add new submenu" B_UTF8_ELLIPSIS), message);
200 
201 	if (dirRef == entry_ref())
202 		submenuItem->SetEnabled(false);
203 
204 	return submenuItem;
205 }
206 
207 
208 void
209 TemplatesMenu::UpdateMenuState()
210 {
211 	BuildMenu(false);
212 }
213 
214 
215 int
216 TemplatesMenu::IterateTemplateDirectory(bool addItems, BPath* path, BMenu* menu)
217 {
218 	uint32 count = 0;
219 	if (!path || !menu)
220 		return count;
221 
222 	BEntry entry;
223 	BList subMenus;
224 	BList subDirs;
225 	BList files;
226 	BDirectory templatesDir(path->Path());
227 	while (templatesDir.GetNextEntry(&entry) == B_OK) {
228 		BNode node(&entry);
229 		BNodeInfo nodeInfo(&node);
230 		char fileName[B_FILE_NAME_LENGTH];
231 		entry.GetName(fileName);
232 		if (nodeInfo.InitCheck() == B_OK) {
233 			char mimeType[B_MIME_TYPE_LENGTH];
234 			nodeInfo.GetType(mimeType);
235 
236 			BMimeType mime(mimeType);
237 			if (mime.IsValid()) {
238 				count++;
239 
240 				// If not adding items, we are just seeing if there
241 				// are any to list.  So if we find one, immediately
242 				// bail and return the result.
243 				if (!addItems)
244 					return count;
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 								count += IterateTemplateDirectory(addItems, &subdirPath, subMenu);
266 								subMenus.AddItem((void*)subMenu);
267 								continue;
268 							}
269 							continue;
270 						}
271 					} else {
272 						// Otherwise add it to subDirs list
273 						BMessage* message = new BMessage(kNewEntryFromTemplate);
274 						message->AddRef("refs_template", &ref);
275 						message->AddString("name", fileName);
276 						subDirs.AddItem(new IconMenuItem(fileName, message, &nodeInfo,
277 							B_MINI_ICON));
278 						continue;
279 					}
280 				}
281 
282 				// Add template files to files list
283 				BMessage* message = new BMessage(kNewEntryFromTemplate);
284 				message->AddRef("refs_template", &ref);
285 				message->AddString("name", fileName);
286 				files.AddItem(new IconMenuItem(fileName, message, &nodeInfo, B_MINI_ICON));
287 			}
288 		}
289 	}
290 
291 	// Add submenus to menu
292 	int32 itemCount = subMenus.CountItems();
293 	for (int32 i = 0; i < itemCount; i++)
294 		menu->AddItem((BMenu*)subMenus.ItemAt(i));
295 
296 	if (itemCount > 0)
297 		menu->AddSeparatorItem();
298 
299 	// Add subdirs to menu
300 	itemCount = subDirs.CountItems();
301 	for (int32 i = 0; i < itemCount; i++)
302 		menu->AddItem((BMenuItem*)subDirs.ItemAt(i));
303 
304 	if (itemCount > 0)
305 		menu->AddSeparatorItem();
306 
307 	// Add files to menu
308 	itemCount = files.CountItems();
309 	for (int32 i = 0; i < itemCount; i++)
310 		menu->AddItem((BMenuItem*)files.ItemAt(i));
311 
312 	if (itemCount > 0)
313 		menu->AddSeparatorItem();
314 
315 	menu->AddItem(NewSubmenuItem(*path));
316 
317 	return count > 0;
318 }
319 
320 
321 status_t
322 TemplatesMenu::SetTargetForSubmenuItems(BMenu* menu, BMessenger messenger)
323 {
324 	if (!menu)
325 		return B_ERROR;
326 
327 	status_t result;
328 
329 	result = menu->SetTargetForItems(messenger);
330 	if (result != B_OK)
331 		return result;
332 
333 	for (int i = 0; i < menu->CountItems(); i++) {
334 		BMenu* submenu = menu->ItemAt(i)->Submenu();
335 		if (submenu != NULL) {
336 			result = SetTargetForSubmenuItems(submenu, messenger);
337 			if (result != B_OK)
338 				return result;
339 		}
340 	}
341 	return result;
342 }
343 
344 
345 status_t
346 TemplatesMenu::SetTargetForSubmenuItems(BMenu* menu, BHandler* target)
347 {
348 	if (!menu || !target)
349 		return B_ERROR;
350 
351 	status_t result;
352 
353 	result = menu->SetTargetForItems(target);
354 	if (result != B_OK)
355 		return result;
356 
357 	for (int i = 0; i < menu->CountItems(); i++) {
358 		BMenu* submenu = menu->ItemAt(i)->Submenu();
359 		if (submenu != NULL) {
360 			result = SetTargetForSubmenuItems(submenu, target);
361 			if (result != B_OK)
362 				return result;
363 		}
364 	}
365 	return result;
366 }
367