2 * Copyright 2006-2010, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "AttributeListView.h"
8 #include "AttributeWindow.h"
9 #include "DropTargetListView.h"
10 #include "ExtensionWindow.h"
11 #include "FileTypes.h"
12 #include "FileTypesWindow.h"
14 #include "MimeTypeListView.h"
15 #include "NewFileTypeWindow.h"
16 #include "PreferredAppMenu.h"
17 #include "StringView.h"
19 #include <Alignment.h>
20 #include <AppFileInfo.h>
21 #include <Application.h>
26 #include <ControlLook.h>
27 #include <LayoutBuilder.h>
31 #include <MenuField.h>
35 #include <OutlineListView.h>
36 #include <PopUpMenu.h>
37 #include <ScrollView.h>
38 #include <SpaceLayoutItem.h>
39 #include <SplitView.h>
40 #include <TextControl.h>
42 #include <OverrideAlert.h>
43 #include <be_apps/Tracker/RecentItems.h>
50 #undef B_TRANSLATION_CONTEXT
51 #define B_TRANSLATION_CONTEXT "FileTypes Window"
54 const uint32 kMsgTypeSelected
= 'typs';
55 const uint32 kMsgAddType
= 'atyp';
56 const uint32 kMsgRemoveType
= 'rtyp';
58 const uint32 kMsgExtensionSelected
= 'exts';
59 const uint32 kMsgExtensionInvoked
= 'exti';
60 const uint32 kMsgAddExtension
= 'aext';
61 const uint32 kMsgRemoveExtension
= 'rext';
62 const uint32 kMsgRuleEntered
= 'rule';
64 const uint32 kMsgAttributeSelected
= 'atrs';
65 const uint32 kMsgAttributeInvoked
= 'atri';
66 const uint32 kMsgAddAttribute
= 'aatr';
67 const uint32 kMsgRemoveAttribute
= 'ratr';
68 const uint32 kMsgMoveUpAttribute
= 'muat';
69 const uint32 kMsgMoveDownAttribute
= 'mdat';
71 const uint32 kMsgPreferredAppChosen
= 'papc';
72 const uint32 kMsgSelectPreferredApp
= 'slpa';
73 const uint32 kMsgSamePreferredAppAs
= 'spaa';
75 const uint32 kMsgPreferredAppOpened
= 'paOp';
76 const uint32 kMsgSamePreferredAppAsOpened
= 'spaO';
78 const uint32 kMsgTypeEntered
= 'type';
79 const uint32 kMsgDescriptionEntered
= 'dsce';
81 const uint32 kMsgToggleIcons
= 'tgic';
82 const uint32 kMsgToggleRule
= 'tgrl';
85 static const char* kAttributeNames
[] = {
98 class TypeIconView
: public IconView
{
100 TypeIconView(const char* name
);
101 virtual ~TypeIconView();
103 virtual void Draw(BRect updateRect
);
104 virtual void GetPreferredSize(float* _width
, float* _height
);
107 virtual BRect
BitmapRect() const;
111 class ExtensionListView
: public DropTargetListView
{
113 ExtensionListView(const char* name
,
114 list_view_type type
= B_SINGLE_SELECTION_LIST
,
115 uint32 flags
= B_WILL_DRAW
| B_FRAME_EVENTS
| B_NAVIGABLE
);
116 virtual ~ExtensionListView();
118 virtual BSize
MinSize();
120 virtual void MessageReceived(BMessage
* message
);
121 virtual bool AcceptsDrag(const BMessage
* message
);
123 void SetType(BMimeType
* type
);
134 TypeIconView::TypeIconView(const char* name
)
137 ShowEmptyFrame(false);
142 TypeIconView::~TypeIconView()
148 TypeIconView::Draw(BRect updateRect
)
153 IconView::Draw(updateRect
);
155 const char* text
= NULL
;
157 switch (IconSource()) {
159 text
= B_TRANSLATE("no icon");
161 case kApplicationIcon
:
162 text
= B_TRANSLATE("(from application)");
165 text
= B_TRANSLATE("(from super type)");
172 SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR
),
173 B_DISABLED_LABEL_TINT
));
174 SetLowColor(ViewColor());
176 font_height fontHeight
;
177 GetFontHeight(&fontHeight
);
179 float y
= fontHeight
.ascent
;
180 if (IconSource() == kNoIcon
) {
181 // center text in the middle of the icon
182 y
+= (IconSize() - fontHeight
.ascent
- fontHeight
.descent
) / 2.0f
;
184 y
+= IconSize() + 3.0f
;
186 DrawString(text
, BPoint(ceilf((Bounds().Width() - StringWidth(text
)) / 2.0f
),
192 TypeIconView::GetPreferredSize(float* _width
, float* _height
)
195 float a
= StringWidth(B_TRANSLATE("(from application)"));
196 float b
= StringWidth(B_TRANSLATE("(from super type)"));
197 float width
= max_c(a
, b
);
198 if (width
< IconSize())
201 *_width
= ceilf(width
);
205 font_height fontHeight
;
206 GetFontHeight(&fontHeight
);
208 *_height
= IconSize() + 3.0f
+ ceilf(fontHeight
.ascent
209 + fontHeight
.descent
);
215 TypeIconView::BitmapRect() const
217 if (IconSource() == kNoIcon
) {
218 // this also defines the drop target area
219 font_height fontHeight
;
220 GetFontHeight(&fontHeight
);
222 float width
= StringWidth(B_TRANSLATE("no icon")) + 8.0f
;
223 float height
= ceilf(fontHeight
.ascent
+ fontHeight
.descent
) + 6.0f
;
224 float x
= (Bounds().Width() - width
) / 2.0f
;
225 float y
= ceilf((IconSize() - fontHeight
.ascent
- fontHeight
.descent
)
228 return BRect(x
, y
, x
+ width
, y
+ height
);
231 float x
= (Bounds().Width() - IconSize()) / 2.0f
;
232 return BRect(x
, 0.0f
, x
+ IconSize() - 1, IconSize() - 1);
239 ExtensionListView::ExtensionListView(const char* name
,
240 list_view_type type
, uint32 flags
)
242 DropTargetListView(name
, type
, flags
)
247 ExtensionListView::~ExtensionListView()
253 ExtensionListView::MinSize()
255 if (!fMinSize
.IsWidthSet()) {
258 fMinSize
.width
= font
.StringWidth(".mmmmm");
261 font
.GetHeight(&height
);
262 fMinSize
.height
= (height
.ascent
+ height
.descent
+ height
.leading
) * 3;
270 ExtensionListView::MessageReceived(BMessage
* message
)
272 if (message
->WasDropped() && AcceptsDrag(message
)) {
273 // create extension list
276 for (int32 index
= 0; message
->FindRef("refs", index
, &ref
) == B_OK
;
278 const char* point
= strchr(ref
.name
, '.');
279 if (point
!= NULL
&& point
[1])
280 list
.AddItem(strdup(++point
));
283 merge_extensions(fType
, list
);
285 // delete extension list
286 for (int32 index
= list
.CountItems(); index
-- > 0;) {
287 free(list
.ItemAt(index
));
290 DropTargetListView::MessageReceived(message
);
295 ExtensionListView::AcceptsDrag(const BMessage
* message
)
297 if (fType
.Type() == NULL
)
303 for (int32 index
= 0; message
->FindRef("refs", index
, &ref
) == B_OK
;
305 const char* point
= strchr(ref
.name
, '.');
306 if (point
!= NULL
&& point
[1])
315 ExtensionListView::SetType(BMimeType
* type
)
318 fType
.SetTo(type
->Type());
327 FileTypesWindow::FileTypesWindow(const BMessage
& settings
)
329 BWindow(_Frame(settings
), B_TRANSLATE_SYSTEM_NAME("FileTypes"),
330 B_TITLED_WINDOW
, B_NOT_ZOOMABLE
| B_ASYNCHRONOUS_CONTROLS
331 | B_AUTO_UPDATE_SIZE_LIMITS
),
336 if (settings
.FindBool("show_icons", &showIcons
) != B_OK
)
338 if (settings
.FindBool("show_rule", &showRule
) != B_OK
)
341 float padding
= be_control_look
->DefaultItemSpacing();
342 BAlignment labelAlignment
= be_control_look
->DefaultLabelAlignment();
343 BAlignment
fullAlignment(B_ALIGN_USE_FULL_WIDTH
, B_ALIGN_USE_FULL_HEIGHT
);
346 BMenuBar
* menuBar
= new BMenuBar("");
348 BMenu
* menu
= new BMenu(B_TRANSLATE("File"));
349 BMenuItem
* item
= new BMenuItem(
350 B_TRANSLATE("New resource file" B_UTF8_ELLIPSIS
), NULL
, 'N',
352 item
->SetEnabled(false);
355 BMenu
* recentsMenu
= BRecentFilesList::NewFileListMenu(
356 B_TRANSLATE("Open" B_UTF8_ELLIPSIS
), NULL
, NULL
,
357 be_app
, 10, false, NULL
, kSignature
);
358 item
= new BMenuItem(recentsMenu
, new BMessage(kMsgOpenFilePanel
));
359 item
->SetShortcut('O', B_COMMAND_KEY
);
362 menu
->AddItem(new BMenuItem(
363 B_TRANSLATE("Application types" B_UTF8_ELLIPSIS
),
364 new BMessage(kMsgOpenApplicationTypesWindow
)));
365 menu
->AddSeparatorItem();
367 menu
->AddItem(new BMenuItem(B_TRANSLATE("Quit"),
368 new BMessage(B_QUIT_REQUESTED
), 'Q', B_COMMAND_KEY
));
369 menu
->SetTargetForItems(be_app
);
370 menuBar
->AddItem(menu
);
372 menu
= new BMenu(B_TRANSLATE("Settings"));
373 item
= new BMenuItem(B_TRANSLATE("Show icons in list"),
374 new BMessage(kMsgToggleIcons
));
375 item
->SetMarked(showIcons
);
376 item
->SetTarget(this);
379 item
= new BMenuItem(B_TRANSLATE("Show recognition rule"),
380 new BMessage(kMsgToggleRule
));
381 item
->SetMarked(showRule
);
382 item
->SetTarget(this);
384 menuBar
->AddItem(menu
);
385 menuBar
->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT
, B_ALIGN_TOP
));
388 BButton
* addTypeButton
= new BButton("add",
389 B_TRANSLATE("Add" B_UTF8_ELLIPSIS
), new BMessage(kMsgAddType
));
391 fRemoveTypeButton
= new BButton("remove", B_TRANSLATE("Remove"),
392 new BMessage(kMsgRemoveType
) );
394 fTypeListView
= new MimeTypeListView("typeview", NULL
, showIcons
, false);
395 fTypeListView
->SetSelectionMessage(new BMessage(kMsgTypeSelected
));
396 fTypeListView
->SetExplicitMinSize(BSize(200, B_SIZE_UNSET
));
398 BScrollView
* typeListScrollView
= new BScrollView("scrollview",
399 fTypeListView
, B_FRAME_EVENTS
| B_WILL_DRAW
, false, true);
403 fIconView
= new TypeIconView("icon");
404 fIconBox
= new BBox("Icon BBox");
405 fIconBox
->SetLabel(B_TRANSLATE("Icon"));
406 BLayoutBuilder::Group
<>(fIconBox
, B_VERTICAL
, padding
)
412 // "File Recognition" group
414 fRecognitionBox
= new BBox("Recognition Box");
415 fRecognitionBox
->SetLabel(B_TRANSLATE("File recognition"));
416 fRecognitionBox
->SetExplicitAlignment(fullAlignment
);
418 fExtensionLabel
= new StringView(B_TRANSLATE("Extensions:"), NULL
);
419 fExtensionLabel
->LabelView()->SetExplicitAlignment(labelAlignment
);
421 fAddExtensionButton
= new BButton("add ext",
422 B_TRANSLATE("Add" B_UTF8_ELLIPSIS
), new BMessage(kMsgAddExtension
));
423 fAddExtensionButton
->SetExplicitMaxSize(
424 BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
426 fRemoveExtensionButton
= new BButton("remove ext", B_TRANSLATE("Remove"),
427 new BMessage(kMsgRemoveExtension
));
429 fExtensionListView
= new ExtensionListView("listview ext",
430 B_SINGLE_SELECTION_LIST
);
431 fExtensionListView
->SetSelectionMessage(
432 new BMessage(kMsgExtensionSelected
));
433 fExtensionListView
->SetInvocationMessage(
434 new BMessage(kMsgExtensionInvoked
));
436 BScrollView
* scrollView
= new BScrollView("scrollview ext",
437 fExtensionListView
, B_FRAME_EVENTS
| B_WILL_DRAW
, false, true);
439 fRuleControl
= new BTextControl("rule", B_TRANSLATE("Rule:"), "",
440 new BMessage(kMsgRuleEntered
));
441 fRuleControl
->SetAlignment(B_ALIGN_RIGHT
, B_ALIGN_LEFT
);
442 fRuleControl
->Hide();
444 BLayoutBuilder::Grid
<>(fRecognitionBox
, padding
, padding
/ 2)
445 .SetInsets(padding
, padding
* 2, padding
, padding
)
446 .Add(fExtensionLabel
->LabelView(), 0, 0)
447 .Add(scrollView
, 0, 1, 2, 2)
448 .Add(fAddExtensionButton
, 2, 1)
449 .Add(fRemoveExtensionButton
, 2, 2)
450 .Add(fRuleControl
, 0, 3, 3, 1);
452 // "Description" group
454 fDescriptionBox
= new BBox("description BBox");
455 fDescriptionBox
->SetLabel(B_TRANSLATE("Description"));
456 fDescriptionBox
->SetExplicitAlignment(fullAlignment
);
458 fInternalNameView
= new StringView(B_TRANSLATE("Internal name:"), NULL
);
459 fInternalNameView
->SetEnabled(false);
460 fTypeNameControl
= new BTextControl("type", B_TRANSLATE("Type name:"), "",
461 new BMessage(kMsgTypeEntered
));
462 fDescriptionControl
= new BTextControl("description",
463 B_TRANSLATE("Description:"), "", new BMessage(kMsgDescriptionEntered
));
465 BLayoutBuilder::Grid
<>(fDescriptionBox
, padding
/ 2, padding
/ 2)
466 .SetInsets(padding
, padding
* 2, padding
, padding
)
467 .Add(fInternalNameView
->LabelView(), 0, 0)
468 .Add(fInternalNameView
->TextView(), 1, 0)
469 .Add(fTypeNameControl
->CreateLabelLayoutItem(), 0, 1)
470 .Add(fTypeNameControl
->CreateTextViewLayoutItem(), 1, 1, 2)
471 .Add(fDescriptionControl
->CreateLabelLayoutItem(), 0, 2)
472 .Add(fDescriptionControl
->CreateTextViewLayoutItem(), 1, 2, 2);
474 // "Preferred Application" group
476 fPreferredBox
= new BBox("preferred BBox");
477 fPreferredBox
->SetLabel(B_TRANSLATE("Preferred application"));
479 menu
= new BPopUpMenu("preferred");
480 menu
->AddItem(item
= new BMenuItem(B_TRANSLATE("None"),
481 new BMessage(kMsgPreferredAppChosen
)));
482 item
->SetMarked(true);
483 fPreferredField
= new BMenuField("preferred", (char*)NULL
, menu
);
485 fSelectButton
= new BButton("select",
486 B_TRANSLATE("Select" B_UTF8_ELLIPSIS
),
487 new BMessage(kMsgSelectPreferredApp
));
489 fSameAsButton
= new BButton("same as",
490 B_TRANSLATE("Same as" B_UTF8_ELLIPSIS
),
491 new BMessage(kMsgSamePreferredAppAs
));
493 BLayoutBuilder::Group
<>(fPreferredBox
, B_HORIZONTAL
, padding
)
494 .SetInsets(padding
, padding
* 2, padding
, padding
)
495 .Add(fPreferredField
)
499 // "Extra Attributes" group
501 fAttributeBox
= new BBox("Attribute Box");
502 fAttributeBox
->SetLabel(B_TRANSLATE("Extra attributes"));
504 fAddAttributeButton
= new BButton("add attr",
505 B_TRANSLATE("Add" B_UTF8_ELLIPSIS
), new BMessage(kMsgAddAttribute
));
506 fAddAttributeButton
->SetExplicitMaxSize(
507 BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
509 fRemoveAttributeButton
= new BButton("remove attr", B_TRANSLATE("Remove"),
510 new BMessage(kMsgRemoveAttribute
));
511 fRemoveAttributeButton
->SetExplicitMaxSize(
512 BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
514 fMoveUpAttributeButton
= new BButton("move up attr", B_TRANSLATE("Move up"),
515 new BMessage(kMsgMoveUpAttribute
));
516 fMoveUpAttributeButton
->SetExplicitMaxSize(
517 BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
518 fMoveDownAttributeButton
= new BButton("move down attr",
519 B_TRANSLATE("Move down"), new BMessage(kMsgMoveDownAttribute
));
520 fMoveDownAttributeButton
->SetExplicitMaxSize(
521 BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
523 fAttributeListView
= new AttributeListView("listview attr");
524 fAttributeListView
->SetSelectionMessage(
525 new BMessage(kMsgAttributeSelected
));
526 fAttributeListView
->SetInvocationMessage(
527 new BMessage(kMsgAttributeInvoked
));
529 BScrollView
* attributesScroller
= new BScrollView("scrollview attr",
530 fAttributeListView
, B_FRAME_EVENTS
| B_WILL_DRAW
, false, true);
532 BLayoutBuilder::Group
<>(fAttributeBox
, B_HORIZONTAL
, padding
)
533 .SetInsets(padding
, padding
* 2, padding
, padding
)
534 .Add(attributesScroller
, 1.0f
)
535 .AddGroup(B_VERTICAL
, padding
/ 2, 0.0f
)
537 .Add(fAddAttributeButton
)
538 .Add(fRemoveAttributeButton
)
540 .Add(fMoveUpAttributeButton
)
541 .Add(fMoveDownAttributeButton
)
544 fMainSplitView
= new BSplitView(B_HORIZONTAL
, floorf(padding
/ 2));
546 BLayoutBuilder::Group
<>(this, B_VERTICAL
, 0)
549 .AddGroup(B_HORIZONTAL
, 0)
550 .SetInsets(B_USE_WINDOW_SPACING
)
551 .AddSplit(fMainSplitView
)
552 .AddGroup(B_VERTICAL
, padding
)
553 .Add(typeListScrollView
)
554 .AddGroup(B_HORIZONTAL
, padding
)
556 .Add(fRemoveTypeButton
)
561 .AddGroup(B_VERTICAL
, padding
)
562 .AddGroup(B_HORIZONTAL
, padding
)
564 .Add(fRecognitionBox
, 3)
566 .Add(fDescriptionBox
)
568 .Add(fAttributeBox
, 5);
571 _ShowSnifferRule(showRule
);
575 if (settings
.FindFloat("left_split_weight", &leftWeight
) != B_OK
576 || settings
.FindFloat("right_split_weight", &rightWeight
) != B_OK
) {
578 rightWeight
= 1.0 - leftWeight
;
580 fMainSplitView
->SetItemWeight(0, leftWeight
, false);
581 fMainSplitView
->SetItemWeight(1, rightWeight
, true);
583 BMimeType::StartWatching(this);
587 FileTypesWindow::~FileTypesWindow()
589 BMimeType::StopWatching(this);
594 FileTypesWindow::MessageReceived(BMessage
* message
)
596 switch (message
->what
) {
600 if (message
->GetInfo("refs", &type
) == B_OK
601 && type
== B_REF_TYPE
) {
602 be_app
->PostMessage(message
);
607 case kMsgToggleIcons
:
610 if (message
->FindPointer("source", (void **)&item
) != B_OK
)
613 item
->SetMarked(!fTypeListView
->IsShowingIcons());
614 fTypeListView
->ShowIcons(item
->IsMarked());
617 BMessage
update(kMsgSettingsChanged
);
618 update
.AddBool("show_icons", item
->IsMarked());
619 be_app_messenger
.SendMessage(&update
);
626 if (message
->FindPointer("source", (void **)&item
) != B_OK
)
629 item
->SetMarked(fRuleControl
->IsHidden());
630 _ShowSnifferRule(item
->IsMarked());
633 BMessage
update(kMsgSettingsChanged
);
634 update
.AddBool("show_rule", item
->IsMarked());
635 be_app_messenger
.SendMessage(&update
);
639 case kMsgTypeSelected
:
642 if (message
->FindInt32("index", &index
) == B_OK
) {
644 = (MimeTypeItem
*)fTypeListView
->ItemAt(index
);
646 BMimeType
type(item
->Type());
655 if (fNewTypeWindow
== NULL
) {
657 = new NewFileTypeWindow(this, fCurrentType
.Type());
658 fNewTypeWindow
->Show();
660 fNewTypeWindow
->Activate();
663 case kMsgNewTypeWindowClosed
:
664 fNewTypeWindow
= NULL
;
669 if (fCurrentType
.Type() == NULL
)
673 if (fCurrentType
.IsSupertypeOnly()) {
674 alert
= new BPrivate::OverrideAlert(
675 B_TRANSLATE("FileTypes request"),
676 B_TRANSLATE("Removing a super type cannot be reverted.\n"
677 "All file types that belong to this super type "
679 "Are you sure you want to do this? To remove the whole "
680 "group, hold down the Shift key and press \"Remove\"."),
681 B_TRANSLATE("Remove"), B_SHIFT_KEY
, B_TRANSLATE("Cancel"),
682 0, NULL
, 0, B_WIDTH_AS_USUAL
, B_STOP_ALERT
);
683 alert
->SetShortcut(1, B_ESCAPE
);
685 alert
= new BAlert(B_TRANSLATE("FileTypes request"),
686 B_TRANSLATE("Removing a file type cannot be reverted.\n"
687 "Are you sure you want to remove it?"),
688 B_TRANSLATE("Remove"), B_TRANSLATE("Cancel"),
689 NULL
, B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
690 alert
->SetShortcut(1, B_ESCAPE
);
695 status_t status
= fCurrentType
.Delete();
696 if (status
!= B_OK
) {
697 fprintf(stderr
, B_TRANSLATE(
698 "Could not remove file type: %s\n"), strerror(status
));
703 case kMsgSelectNewType
:
706 if (message
->FindString("type", &type
) == B_OK
)
707 fTypeListView
->SelectNewType(type
);
711 // File Recognition group
713 case kMsgExtensionSelected
:
716 if (message
->FindInt32("index", &index
) == B_OK
) {
718 = (BStringItem
*)fExtensionListView
->ItemAt(index
);
719 fRemoveExtensionButton
->SetEnabled(item
!= NULL
);
724 case kMsgExtensionInvoked
:
726 if (fCurrentType
.Type() == NULL
)
730 if (message
->FindInt32("index", &index
) == B_OK
) {
732 = (BStringItem
*)fExtensionListView
->ItemAt(index
);
737 = new ExtensionWindow(this, fCurrentType
, item
->Text());
743 case kMsgAddExtension
:
745 if (fCurrentType
.Type() == NULL
)
748 BWindow
* window
= new ExtensionWindow(this, fCurrentType
, NULL
);
753 case kMsgRemoveExtension
:
755 int32 index
= fExtensionListView
->CurrentSelection();
756 if (index
< 0 || fCurrentType
.Type() == NULL
)
760 if (fCurrentType
.GetFileExtensions(&extensions
) == B_OK
) {
761 extensions
.RemoveData("extensions", index
);
762 fCurrentType
.SetFileExtensions(&extensions
);
767 case kMsgRuleEntered
:
771 if (BMimeType::CheckSnifferRule(fRuleControl
->Text(),
772 &parseError
) != B_OK
) {
774 B_TRANSLATE("Recognition rule is not valid:\n\n"));
775 error_alert(parseError
.String());
777 fCurrentType
.SetSnifferRule(fRuleControl
->Text());
783 case kMsgTypeEntered
:
785 fCurrentType
.SetShortDescription(fTypeNameControl
->Text());
789 case kMsgDescriptionEntered
:
791 fCurrentType
.SetLongDescription(fDescriptionControl
->Text());
795 // Preferred Application group
797 case kMsgPreferredAppChosen
:
799 const char* signature
;
800 if (message
->FindString("signature", &signature
) != B_OK
)
803 fCurrentType
.SetPreferredApp(signature
);
807 case kMsgSelectPreferredApp
:
809 BMessage
panel(kMsgOpenFilePanel
);
810 panel
.AddString("title",
811 B_TRANSLATE("Select preferred application"));
812 panel
.AddInt32("message", kMsgPreferredAppOpened
);
813 panel
.AddMessenger("target", this);
815 be_app_messenger
.SendMessage(&panel
);
818 case kMsgPreferredAppOpened
:
819 _AdoptPreferredApplication(message
, false);
822 case kMsgSamePreferredAppAs
:
824 BMessage
panel(kMsgOpenFilePanel
);
825 panel
.AddString("title",
826 B_TRANSLATE("Select same preferred application as"));
827 panel
.AddInt32("message", kMsgSamePreferredAppAsOpened
);
828 panel
.AddMessenger("target", this);
829 panel
.AddBool("allowDirs", true);
831 be_app_messenger
.SendMessage(&panel
);
834 case kMsgSamePreferredAppAsOpened
:
835 _AdoptPreferredApplication(message
, true);
838 // Extra Attributes group
840 case kMsgAttributeSelected
:
843 if (message
->FindInt32("index", &index
) == B_OK
) {
845 = (AttributeItem
*)fAttributeListView
->ItemAt(index
);
846 fRemoveAttributeButton
->SetEnabled(item
!= NULL
);
847 fMoveUpAttributeButton
->SetEnabled(index
> 0);
848 fMoveDownAttributeButton
->SetEnabled(index
>= 0
849 && index
< fAttributeListView
->CountItems() - 1);
854 case kMsgAttributeInvoked
:
856 if (fCurrentType
.Type() == NULL
)
860 if (message
->FindInt32("index", &index
) == B_OK
) {
862 = (AttributeItem
*)fAttributeListView
->ItemAt(index
);
866 BWindow
* window
= new AttributeWindow(this, fCurrentType
,
873 case kMsgAddAttribute
:
875 if (fCurrentType
.Type() == NULL
)
878 BWindow
* window
= new AttributeWindow(this, fCurrentType
, NULL
);
883 case kMsgRemoveAttribute
:
885 int32 index
= fAttributeListView
->CurrentSelection();
886 if (index
< 0 || fCurrentType
.Type() == NULL
)
890 if (fCurrentType
.GetAttrInfo(&attributes
) == B_OK
) {
891 for (uint32 i
= 0; i
<
892 sizeof(kAttributeNames
) / sizeof(kAttributeNames
[0]);
894 attributes
.RemoveData(kAttributeNames
[i
], index
);
897 fCurrentType
.SetAttrInfo(&attributes
);
902 case kMsgMoveUpAttribute
:
904 int32 index
= fAttributeListView
->CurrentSelection();
905 if (index
< 1 || fCurrentType
.Type() == NULL
)
908 _MoveUpAttributeIndex(index
);
912 case kMsgMoveDownAttribute
:
914 int32 index
= fAttributeListView
->CurrentSelection();
915 if (index
< 0 || index
== fAttributeListView
->CountItems() - 1
916 || fCurrentType
.Type() == NULL
) {
920 _MoveUpAttributeIndex(index
+ 1);
924 case B_META_MIME_CHANGED
:
928 if (message
->FindString("be:type", &type
) != B_OK
929 || message
->FindInt32("be:which", &which
) != B_OK
)
932 if (fCurrentType
.Type() == NULL
)
935 if (!strcasecmp(fCurrentType
.Type(), type
)) {
936 if (which
!= B_MIME_TYPE_DELETED
)
937 _SetType(&fCurrentType
, which
);
941 // this change could still affect our current type
943 if (which
== B_MIME_TYPE_DELETED
944 || which
== B_SUPPORTED_TYPES_CHANGED
945 || which
== B_PREFERRED_APP_CHANGED
) {
946 _UpdatePreferredApps(&fCurrentType
);
953 BWindow::MessageReceived(message
);
959 FileTypesWindow::SelectType(const char* type
)
961 fTypeListView
->SelectType(type
);
966 FileTypesWindow::QuitRequested()
968 BMessage
update(kMsgSettingsChanged
);
969 update
.AddRect("file_types_frame", Frame());
970 update
.AddFloat("left_split_weight", fMainSplitView
->ItemWeight((int32
)0));
971 update
.AddFloat("right_split_weight", fMainSplitView
->ItemWeight(1));
972 be_app_messenger
.SendMessage(&update
);
974 be_app
->PostMessage(kMsgTypesWindowClosed
);
980 FileTypesWindow::PlaceSubWindow(BWindow
* window
)
982 window
->MoveTo(Frame().left
+ (Frame().Width() - window
->Frame().Width())
983 / 2.0f
, Frame().top
+ (Frame().Height() - window
->Frame().Height())
988 // #pragma mark - private
992 FileTypesWindow::_Frame(const BMessage
& settings
) const
995 if (settings
.FindRect("file_types_frame", &rect
) == B_OK
)
998 return BRect(80.0f
, 80.0f
, 0.0f
, 0.0f
);
1003 FileTypesWindow::_ShowSnifferRule(bool show
)
1005 if (fRuleControl
->IsHidden() == !show
)
1009 fRuleControl
->Hide();
1011 fRuleControl
->Show();
1016 FileTypesWindow::_UpdateExtensions(BMimeType
* type
)
1020 for (int32 i
= fExtensionListView
->CountItems(); i
-- > 0;) {
1021 delete fExtensionListView
->ItemAt(i
);
1023 fExtensionListView
->MakeEmpty();
1030 BMessage extensions
;
1031 if (type
->GetFileExtensions(&extensions
) != B_OK
)
1034 const char* extension
;
1036 while (extensions
.FindString("extensions", i
++, &extension
) == B_OK
) {
1037 char dotExtension
[B_FILE_NAME_LENGTH
];
1038 snprintf(dotExtension
, B_FILE_NAME_LENGTH
, ".%s", extension
);
1040 fExtensionListView
->AddItem(new BStringItem(dotExtension
));
1046 FileTypesWindow::_AdoptPreferredApplication(BMessage
* message
, bool sameAs
)
1048 if (fCurrentType
.Type() == NULL
)
1052 if (retrieve_preferred_app(message
, sameAs
, fCurrentType
.Type(), preferred
)
1057 status_t status
= fCurrentType
.SetPreferredApp(preferred
.String());
1059 error_alert(B_TRANSLATE("Could not set preferred application"),
1065 FileTypesWindow::_UpdatePreferredApps(BMimeType
* type
)
1067 update_preferred_app_menu(fPreferredField
->Menu(), type
,
1068 kMsgPreferredAppChosen
);
1073 FileTypesWindow::_UpdateIcon(BMimeType
* type
)
1076 fIconView
->SetTo(*type
);
1083 FileTypesWindow::_SetType(BMimeType
* type
, int32 forceUpdate
)
1085 bool enabled
= type
!= NULL
;
1090 if (fCurrentType
== *type
) {
1094 forceUpdate
= B_EVERYTHING_CHANGED
;
1096 if (&fCurrentType
!= type
)
1097 fCurrentType
.SetTo(type
->Type());
1099 fInternalNameView
->SetText(type
->Type());
1101 char description
[B_MIME_TYPE_LENGTH
];
1103 if ((forceUpdate
& B_SHORT_DESCRIPTION_CHANGED
) != 0) {
1104 if (type
->GetShortDescription(description
) != B_OK
)
1105 description
[0] = '\0';
1106 fTypeNameControl
->SetText(description
);
1109 if ((forceUpdate
& B_LONG_DESCRIPTION_CHANGED
) != 0) {
1110 if (type
->GetLongDescription(description
) != B_OK
)
1111 description
[0] = '\0';
1112 fDescriptionControl
->SetText(description
);
1115 if ((forceUpdate
& B_SNIFFER_RULE_CHANGED
) != 0) {
1117 if (type
->GetSnifferRule(&rule
) != B_OK
)
1119 fRuleControl
->SetText(rule
.String());
1122 fExtensionListView
->SetType(&fCurrentType
);
1124 fCurrentType
.Unset();
1125 fInternalNameView
->SetText(NULL
);
1126 fTypeNameControl
->SetText(NULL
);
1127 fDescriptionControl
->SetText(NULL
);
1128 fRuleControl
->SetText(NULL
);
1129 fPreferredField
->Menu()->ItemAt(0)->SetMarked(true);
1130 fExtensionListView
->SetType(NULL
);
1131 fAttributeListView
->SetTo(NULL
);
1134 if ((forceUpdate
& B_FILE_EXTENSIONS_CHANGED
) != 0)
1135 _UpdateExtensions(type
);
1137 if ((forceUpdate
& B_PREFERRED_APP_CHANGED
) != 0)
1138 _UpdatePreferredApps(type
);
1140 if ((forceUpdate
& (B_ICON_CHANGED
| B_PREFERRED_APP_CHANGED
)) != 0)
1143 if ((forceUpdate
& B_ATTR_INFO_CHANGED
) != 0)
1144 fAttributeListView
->SetTo(type
);
1146 // enable/disable controls
1148 fIconView
->SetEnabled(enabled
);
1150 fInternalNameView
->SetEnabled(enabled
);
1151 fTypeNameControl
->SetEnabled(enabled
);
1152 fDescriptionControl
->SetEnabled(enabled
);
1153 fPreferredField
->SetEnabled(enabled
);
1155 fRemoveTypeButton
->SetEnabled(enabled
);
1157 fSelectButton
->SetEnabled(enabled
);
1158 fSameAsButton
->SetEnabled(enabled
);
1160 fExtensionLabel
->SetEnabled(enabled
);
1161 fAddExtensionButton
->SetEnabled(enabled
);
1162 fRemoveExtensionButton
->SetEnabled(false);
1163 fRuleControl
->SetEnabled(enabled
);
1165 fAddAttributeButton
->SetEnabled(enabled
);
1166 fRemoveAttributeButton
->SetEnabled(false);
1167 fMoveUpAttributeButton
->SetEnabled(false);
1168 fMoveDownAttributeButton
->SetEnabled(false);
1173 FileTypesWindow::_MoveUpAttributeIndex(int32 index
)
1175 BMessage attributes
;
1176 if (fCurrentType
.GetAttrInfo(&attributes
) != B_OK
)
1179 // Iterate over all known attribute fields, and for each field,
1180 // iterate over all fields of the same name and build a copy
1181 // of the attributes message with the field at the given index swapped
1182 // with the previous field.
1183 BMessage resortedAttributes
;
1184 for (uint32 i
= 0; i
<
1185 sizeof(kAttributeNames
) / sizeof(kAttributeNames
[0]);
1191 if (attributes
.GetInfo(kAttributeNames
[i
], &type
, &count
,
1192 &isFixedSize
) != B_OK
) {
1193 // Apparently the message does not contain this name,
1194 // so just ignore this attribute name.
1195 // NOTE: This shows that the attribute description is
1196 // too fragile. It would have been better to pack each
1197 // attribute description into a separate BMessage.
1201 for (int32 j
= 0; j
< count
; j
++) {
1204 int32 originalIndex
;
1206 originalIndex
= j
+ 1;
1207 else if (j
== index
)
1208 originalIndex
= j
- 1;
1211 attributes
.FindData(kAttributeNames
[i
], type
,
1212 originalIndex
, &data
, &size
);
1214 resortedAttributes
.AddData(kAttributeNames
[i
], type
,
1215 data
, size
, isFixedSize
);
1217 resortedAttributes
.AddData(kAttributeNames
[i
], type
,
1223 // Setting it directly on the type will trigger an update of the GUI as
1224 // well. TODO: FileTypes is heavily descructive, it should use an
1226 fCurrentType
.SetAttrInfo(&resortedAttributes
);