xref: /haiku/src/apps/stylededit/StyledEditApp.cpp (revision 70449c90d95aeea01b25f686d51da4217fe41317)
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)
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 				return B_OK;
221 			}
222 		}
223 	}
224 
225 	cascade();
226 	new StyledEditWindow(gWindowRect, ref, fOpenAsEncoding);
227 	fWindowCount++;
228 
229 	return B_OK;
230 }
231 
232 
233 void
234 StyledEditApp::CloseDocument()
235 {
236 	uncascade();
237 	fWindowCount--;
238 	if (fWindowCount == 0) {
239 		BAutolock lock(this);
240 		Quit();
241 	}
242 }
243 
244 
245 void
246 StyledEditApp::RefsReceived(BMessage* message)
247 {
248 	int32 index = 0;
249 	entry_ref ref;
250 
251 	while (message->FindRef("refs", index++, &ref) == B_OK) {
252 		OpenDocument(&ref);
253 	}
254 }
255 
256 
257 void
258 StyledEditApp::ArgvReceived(int32 argc, char* argv[])
259 {
260 	// If StyledEdit is already running and gets invoked again
261 	// we need to account for a possible mismatch in current
262 	// working directory. The paths of the new arguments are
263 	// relative to the cwd of the invocation, if they are not
264 	// absolute. This cwd we find as a string named "cwd" in
265 	// the BLooper's current message.
266 
267 	const char* cwd = "";
268 	BMessage* message = CurrentMessage();
269 
270 	if (message != NULL) {
271 		if (message->FindString("cwd", &cwd) != B_OK)
272 			cwd = "";
273 	}
274 
275 	for (int i = 1 ; (i < argc) ; i++) {
276 		BPath path;
277 		if (argv[i][0] == '/') {
278 			path.SetTo(argv[i]);
279 		} else {
280 			path.SetTo(cwd, argv[i]);
281 				// patch relative paths only
282 		}
283 
284 		entry_ref ref;
285 		get_ref_for_path(path.Path(), &ref);
286 
287 		status_t status;
288 		status = OpenDocument(&ref);
289 
290 		if (status != B_OK && IsLaunching())
291 			fBadArguments = true;
292 	}
293 }
294 
295 
296 void
297 StyledEditApp::ReadyToRun()
298 {
299 	if (fWindowCount > 0)
300 		return;
301 
302 	if (fBadArguments)
303 		Quit();
304 	else
305 		OpenDocument();
306 }
307 
308 
309 int32
310 StyledEditApp::NumberOfWindows()
311 {
312  	return fWindowCount;
313 }
314 
315 
316 //	#pragma mark -
317 
318 
319 int
320 main(int argc, char** argv)
321 {
322 	StyledEditApp styledEdit;
323 	styledEdit.Run();
324 	return 0;
325 }
326 
327