2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
8 #include "FileTypeWindow.h"
10 #include "PreferredAppMenu.h"
11 #include "TypeListWindow.h"
13 #include <Application.h>
18 #include <ControlLook.h>
20 #include <LayoutBuilder.h>
22 #include <MenuField.h>
26 #include <PopUpMenu.h>
27 #include <SpaceLayoutItem.h>
28 #include <TextControl.h>
33 #undef B_TRANSLATION_CONTEXT
34 #define B_TRANSLATION_CONTEXT "FileType Window"
37 const uint32 kMsgTypeEntered
= 'type';
38 const uint32 kMsgSelectType
= 'sltp';
39 const uint32 kMsgTypeSelected
= 'tpsd';
40 const uint32 kMsgSameTypeAs
= 'stpa';
41 const uint32 kMsgSameTypeAsOpened
= 'stpO';
43 const uint32 kMsgPreferredAppChosen
= 'papc';
44 const uint32 kMsgSelectPreferredApp
= 'slpa';
45 const uint32 kMsgSamePreferredAppAs
= 'spaa';
46 const uint32 kMsgPreferredAppOpened
= 'paOp';
47 const uint32 kMsgSamePreferredAppAsOpened
= 'spaO';
50 FileTypeWindow::FileTypeWindow(BPoint position
, const BMessage
& refs
)
52 BWindow(BRect(0.0f
, 0.0f
, 300.0f
, 200.0f
).OffsetBySelf(position
),
53 B_TRANSLATE("File type"), B_TITLED_WINDOW
,
54 B_NOT_V_RESIZABLE
| B_NOT_ZOOMABLE
55 | B_ASYNCHRONOUS_CONTROLS
| B_AUTO_UPDATE_SIZE_LIMITS
)
57 float padding
= be_control_look
->DefaultItemSpacing();
60 BBox
* fileTypeBox
= new BBox("file type BBox");
61 fileTypeBox
->SetLabel(B_TRANSLATE("File type"));
63 fTypeControl
= new BTextControl("type", NULL
, "Type Control",
64 new BMessage(kMsgTypeEntered
));
66 // filter out invalid characters that can't be part of a MIME type name
67 BTextView
* textView
= fTypeControl
->TextView();
68 const char* disallowedCharacters
= "<>@,;:\"()[]?=";
69 for (int32 i
= 0; disallowedCharacters
[i
]; i
++) {
70 textView
->DisallowChar(disallowedCharacters
[i
]);
73 fSelectTypeButton
= new BButton("select type",
74 B_TRANSLATE("Select" B_UTF8_ELLIPSIS
), new BMessage(kMsgSelectType
));
76 fSameTypeAsButton
= new BButton("same type as",
77 B_TRANSLATE_COMMENT("Same as" B_UTF8_ELLIPSIS
,
78 "The same TYPE as ..."), new BMessage(kMsgSameTypeAs
));
80 BLayoutBuilder::Grid
<>(fileTypeBox
, padding
, padding
/ 2)
81 .SetInsets(padding
, padding
* 2, padding
, padding
)
82 .Add(fTypeControl
, 0, 0, 3, 1)
83 .Add(fSelectTypeButton
, 0, 1)
84 .Add(fSameTypeAsButton
, 1, 1);
88 BBox
* iconBox
= new BBox("icon BBox");
89 iconBox
->SetLabel(B_TRANSLATE("Icon"));
90 fIconView
= new IconView("icon");
91 BLayoutBuilder::Group
<>(iconBox
, B_HORIZONTAL
)
92 .SetInsets(padding
, padding
* 2, padding
, padding
)
95 // "Preferred Application" group
97 BBox
* preferredBox
= new BBox("preferred BBox");
98 preferredBox
->SetLabel(B_TRANSLATE("Preferred application"));
100 BMenu
* menu
= new BPopUpMenu("preferred");
102 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("Default application"),
103 new BMessage(kMsgPreferredAppChosen
)));
104 item
->SetMarked(true);
106 fPreferredField
= new BMenuField("preferred", NULL
, menu
);
108 fSelectAppButton
= new BButton("select app",
109 B_TRANSLATE("Select" B_UTF8_ELLIPSIS
),
110 new BMessage(kMsgSelectPreferredApp
));
112 fSameAppAsButton
= new BButton("same app as",
113 B_TRANSLATE_COMMENT("Same as" B_UTF8_ELLIPSIS
,
114 "The same APPLICATION as ..."),
115 new BMessage(kMsgSamePreferredAppAs
));
117 BLayoutBuilder::Grid
<>(preferredBox
, padding
, padding
/ 2)
118 .SetInsets(padding
, padding
* 2, padding
, padding
)
119 .Add(fPreferredField
, 0, 0, 2, 1)
120 .Add(fSelectAppButton
, 0, 1)
121 .Add(fSameAppAsButton
, 1, 1);
123 BLayoutBuilder::Grid
<>(this)
125 .Add(fileTypeBox
, 0, 0, 2, 1)
126 .Add(preferredBox
, 0, 1, 1, 1)
127 .Add(iconBox
, 1, 1, 1, 1);
129 fTypeControl
->MakeFocus(true);
130 BMimeType::StartWatching(this);
135 FileTypeWindow::~FileTypeWindow()
137 BMimeType::StopWatching(this);
142 FileTypeWindow::_Title(const BMessage
& refs
)
147 if (refs
.FindRef("refs", 1, &ref
) == B_OK
) {
149 BEntry entry
, parent
;
150 if (entry
.SetTo(&ref
) == B_OK
151 && entry
.GetParent(&parent
) == B_OK
) {
154 // Check if all entries have the same parent directory
155 for (int32 i
= 0; refs
.FindRef("refs", i
, &ref
) == B_OK
; i
++) {
157 if (entry
.SetTo(&ref
) == B_OK
158 && entry
.GetParent(&directory
) == B_OK
) {
159 if (directory
!= parent
) {
167 char name
[B_FILE_NAME_LENGTH
];
168 if (same
&& parent
.GetName(name
) == B_OK
) {
170 snprintf(buffer
, sizeof(buffer
),
171 B_TRANSLATE("Multiple files from \"%s\" file type"), name
);
174 title
= B_TRANSLATE("[Multiple files] file types");
175 } else if (refs
.FindRef("refs", 0, &ref
) == B_OK
) {
177 snprintf(buffer
, sizeof(buffer
), B_TRANSLATE("%s file type"), ref
.name
);
186 FileTypeWindow::_SetTo(const BMessage
& refs
)
188 SetTitle(_Title(refs
).String());
190 // get common info and icons
192 fCommonPreferredApp
= "";
195 for (int32 i
= 0; refs
.FindRef("refs", i
, &ref
) == B_OK
; i
++) {
197 if (node
.InitCheck() != B_OK
)
200 BNodeInfo
info(&node
);
201 if (info
.InitCheck() != B_OK
)
204 // TODO: watch entries?
206 entry_ref
* copiedRef
= new entry_ref(ref
);
207 fEntries
.AddItem(copiedRef
);
209 char type
[B_MIME_TYPE_LENGTH
];
210 if (info
.GetType(type
) != B_OK
)
214 if (fCommonType
!= type
)
219 char preferredApp
[B_MIME_TYPE_LENGTH
];
220 if (info
.GetPreferredApp(preferredApp
) != B_OK
)
221 preferredApp
[0] = '\0';
224 if (fCommonPreferredApp
!= preferredApp
)
225 fCommonPreferredApp
= "";
227 fCommonPreferredApp
= preferredApp
;
230 fIconView
->SetTo(ref
);
233 fTypeControl
->SetText(fCommonType
.String());
234 _UpdatePreferredApps();
236 fIconView
->ShowIconHeap(fEntries
.CountItems() != 1);
241 FileTypeWindow::_AdoptType(BMessage
* message
)
244 if (message
== NULL
|| message
->FindRef("refs", &ref
) != B_OK
)
248 status_t status
= node
.InitCheck();
250 char type
[B_MIME_TYPE_LENGTH
];
252 if (status
== B_OK
) {
253 // get type from file
254 BNodeInfo
nodeInfo(&node
);
255 status
= nodeInfo
.InitCheck();
256 if (status
== B_OK
) {
257 if (nodeInfo
.GetType(type
) != B_OK
)
262 if (status
!= B_OK
) {
263 error_alert(B_TRANSLATE("Could not open file"), status
);
268 fTypeControl
->SetText(type
);
274 FileTypeWindow::_AdoptType()
276 for (int32 i
= 0; i
< fEntries
.CountItems(); i
++) {
277 BNode
node(fEntries
.ItemAt(i
));
278 BNodeInfo
info(&node
);
279 if (node
.InitCheck() != B_OK
280 || info
.InitCheck() != B_OK
)
283 info
.SetType(fCommonType
.String());
289 FileTypeWindow::_AdoptPreferredApp(BMessage
* message
, bool sameAs
)
291 if (retrieve_preferred_app(message
, sameAs
, fCommonType
.String(),
292 fCommonPreferredApp
) == B_OK
) {
293 _AdoptPreferredApp();
294 _UpdatePreferredApps();
300 FileTypeWindow::_AdoptPreferredApp()
302 for (int32 i
= 0; i
< fEntries
.CountItems(); i
++) {
303 BNode
node(fEntries
.ItemAt(i
));
304 if (fCommonPreferredApp
.Length() == 0) {
305 node
.RemoveAttr("BEOS:PREF_APP");
309 BNodeInfo
info(&node
);
310 if (node
.InitCheck() != B_OK
311 || info
.InitCheck() != B_OK
)
314 info
.SetPreferredApp(fCommonPreferredApp
.String());
320 FileTypeWindow::_UpdatePreferredApps()
322 BMimeType
type(fCommonType
.String());
323 update_preferred_app_menu(fPreferredField
->Menu(), &type
,
324 kMsgPreferredAppChosen
, fCommonPreferredApp
.String());
329 FileTypeWindow::MessageReceived(BMessage
* message
)
331 switch (message
->what
) {
334 case kMsgTypeEntered
:
335 fCommonType
= fTypeControl
->Text();
341 BWindow
* window
= new TypeListWindow(fCommonType
.String(),
342 kMsgTypeSelected
, this);
346 case kMsgTypeSelected
:
349 if (message
->FindString("type", &type
) == B_OK
) {
351 fTypeControl
->SetText(type
);
359 BMessage
panel(kMsgOpenFilePanel
);
360 panel
.AddString("title", B_TRANSLATE("Select same type as"));
361 panel
.AddInt32("message", kMsgSameTypeAsOpened
);
362 panel
.AddMessenger("target", this);
363 panel
.AddBool("allowDirs", true);
365 be_app_messenger
.SendMessage(&panel
);
368 case kMsgSameTypeAsOpened
:
372 // Preferred Application group
374 case kMsgPreferredAppChosen
:
376 const char* signature
;
377 if (message
->FindString("signature", &signature
) == B_OK
)
378 fCommonPreferredApp
= signature
;
380 fCommonPreferredApp
= "";
382 _AdoptPreferredApp();
386 case kMsgSelectPreferredApp
:
388 BMessage
panel(kMsgOpenFilePanel
);
389 panel
.AddString("title",
390 B_TRANSLATE("Select preferred application"));
391 panel
.AddInt32("message", kMsgPreferredAppOpened
);
392 panel
.AddMessenger("target", this);
394 be_app_messenger
.SendMessage(&panel
);
397 case kMsgPreferredAppOpened
:
398 _AdoptPreferredApp(message
, false);
401 case kMsgSamePreferredAppAs
:
403 BMessage
panel(kMsgOpenFilePanel
);
404 panel
.AddString("title",
405 B_TRANSLATE("Select same preferred application as"));
406 panel
.AddInt32("message", kMsgSamePreferredAppAsOpened
);
407 panel
.AddMessenger("target", this);
408 panel
.AddBool("allowDirs", true);
410 be_app_messenger
.SendMessage(&panel
);
413 case kMsgSamePreferredAppAsOpened
:
414 _AdoptPreferredApp(message
, true);
422 if (message
->FindRef("refs", &ref
) != B_OK
)
425 BFile
file(&ref
, B_READ_ONLY
);
426 if (is_application(file
))
427 _AdoptPreferredApp(message
, false);
433 case B_META_MIME_CHANGED
:
436 if (message
->FindString("be:type", &type
) != B_OK
437 || message
->FindInt32("be:which", &which
) != B_OK
)
440 if (which
== B_MIME_TYPE_DELETED
441 || which
== B_SUPPORTED_TYPES_CHANGED
) {
442 _UpdatePreferredApps();
447 BWindow::MessageReceived(message
);
453 FileTypeWindow::QuitRequested()
455 be_app
->PostMessage(kMsgTypeWindowClosed
);