xref: /haiku/src/apps/stylededit/StyledEditApp.cpp (revision a906d0a031e721e2f2ec9d95274103e74a3a774f)
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_TRANSLATE_CONTEXT
84 #define B_TRANSLATE_CONTEXT "Open_and_SaveAsPanel"
85 
86 
87 StyledEditApp::StyledEditApp()
88 	:
89 	BApplication(APP_SIGNATURE),
90 	fOpenPanel(NULL)
91 {
92 	fOpenPanel = new BFilePanel();
93 
94 	fOpenAsEncoding = 0;
95 
96 	BMenuBar* menuBar
97 		= dynamic_cast<BMenuBar*>(fOpenPanel->Window()->FindView("MenuBar"));
98 	if (menuBar != NULL) {
99 		fOpenPanelEncodingMenu = new BMenu(B_TRANSLATE("Encoding"));
100 		fOpenPanelEncodingMenu->SetRadioMode(true);
101 
102 		menuBar->AddItem(fOpenPanelEncodingMenu);
103 
104 		BCharacterSetRoster roster;
105 		BCharacterSet charset;
106 		while (roster.GetNextCharacterSet(&charset) == B_NO_ERROR) {
107 			BString name;
108 			if (charset.GetFontID() == B_UNICODE_UTF8)
109 				name = B_TRANSLATE("Default");
110 			else
111 				name = charset.GetPrintName();
112 
113 			const char* mime = charset.GetMIMEName();
114 			if (mime != NULL) {
115 				name.Append(" (");
116 				name.Append(mime);
117 				name.Append(")");
118 			}
119 			BMenuItem* item =
120 				new BMenuItem(name.String(), new BMessage(OPEN_AS_ENCODING));
121 			item->SetTarget(this);
122 			fOpenPanelEncodingMenu->AddItem(item);
123 			if (charset.GetFontID() == fOpenAsEncoding)
124 				item->SetMarked(true);
125 		}
126 	} else
127 		fOpenPanelEncodingMenu = NULL;
128 
129 	fWindowCount = 0;
130 	fNextUntitledWindow = 1;
131 	fBadArguments = false;
132 }
133 
134 
135 StyledEditApp::~StyledEditApp()
136 {
137 	delete fOpenPanel;
138 }
139 
140 
141 void
142 StyledEditApp::MessageReceived(BMessage* message)
143 {
144 	switch (message->what) {
145 		case MENU_NEW:
146 			OpenDocument();
147 			break;
148 		case MENU_OPEN:
149 			fOpenPanel->Show();
150 			break;
151 		case B_SILENT_RELAUNCH:
152 			OpenDocument();
153 			break;
154 		case OPEN_AS_ENCODING:
155 			void* ptr;
156 			if (message->FindPointer("source", &ptr) == B_OK
157 				&& fOpenPanelEncodingMenu != NULL) {
158 				fOpenAsEncoding = (uint32)fOpenPanelEncodingMenu->IndexOf(
159 					(BMenuItem*)ptr);
160 			}
161 			break;
162 
163 		default:
164 			BApplication::MessageReceived(message);
165 			break;
166 	}
167 }
168 
169 
170 void
171 StyledEditApp::OpenDocument()
172 {
173 	cascade();
174 	new StyledEditWindow(gWindowRect, fNextUntitledWindow++, fOpenAsEncoding);
175 	fWindowCount++;
176 }
177 
178 
179 status_t
180 StyledEditApp::OpenDocument(entry_ref* ref)
181 {
182 	// traverse eventual symlink
183 	BEntry entry(ref, true);
184 	entry.GetRef(ref);
185 
186 	if (entry.IsDirectory()) {
187 		BPath path(&entry);
188 		fprintf(stderr,
189 			"Can't open directory \"%s\" for editing.\n",
190 			path.Path());
191 		return B_ERROR;
192 	}
193 
194 	BEntry parent;
195 	entry.GetParent(&parent);
196 
197 	if (!entry.Exists() && !parent.Exists()) {
198 		fprintf(stderr,
199 			"Can't create file. Missing parent directory.\n");
200 		return B_ERROR;
201 	}
202 
203 	BWindow* window = NULL;
204 	StyledEditWindow* document = NULL;
205 
206 	for (int32 index = 0; ; index++) {
207 		window = WindowAt(index);
208 		if (window == NULL)
209 			break;
210 
211 		document = dynamic_cast<StyledEditWindow*>(window);
212 		if (document == NULL)
213 			continue;
214 
215 		if (document->IsDocumentEntryRef(ref)) {
216 			if (document->Lock()) {
217 				document->Activate();
218 				document->Unlock();
219 				return B_OK;
220 			}
221 		}
222 	}
223 
224 	cascade();
225 	new StyledEditWindow(gWindowRect, ref, fOpenAsEncoding);
226 	fWindowCount++;
227 
228 	return B_OK;
229 }
230 
231 
232 void
233 StyledEditApp::CloseDocument()
234 {
235 	uncascade();
236 	fWindowCount--;
237 	if (fWindowCount == 0) {
238 		BAutolock lock(this);
239 		Quit();
240 	}
241 }
242 
243 
244 void
245 StyledEditApp::RefsReceived(BMessage* message)
246 {
247 	int32 index = 0;
248 	entry_ref ref;
249 
250 	while (message->FindRef("refs", index++, &ref) == B_OK) {
251 		OpenDocument(&ref);
252 	}
253 }
254 
255 
256 void
257 StyledEditApp::ArgvReceived(int32 argc, char* argv[])
258 {
259 	// If StyledEdit is already running and gets invoked again
260 	// we need to account for a possible mismatch in current
261 	// working directory. The paths of the new arguments are
262 	// relative to the cwd of the invocation, if they are not
263 	// absolute. This cwd we find as a string named "cwd" in
264 	// the BLooper's current message.
265 
266 	const char* cwd = "";
267 	BMessage* message = CurrentMessage();
268 
269 	if (message != NULL) {
270 		if (message->FindString("cwd", &cwd) != B_OK)
271 			cwd = "";
272 	}
273 
274 	for (int i = 1 ; (i < argc) ; i++) {
275 		BPath path;
276 		if (argv[i][0] == '/') {
277 			path.SetTo(argv[i]);
278 		} else {
279 			path.SetTo(cwd, argv[i]);
280 				// patch relative paths only
281 		}
282 
283 		entry_ref ref;
284 		get_ref_for_path(path.Path(), &ref);
285 
286 		status_t status;
287 		status = OpenDocument(&ref);
288 
289 		if (status != B_OK && IsLaunching())
290 			fBadArguments = true;
291 	}
292 }
293 
294 
295 void
296 StyledEditApp::ReadyToRun()
297 {
298 	if (fWindowCount > 0)
299 		return;
300 
301 	if (fBadArguments)
302 		Quit();
303 	else
304 		OpenDocument();
305 }
306 
307 
308 int32
309 StyledEditApp::NumberOfWindows()
310 {
311  	return fWindowCount;
312 }
313 
314 
315 //	#pragma mark -
316 
317 
318 int
319 main(int argc, char** argv)
320 {
321 	StyledEditApp styledEdit;
322 	styledEdit.Run();
323 	return 0;
324 }
325 
326