docs/ikteam: Delete most files.
[haiku.git] / src / preferences / filetypes / FileTypes.cpp
blob0d3cd0f259cc5c46d8ba02adf591438122ca214e
1 /*
2 * Copyright 2006-2007, Axel Dörfler, axeld@pinc-software.de.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
7 #include "ApplicationTypesWindow.h"
8 #include "ApplicationTypeWindow.h"
9 #include "FileTypes.h"
10 #include "FileTypesWindow.h"
11 #include "FileTypeWindow.h"
13 #include <AppFileInfo.h>
14 #include <Application.h>
15 #include <Alert.h>
16 #include <Catalog.h>
17 #include <Locale.h>
18 #include <TextView.h>
19 #include <FilePanel.h>
20 #include <FindDirectory.h>
21 #include <Directory.h>
22 #include <Entry.h>
23 #include <Path.h>
24 #include <Resources.h>
26 #include <stdio.h>
27 #include <strings.h>
30 #undef B_TRANSLATION_CONTEXT
31 #define B_TRANSLATION_CONTEXT "FileTypes"
34 const char* kSignature = "application/x-vnd.Haiku-FileTypes";
36 static const uint32 kMsgFileTypesSettings = 'FTst';
37 static const uint32 kCascadeOffset = 20;
40 class Settings {
41 public:
42 Settings();
43 ~Settings();
45 const BMessage& Message() const { return fMessage; }
46 void UpdateFrom(BMessage* message);
48 private:
49 void _SetDefaults();
50 status_t _Open(BFile* file, int32 mode);
52 BMessage fMessage;
53 bool fUpdated;
56 class FileTypes : public BApplication {
57 public:
58 FileTypes();
59 virtual ~FileTypes();
61 virtual void ReadyToRun();
63 virtual void RefsReceived(BMessage* message);
64 virtual void ArgvReceived(int32 argc, char** argv);
65 virtual void MessageReceived(BMessage* message);
67 virtual bool QuitRequested();
69 private:
70 void _WindowClosed();
72 Settings fSettings;
73 BFilePanel* fFilePanel;
74 BMessenger fFilePanelTarget;
75 FileTypesWindow* fTypesWindow;
76 BWindow* fApplicationTypesWindow;
77 uint32 fWindowCount;
78 uint32 fTypeWindowCount;
79 BString fArgvType;
83 Settings::Settings()
85 fMessage(kMsgFileTypesSettings),
86 fUpdated(false)
88 _SetDefaults();
90 BFile file;
91 if (_Open(&file, B_READ_ONLY) != B_OK)
92 return;
94 BMessage settings;
95 if (settings.Unflatten(&file) == B_OK) {
96 // We don't unflatten into our default message to make sure
97 // nothing is lost (because of old or corrupted on disk settings)
98 UpdateFrom(&settings);
99 fUpdated = false;
104 Settings::~Settings()
106 // only save the settings if something has changed
107 if (!fUpdated)
108 return;
110 BFile file;
111 if (_Open(&file, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY) != B_OK)
112 return;
114 fMessage.Flatten(&file);
118 void
119 Settings::UpdateFrom(BMessage* message)
121 BRect frame;
122 if (message->FindRect("file_types_frame", &frame) == B_OK)
123 fMessage.ReplaceRect("file_types_frame", frame);
125 if (message->FindRect("app_types_frame", &frame) == B_OK)
126 fMessage.ReplaceRect("app_types_frame", frame);
128 bool showIcons;
129 if (message->FindBool("show_icons", &showIcons) == B_OK)
130 fMessage.ReplaceBool("show_icons", showIcons);
132 bool showRule;
133 if (message->FindBool("show_rule", &showRule) == B_OK)
134 fMessage.ReplaceBool("show_rule", showRule);
136 float splitWeight;
137 if (message->FindFloat("left_split_weight", &splitWeight) == B_OK)
138 fMessage.ReplaceFloat("left_split_weight", splitWeight);
139 if (message->FindFloat("right_split_weight", &splitWeight) == B_OK)
140 fMessage.ReplaceFloat("right_split_weight", splitWeight);
142 fUpdated = true;
146 void
147 Settings::_SetDefaults()
149 fMessage.AddRect("file_types_frame", BRect(80.0f, 80.0f, 600.0f, 480.0f));
150 fMessage.AddRect("app_types_frame", BRect(100.0f, 100.0f, 540.0f, 480.0f));
151 fMessage.AddBool("show_icons", true);
152 fMessage.AddBool("show_rule", false);
153 fMessage.AddFloat("left_split_weight", 0.2);
154 fMessage.AddFloat("right_split_weight", 0.8);
158 status_t
159 Settings::_Open(BFile* file, int32 mode)
161 BPath path;
162 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
163 return B_ERROR;
165 path.Append("FileTypes settings");
167 return file->SetTo(path.Path(), mode);
171 // #pragma mark -
174 FileTypes::FileTypes()
176 BApplication(kSignature),
177 fTypesWindow(NULL),
178 fApplicationTypesWindow(NULL),
179 fWindowCount(0),
180 fTypeWindowCount(0)
182 fFilePanel = new BFilePanel(B_OPEN_PANEL, NULL, NULL,
183 B_FILE_NODE, false);
187 FileTypes::~FileTypes()
189 delete fFilePanel;
193 void
194 FileTypes::ReadyToRun()
196 // are there already windows open?
197 if (CountWindows() != 1)
198 return;
200 // if not, open the FileTypes window
201 PostMessage(kMsgOpenTypesWindow);
205 void
206 FileTypes::RefsReceived(BMessage* message)
208 bool traverseLinks = (modifiers() & B_SHIFT_KEY) == 0;
210 // filter out applications and entries we can't open
211 int32 index = 0;
212 entry_ref ref;
213 while (message->FindRef("refs", index++, &ref) == B_OK) {
214 BEntry entry;
215 BFile file;
217 status_t status = entry.SetTo(&ref, traverseLinks);
218 if (status == B_OK)
219 status = file.SetTo(&entry, B_READ_ONLY);
221 if (status != B_OK) {
222 // file cannot be opened
224 char buffer[1024];
225 snprintf(buffer, sizeof(buffer),
226 B_TRANSLATE("Could not open \"%s\":\n"
227 "%s"),
228 ref.name, strerror(status));
230 BAlert* alert = new BAlert(B_TRANSLATE("FileTypes request"),
231 buffer, B_TRANSLATE("OK"), NULL, NULL,
232 B_WIDTH_AS_USUAL, B_STOP_ALERT);
233 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
234 alert->Go();
236 message->RemoveData("refs", --index);
237 continue;
240 if (!is_application(file) && !is_resource(file)) {
241 entry_ref target;
242 if (entry.GetRef(&target) == B_OK && target != ref)
243 message->ReplaceRef("refs", index - 1, &ref);
244 continue;
247 // remove application from list
248 message->RemoveData("refs", --index);
250 // There are some refs left that want to be handled by the type window
251 BPoint point(100.0f + kCascadeOffset * fTypeWindowCount,
252 110.0f + kCascadeOffset * fTypeWindowCount);
254 BWindow* window = new ApplicationTypeWindow(point, entry);
255 window->Show();
257 fTypeWindowCount++;
258 fWindowCount++;
261 if (message->FindRef("refs", &ref) != B_OK)
262 return;
264 // There are some refs left that want to be handled by the type window
265 BPoint point(100.0f + kCascadeOffset * fTypeWindowCount,
266 110.0f + kCascadeOffset * fTypeWindowCount);
268 BWindow* window = new FileTypeWindow(point, *message);
269 window->Show();
271 fTypeWindowCount++;
272 fWindowCount++;
276 void
277 FileTypes::ArgvReceived(int32 argc, char** argv)
279 if (argc == 3 && strcmp(argv[1], "-type") == 0) {
280 fArgvType = argv[2];
281 return;
284 BMessage* message = CurrentMessage();
286 BDirectory currentDirectory;
287 if (message != NULL)
288 currentDirectory.SetTo(message->FindString("cwd"));
290 BMessage refs;
292 for (int i = 1 ; i < argc ; i++) {
293 BPath path;
294 if (argv[i][0] == '/')
295 path.SetTo(argv[i]);
296 else
297 path.SetTo(&currentDirectory, argv[i]);
299 status_t status;
300 entry_ref ref;
301 BEntry entry;
303 if ((status = entry.SetTo(path.Path(), false)) != B_OK
304 || (status = entry.GetRef(&ref)) != B_OK) {
305 fprintf(stderr, "Could not open file \"%s\": %s\n",
306 path.Path(), strerror(status));
307 continue;
310 refs.AddRef("refs", &ref);
313 RefsReceived(&refs);
317 void
318 FileTypes::MessageReceived(BMessage* message)
320 switch (message->what) {
321 case kMsgSettingsChanged:
322 fSettings.UpdateFrom(message);
323 break;
325 case kMsgOpenTypesWindow:
326 if (fTypesWindow == NULL) {
327 fTypesWindow = new FileTypesWindow(fSettings.Message());
328 if (fArgvType.Length() > 0) {
329 // Set the window to the type that was requested on the
330 // command line (-type), we do this only once, if we
331 // ever opened more than one FileTypesWindow.
332 fTypesWindow->SelectType(fArgvType.String());
333 fArgvType = "";
335 fTypesWindow->Show();
336 fWindowCount++;
337 } else
338 fTypesWindow->Activate(true);
339 break;
340 case kMsgTypesWindowClosed:
341 fTypesWindow = NULL;
342 _WindowClosed();
343 break;
345 case kMsgOpenApplicationTypesWindow:
346 if (fApplicationTypesWindow == NULL) {
347 fApplicationTypesWindow = new ApplicationTypesWindow(
348 fSettings.Message());
349 fApplicationTypesWindow->Show();
350 fWindowCount++;
351 } else
352 fApplicationTypesWindow->Activate(true);
353 break;
354 case kMsgApplicationTypesWindowClosed:
355 fApplicationTypesWindow = NULL;
356 _WindowClosed();
357 break;
359 case kMsgTypeWindowClosed:
360 fTypeWindowCount--;
361 // supposed to fall through
363 case kMsgWindowClosed:
364 _WindowClosed();
365 break;
368 case kMsgOpenFilePanel:
370 // the open file panel sends us a message when it's done
371 const char* subTitle;
372 if (message->FindString("title", &subTitle) != B_OK)
373 subTitle = B_TRANSLATE("Open file");
375 int32 what;
376 if (message->FindInt32("message", &what) != B_OK)
377 what = B_REFS_RECEIVED;
379 BMessenger target;
380 if (message->FindMessenger("target", &target) != B_OK)
381 target = be_app_messenger;
383 BString title = B_TRANSLATE("FileTypes");
384 if (subTitle != NULL && subTitle[0]) {
385 title.Append(": ");
386 title.Append(subTitle);
389 uint32 flavors = B_FILE_NODE;
390 if (message->FindBool("allowDirs"))
391 flavors |= B_DIRECTORY_NODE;
392 fFilePanel->SetNodeFlavors(flavors);
395 fFilePanel->SetMessage(new BMessage(what));
396 fFilePanel->Window()->SetTitle(title.String());
397 fFilePanel->SetTarget(target);
399 if (!fFilePanel->IsShowing())
400 fFilePanel->Show();
401 break;
404 case B_SILENT_RELAUNCH:
405 // In case we were launched via the add-on, there is no types
406 // window yet.
407 if (fTypesWindow == NULL)
408 PostMessage(kMsgOpenTypesWindow);
409 break;
411 case B_CANCEL:
412 if (fWindowCount == 0)
413 PostMessage(B_QUIT_REQUESTED);
414 break;
416 case B_SIMPLE_DATA:
417 RefsReceived(message);
418 break;
420 default:
421 BApplication::MessageReceived(message);
422 break;
427 bool
428 FileTypes::QuitRequested()
430 return true;
434 void
435 FileTypes::_WindowClosed()
437 if (--fWindowCount == 0 && !fFilePanel->IsShowing())
438 PostMessage(B_QUIT_REQUESTED);
442 // #pragma mark -
445 bool
446 is_application(BFile& file)
448 BAppFileInfo appInfo(&file);
449 if (appInfo.InitCheck() != B_OK)
450 return false;
452 char type[B_MIME_TYPE_LENGTH];
453 if (appInfo.GetType(type) != B_OK
454 || strcasecmp(type, B_APP_MIME_TYPE))
455 return false;
457 return true;
461 bool
462 is_resource(BFile& file)
464 BResources resources(&file);
465 if (resources.InitCheck() != B_OK)
466 return false;
468 BNodeInfo nodeInfo(&file);
469 char type[B_MIME_TYPE_LENGTH];
470 if (nodeInfo.GetType(type) != B_OK
471 || strcasecmp(type, B_RESOURCE_MIME_TYPE))
472 return false;
474 return true;
478 void
479 error_alert(const char* message, status_t status, alert_type type)
481 char warning[512];
482 if (status != B_OK) {
483 snprintf(warning, sizeof(warning), "%s:\n\t%s\n", message,
484 strerror(status));
487 BAlert* alert = new BAlert(B_TRANSLATE("FileTypes request"),
488 status == B_OK ? message : warning,
489 B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, type);
490 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
491 alert->Go();
496 main(int argc, char** argv)
498 FileTypes probe;
499 probe.Run();
500 return 0;