2 * Copyright 2006-2007, Axel Dörfler, axeld@pinc-software.de.
3 * All rights reserved. Distributed under the terms of the MIT License.
7 #include "ApplicationTypesWindow.h"
8 #include "ApplicationTypeWindow.h"
10 #include "FileTypesWindow.h"
11 #include "FileTypeWindow.h"
13 #include <AppFileInfo.h>
14 #include <Application.h>
19 #include <FilePanel.h>
20 #include <FindDirectory.h>
21 #include <Directory.h>
24 #include <Resources.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;
45 const BMessage
& Message() const { return fMessage
; }
46 void UpdateFrom(BMessage
* message
);
50 status_t
_Open(BFile
* file
, int32 mode
);
56 class FileTypes
: public BApplication
{
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();
73 BFilePanel
* fFilePanel
;
74 BMessenger fFilePanelTarget
;
75 FileTypesWindow
* fTypesWindow
;
76 BWindow
* fApplicationTypesWindow
;
78 uint32 fTypeWindowCount
;
85 fMessage(kMsgFileTypesSettings
),
91 if (_Open(&file
, B_READ_ONLY
) != B_OK
)
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
);
104 Settings::~Settings()
106 // only save the settings if something has changed
111 if (_Open(&file
, B_CREATE_FILE
| B_ERASE_FILE
| B_WRITE_ONLY
) != B_OK
)
114 fMessage
.Flatten(&file
);
119 Settings::UpdateFrom(BMessage
* message
)
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
);
129 if (message
->FindBool("show_icons", &showIcons
) == B_OK
)
130 fMessage
.ReplaceBool("show_icons", showIcons
);
133 if (message
->FindBool("show_rule", &showRule
) == B_OK
)
134 fMessage
.ReplaceBool("show_rule", showRule
);
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
);
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);
159 Settings::_Open(BFile
* file
, int32 mode
)
162 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
) != B_OK
)
165 path
.Append("FileTypes settings");
167 return file
->SetTo(path
.Path(), mode
);
174 FileTypes::FileTypes()
176 BApplication(kSignature
),
178 fApplicationTypesWindow(NULL
),
182 fFilePanel
= new BFilePanel(B_OPEN_PANEL
, NULL
, NULL
,
187 FileTypes::~FileTypes()
194 FileTypes::ReadyToRun()
196 // are there already windows open?
197 if (CountWindows() != 1)
200 // if not, open the FileTypes window
201 PostMessage(kMsgOpenTypesWindow
);
206 FileTypes::RefsReceived(BMessage
* message
)
208 bool traverseLinks
= (modifiers() & B_SHIFT_KEY
) == 0;
210 // filter out applications and entries we can't open
213 while (message
->FindRef("refs", index
++, &ref
) == B_OK
) {
217 status_t status
= entry
.SetTo(&ref
, traverseLinks
);
219 status
= file
.SetTo(&entry
, B_READ_ONLY
);
221 if (status
!= B_OK
) {
222 // file cannot be opened
225 snprintf(buffer
, sizeof(buffer
),
226 B_TRANSLATE("Could not open \"%s\":\n"
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
);
236 message
->RemoveData("refs", --index
);
240 if (!is_application(file
) && !is_resource(file
)) {
242 if (entry
.GetRef(&target
) == B_OK
&& target
!= ref
)
243 message
->ReplaceRef("refs", index
- 1, &ref
);
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
);
261 if (message
->FindRef("refs", &ref
) != B_OK
)
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
);
277 FileTypes::ArgvReceived(int32 argc
, char** argv
)
279 if (argc
== 3 && strcmp(argv
[1], "-type") == 0) {
284 BMessage
* message
= CurrentMessage();
286 BDirectory currentDirectory
;
288 currentDirectory
.SetTo(message
->FindString("cwd"));
292 for (int i
= 1 ; i
< argc
; i
++) {
294 if (argv
[i
][0] == '/')
297 path
.SetTo(¤tDirectory
, argv
[i
]);
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
));
310 refs
.AddRef("refs", &ref
);
318 FileTypes::MessageReceived(BMessage
* message
)
320 switch (message
->what
) {
321 case kMsgSettingsChanged
:
322 fSettings
.UpdateFrom(message
);
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());
335 fTypesWindow
->Show();
338 fTypesWindow
->Activate(true);
340 case kMsgTypesWindowClosed
:
345 case kMsgOpenApplicationTypesWindow
:
346 if (fApplicationTypesWindow
== NULL
) {
347 fApplicationTypesWindow
= new ApplicationTypesWindow(
348 fSettings
.Message());
349 fApplicationTypesWindow
->Show();
352 fApplicationTypesWindow
->Activate(true);
354 case kMsgApplicationTypesWindowClosed
:
355 fApplicationTypesWindow
= NULL
;
359 case kMsgTypeWindowClosed
:
361 // supposed to fall through
363 case kMsgWindowClosed
:
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");
376 if (message
->FindInt32("message", &what
) != B_OK
)
377 what
= B_REFS_RECEIVED
;
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]) {
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())
404 case B_SILENT_RELAUNCH
:
405 // In case we were launched via the add-on, there is no types
407 if (fTypesWindow
== NULL
)
408 PostMessage(kMsgOpenTypesWindow
);
412 if (fWindowCount
== 0)
413 PostMessage(B_QUIT_REQUESTED
);
417 RefsReceived(message
);
421 BApplication::MessageReceived(message
);
428 FileTypes::QuitRequested()
435 FileTypes::_WindowClosed()
437 if (--fWindowCount
== 0 && !fFilePanel
->IsShowing())
438 PostMessage(B_QUIT_REQUESTED
);
446 is_application(BFile
& file
)
448 BAppFileInfo
appInfo(&file
);
449 if (appInfo
.InitCheck() != B_OK
)
452 char type
[B_MIME_TYPE_LENGTH
];
453 if (appInfo
.GetType(type
) != B_OK
454 || strcasecmp(type
, B_APP_MIME_TYPE
))
462 is_resource(BFile
& file
)
464 BResources
resources(&file
);
465 if (resources
.InitCheck() != B_OK
)
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
))
479 error_alert(const char* message
, status_t status
, alert_type type
)
482 if (status
!= B_OK
) {
483 snprintf(warning
, sizeof(warning
), "%s:\n\t%s\n", message
,
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
);
496 main(int argc
, char** argv
)