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