xref: /haiku/src/apps/stylededit/StyledEditApp.cpp (revision 220d04022750f40f8bac8f01fa551211e28d04f2)
1 /*
2  * Copyright 2002-2010, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Mattias Sundblad
7  *		Andrew Bachmann
8  *		Jonas Sundström
9  */
10 
11 
12 #include "Constants.h"
13 #include "StyledEditApp.h"
14 #include "StyledEditWindow.h"
15 
16 #include <Alert.h>
17 #include <Autolock.h>
18 #include <Catalog.h>
19 #include <Locale.h>
20 #include <MenuBar.h>
21 #include <CharacterSet.h>
22 #include <CharacterSetRoster.h>
23 #include <FilePanel.h>
24 #include <MenuItem.h>
25 #include <Message.h>
26 #include <Path.h>
27 #include <Screen.h>
28 
29 #include <stdio.h>
30 
31 
32 using namespace BPrivate;
33 
34 
35 BRect gWindowRect(7 - 15, 26 - 15, 507, 426);
36 
37 
38 namespace
39 {
40 	void
41 	cascade()
42 	{
43 		BScreen screen;
44 		BRect screenBorder = screen.Frame();
45 		float left = gWindowRect.left + 15;
46 		if (left + gWindowRect.Width() > screenBorder.right)
47 			left = 7;
48 
49 		float top = gWindowRect.top + 15;
50 		if (top + gWindowRect.Height() > screenBorder.bottom)
51 			top = 26;
52 
53 		gWindowRect.OffsetTo(BPoint(left, top));
54 	}
55 
56 
57 	void
58 	uncascade()
59 	{
60 		BScreen screen;
61 		BRect screenBorder = screen.Frame();
62 
63 		float left = gWindowRect.left - 15;
64 		if (left < 7) {
65 			left = screenBorder.right - gWindowRect.Width() - 7;
66 			left = left - ((int)left % 15) + 7;
67 		}
68 
69 		float top = gWindowRect.top - 15;
70 		if (top < 26) {
71 			top = screenBorder.bottom - gWindowRect.Height() - 26;
72 			top = top - ((int)left % 15) + 26;
73 		}
74 
75 		gWindowRect.OffsetTo(BPoint(left, top));
76 	}
77 }
78 
79 
80 //	#pragma mark -
81 
82 
83 #undef B_TRANSLATION_CONTEXT
84 #define B_TRANSLATION_CONTEXT "Open_and_SaveAsPanel"
85 
86 
87 StyledEditApp::StyledEditApp()
88 	:
89 	BApplication(APP_SIGNATURE),
90 	fOpenPanel(NULL)
91 {
92 	B_TRANSLATE_MARK_SYSTEM_NAME_VOID("StyledEdit");
93 
94 	fOpenPanel = new BFilePanel();
95 	fOpenAsEncoding = 0;
96 
97 	BMenuBar* menuBar
98 		= dynamic_cast<BMenuBar*>(fOpenPanel->Window()->FindView("MenuBar"));
99 	if (menuBar != NULL) {
100 		fOpenPanelEncodingMenu = new BMenu(B_TRANSLATE("Encoding"));
101 		fOpenPanelEncodingMenu->SetRadioMode(true);
102 
103 		menuBar->AddItem(fOpenPanelEncodingMenu);
104 
105 		BCharacterSetRoster roster;
106 		BCharacterSet charset;
107 		while (roster.GetNextCharacterSet(&charset) == B_NO_ERROR) {
108 			BString name;
109 			if (charset.GetFontID() == B_UNICODE_UTF8)
110 				name = B_TRANSLATE("Default");
111 			else
112 				name = charset.GetPrintName();
113 
114 			const char* mime = charset.GetMIMEName();
115 			if (mime != NULL) {
116 				name.Append(" (");
117 				name.Append(mime);
118 				name.Append(")");
119 			}
120 			BMenuItem* item
121 				= new BMenuItem(name.String(), new BMessage(OPEN_AS_ENCODING));
122 			item->SetTarget(this);
123 			fOpenPanelEncodingMenu->AddItem(item);
124 			if (charset.GetFontID() == fOpenAsEncoding)
125 				item->SetMarked(true);
126 		}
127 	} else
128 		fOpenPanelEncodingMenu = NULL;
129 
130 	fWindowCount = 0;
131 	fNextUntitledWindow = 1;
132 	fBadArguments = false;
133 }
134 
135 
136 StyledEditApp::~StyledEditApp()
137 {
138 	delete fOpenPanel;
139 }
140 
141 
142 void
143 StyledEditApp::MessageReceived(BMessage* message)
144 {
145 	switch (message->what) {
146 		case MENU_NEW:
147 			OpenDocument();
148 			break;
149 		case MENU_OPEN:
150 			fOpenPanel->Show();
151 			break;
152 		case B_SILENT_RELAUNCH:
153 			OpenDocument();
154 			break;
155 		case OPEN_AS_ENCODING:
156 			void* ptr;
157 			if (message->FindPointer("source", &ptr) == B_OK
158 				&& fOpenPanelEncodingMenu != NULL) {
159 				fOpenAsEncoding = (uint32)fOpenPanelEncodingMenu->IndexOf(
160 					(BMenuItem*)ptr);
161 			}
162 			break;
163 
164 		default:
165 			BApplication::MessageReceived(message);
166 			break;
167 	}
168 }
169 
170 
171 void
172 StyledEditApp::OpenDocument()
173 {
174 	cascade();
175 	new StyledEditWindow(gWindowRect, fNextUntitledWindow++, fOpenAsEncoding);
176 	fWindowCount++;
177 }
178 
179 
180 status_t
181 StyledEditApp::OpenDocument(entry_ref* ref, BMessage* message)
182 {
183 	// traverse eventual symlink
184 	BEntry entry(ref, true);
185 	entry.GetRef(ref);
186 
187 	if (entry.IsDirectory()) {
188 		BPath path(&entry);
189 		fprintf(stderr,
190 			"Can't open directory \"%s\" for editing.\n",
191 			path.Path());
192 		return B_ERROR;
193 	}
194 
195 	BEntry parent;
196 	entry.GetParent(&parent);
197 
198 	if (!entry.Exists() && !parent.Exists()) {
199 		fprintf(stderr,
200 			"Can't create file. Missing parent directory.\n");
201 		return B_ERROR;
202 	}
203 
204 	BWindow* window = NULL;
205 	StyledEditWindow* document = NULL;
206 
207 	for (int32 index = 0; ; index++) {
208 		window = WindowAt(index);
209 		if (window == NULL)
210 			break;
211 
212 		document = dynamic_cast<StyledEditWindow*>(window);
213 		if (document == NULL)
214 			continue;
215 
216 		if (document->IsDocumentEntryRef(ref)) {
217 			if (document->Lock()) {
218 				document->Activate();
219 				document->Unlock();
220 				if (message != NULL)
221 					document->PostMessage(message);
222 				return B_OK;
223 			}
224 		}
225 	}
226 
227 	cascade();
228 	document = new StyledEditWindow(gWindowRect, ref, fOpenAsEncoding);
229 
230 	if (message != NULL)
231 		document->PostMessage(message);
232 
233 	fWindowCount++;
234 
235 	return B_OK;
236 }
237 
238 
239 void
240 StyledEditApp::CloseDocument()
241 {
242 	uncascade();
243 	fWindowCount--;
244 	if (fWindowCount == 0) {
245 		BAutolock lock(this);
246 		Quit();
247 	}
248 }
249 
250 
251 void
252 StyledEditApp::RefsReceived(BMessage* message)
253 {
254 	int32 index = 0;
255 	entry_ref ref;
256 
257 	while (message->FindRef("refs", index, &ref) == B_OK) {
258 		int32 line;
259 		if (message->FindInt32("be:line", index, &line) != B_OK)
260 			line = -1;
261 		int32 start, length;
262 		if (message->FindInt32("be:selection_length", index, &length) != B_OK
263 			|| message->FindInt32("be:selection_offset", index, &start) != B_OK)
264 		{
265 			start = -1;
266 			length = -1;
267 		}
268 
269 		BMessage* selection = NULL;
270 		if (line >= 0 || (start >= 0 && length >= 0)) {
271 			selection = new BMessage(UPDATE_LINE_SELECTION);
272 			if (line >= 0)
273 				selection->AddInt32("be:line", line);
274 			if (start >= 0) {
275 				selection->AddInt32("be:selection_offset", start);
276 				selection->AddInt32("be:selection_length", max_c(0, length));
277 			}
278 		}
279 
280 		OpenDocument(&ref, selection);
281 		index++;
282 	}
283 }
284 
285 
286 void
287 StyledEditApp::ArgvReceived(int32 argc, char* argv[])
288 {
289 	// If StyledEdit is already running and gets invoked again
290 	// we need to account for a possible mismatch in current
291 	// working directory. The paths of the new arguments are
292 	// relative to the cwd of the invocation, if they are not
293 	// absolute. This cwd we find as a string named "cwd" in
294 	// the BLooper's current message.
295 
296 	const char* cwd = "";
297 	BMessage* message = CurrentMessage();
298 
299 	if (message != NULL) {
300 		if (message->FindString("cwd", &cwd) != B_OK)
301 			cwd = "";
302 	}
303 
304 	for (int i = 1 ; (i < argc) ; i++) {
305 		BPath path;
306 		if (argv[i][0] == '/') {
307 			path.SetTo(argv[i]);
308 		} else {
309 			path.SetTo(cwd, argv[i]);
310 				// patch relative paths only
311 		}
312 
313 		entry_ref ref;
314 		get_ref_for_path(path.Path(), &ref);
315 
316 		status_t status;
317 		status = OpenDocument(&ref);
318 
319 		if (status != B_OK && IsLaunching())
320 			fBadArguments = true;
321 	}
322 }
323 
324 
325 void
326 StyledEditApp::ReadyToRun()
327 {
328 	if (fWindowCount > 0)
329 		return;
330 
331 	if (fBadArguments)
332 		Quit();
333 	else
334 		OpenDocument();
335 }
336 
337 
338 int32
339 StyledEditApp::NumberOfWindows()
340 {
341 	return fWindowCount;
342 }
343 
344 
345 //	#pragma mark -
346 
347 
348 int
349 main(int argc, char** argv)
350 {
351 	StyledEditApp styledEdit;
352 	styledEdit.Run();
353 	return 0;
354 }
355 
356