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