/* * Copyright 2007-2016, Haiku, Inc. All rights reserved. * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved. * Copyright 2011, Clemens Zeidler * Distributed under the terms of the MIT License. */ #include "FilterConfigView.h" #include #include #include #include #include #include #include #include #include #include #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Config Views" // FiltersConfigView const uint32 kMsgFilterMoved = 'flmv'; const uint32 kMsgChainSelected = 'chsl'; const uint32 kMsgAddFilter = 'addf'; const uint32 kMsgRemoveFilter = 'rmfi'; const uint32 kMsgFilterSelected = 'fsel'; const uint32 kMsgItemDragged = 'itdr'; class DragListView : public BListView { public: DragListView(const char* name, list_view_type type = B_SINGLE_SELECTION_LIST, BMessage* itemMovedMsg = NULL) : BListView(name, type), fDragging(false), fItemMovedMessage(itemMovedMsg) { } virtual bool InitiateDrag(BPoint point, int32 index, bool wasSelected) { BRect frame(ItemFrame(index)); BBitmap *bitmap = new BBitmap(frame.OffsetToCopy(B_ORIGIN), B_RGBA32, true); BView *view = new BView(bitmap->Bounds(), NULL, 0, 0); bitmap->AddChild(view); if (view->LockLooper()) { BListItem *item = ItemAt(index); bool selected = item->IsSelected(); view->SetLowColor(225, 225, 225, 128); view->FillRect(view->Bounds()); if (selected) item->Deselect(); ItemAt(index)->DrawItem(view, view->Bounds(), true); if (selected) item->Select(); view->UnlockLooper(); } fLastDragTarget = -1; fDragIndex = index; fDragging = true; BMessage drag(kMsgItemDragged); drag.AddInt32("index", index); DragMessage(&drag, bitmap, B_OP_ALPHA, point - frame.LeftTop(), this); return true; } void DrawDragTargetIndicator(int32 target) { PushState(); SetDrawingMode(B_OP_INVERT); bool last = false; if (target >= CountItems()) target = CountItems() - 1, last = true; BRect frame = ItemFrame(target); if (last) frame.OffsetBy(0,frame.Height()); frame.bottom = frame.top + 1; FillRect(frame); PopState(); } virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *msg) { BListView::MouseMoved(point, transit, msg); if ((transit != B_ENTERED_VIEW && transit != B_INSIDE_VIEW) || !fDragging) return; int32 target = IndexOf(point); if (target == -1) target = CountItems(); // correct the target insertion index if (target == fDragIndex || target == fDragIndex + 1) target = -1; if (target == fLastDragTarget) return; // remove old target indicator if (fLastDragTarget != -1) DrawDragTargetIndicator(fLastDragTarget); // draw new one fLastDragTarget = target; if (target != -1) DrawDragTargetIndicator(target); } virtual void MouseUp(BPoint point) { if (fDragging) { fDragging = false; if (fLastDragTarget != -1) DrawDragTargetIndicator(fLastDragTarget); } BListView::MouseUp(point); } virtual void MessageReceived(BMessage *msg) { switch (msg->what) { case kMsgItemDragged: { int32 source = msg->FindInt32("index"); BPoint point = msg->FindPoint("_drop_point_"); ConvertFromScreen(&point); int32 to = IndexOf(point); if (to > fDragIndex) to--; if (to == -1) to = CountItems() - 1; if (source != to) { MoveItem(source,to); if (fItemMovedMessage != NULL) { BMessage msg(fItemMovedMessage->what); msg.AddInt32("from",source); msg.AddInt32("to",to); Messenger().SendMessage(&msg); } } break; } } BListView::MessageReceived(msg); } private: bool fDragging; int32 fLastDragTarget,fDragIndex; BMessage *fItemMovedMessage; }; // #pragma mark - class FilterSettingsView : public BBox { public: FilterSettingsView(const BString& label, BMailSettingsView* settingsView) : BBox("filter"), fSettingsView(settingsView) { SetLabel(label); BView* contents = new BView("contents", 0); AddChild(contents); BLayoutBuilder::Group<>(contents, B_VERTICAL) .SetInsets(B_USE_DEFAULT_SPACING) .Add(fSettingsView); } status_t SaveInto(BMailAddOnSettings& settings) const { return fSettingsView->SaveInto(settings); } private: BMailSettingsView* fSettingsView; }; // #pragma mark - FiltersConfigView::FiltersConfigView(BMailAccountSettings& account) : BGroupView(B_VERTICAL), fAccount(account), fDirection(kIncoming), fInboundFilters(kIncoming), fOutboundFilters(kOutgoing), fFilterView(NULL), fCurrentIndex(-1) { BBox* box = new BBox("filters"); AddChild(box); BView* contents = new BView(NULL, 0); box->AddChild(contents); BMessage* msg = new BMessage(kMsgChainSelected); msg->AddInt32("direction", kIncoming); BMenuItem* item = new BMenuItem(B_TRANSLATE("Incoming mail filters"), msg); item->SetMarked(true); BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING); menu->AddItem(item); msg = new BMessage(kMsgChainSelected); msg->AddInt32("direction", kOutgoing); item = new BMenuItem(B_TRANSLATE("Outgoing mail filters"), msg); menu->AddItem(item); fChainsField = new BMenuField(NULL, NULL, menu); fChainsField->ResizeToPreferred(); box->SetLabel(fChainsField); fListView = new DragListView(NULL, B_SINGLE_SELECTION_LIST, new BMessage(kMsgFilterMoved)); fListView->SetSelectionMessage(new BMessage(kMsgFilterSelected)); menu = new BPopUpMenu(B_TRANSLATE("Add filter")); menu->SetRadioMode(false); fAddField = new BMenuField(NULL, NULL, menu); fRemoveButton = new BButton(NULL, B_TRANSLATE("Remove"), new BMessage(kMsgRemoveFilter)); BLayoutBuilder::Group<>(contents, B_VERTICAL) .SetInsets(B_USE_DEFAULT_SPACING) .Add(new BScrollView(NULL, fListView, 0, false, true)) .AddGroup(B_HORIZONTAL) .Add(fAddField) .Add(fRemoveButton) .AddGlue(); _SetDirection(fDirection); } FiltersConfigView::~FiltersConfigView() { // We need to remove the filter manually, as their add-on // is not available anymore in the parent destructor. if (fFilterView != NULL) { RemoveChild(fFilterView); delete fFilterView; } } void FiltersConfigView::_SelectFilter(int32 index) { Hide(); // remove old config view if (fFilterView != NULL) { RemoveChild(fFilterView); _SaveConfig(fCurrentIndex); delete fFilterView; fFilterView = NULL; } if (index >= 0) { // add new config view BMailAddOnSettings* filterSettings = _MailSettings()->FilterSettingsAt(index); if (filterSettings != NULL) { ::FilterList* filters = _FilterList(); BMailSettingsView* view = filters->CreateSettingsView(fAccount, *filterSettings); if (view != NULL) { fFilterView = new FilterSettingsView( filters->DescriptiveName(filterSettings->AddOnRef(), fAccount, NULL), view); AddChild(fFilterView); } } } fCurrentIndex = index; Show(); } void FiltersConfigView::_SetDirection(direction direction) { // remove the filter config view _SelectFilter(-1); for (int32 i = fListView->CountItems(); i-- > 0;) { BStringItem *item = (BStringItem *)fListView->RemoveItem(i); delete item; } fDirection = direction; BMailProtocolSettings* protocolSettings = _MailSettings(); ::FilterList* filters = _FilterList(); filters->Reload(); for (int32 i = 0; i < protocolSettings->CountFilterSettings(); i++) { BMailAddOnSettings* settings = protocolSettings->FilterSettingsAt(i); if (filters->InfoIndexFor(settings->AddOnRef()) < 0) { fprintf(stderr, "Removed missing filter: %s\n", settings->AddOnRef().name); protocolSettings->RemoveFilterSettings(i); i--; continue; } fListView->AddItem(new BStringItem(filters->DescriptiveName( settings->AddOnRef(), fAccount, settings))); } // remove old filter items BMenu* menu = fAddField->Menu(); for (int32 i = menu->CountItems(); i-- > 0;) { BMenuItem *item = menu->RemoveItem(i); delete item; } for (int32 i = 0; i < filters->CountInfos(); i++) { const FilterInfo& info = filters->InfoAt(i); BMessage* msg = new BMessage(kMsgAddFilter); msg->AddRef("filter", &info.ref); BMenuItem* item = new BMenuItem(filters->SimpleName(i, fAccount), msg); menu->AddItem(item); } menu->SetTargetForItems(this); } void FiltersConfigView::AttachedToWindow() { fChainsField->Menu()->SetTargetForItems(this); fListView->SetTarget(this); fAddField->Menu()->SetTargetForItems(this); fRemoveButton->SetTarget(this); } void FiltersConfigView::DetachedFromWindow() { _SaveConfig(fCurrentIndex); } void FiltersConfigView::MessageReceived(BMessage *msg) { switch (msg->what) { case kMsgChainSelected: { direction dir; if (msg->FindInt32("direction", (int32*)&dir) != B_OK) break; if (fDirection == dir) break; _SetDirection(dir); break; } case kMsgAddFilter: { entry_ref ref; if (msg->FindRef("filter", &ref) != B_OK) break; int32 index = _MailSettings()->AddFilterSettings(&ref); if (index < 0) break; fListView->AddItem(new BStringItem(_FilterList()->DescriptiveName( ref, fAccount, _MailSettings()->FilterSettingsAt(index)))); break; } case kMsgRemoveFilter: { int32 index = fListView->CurrentSelection(); if (index < 0) break; BStringItem* item = (BStringItem*)fListView->RemoveItem(index); delete item; _SelectFilter(-1); _MailSettings()->RemoveFilterSettings(index); break; } case kMsgFilterSelected: { int32 index = -1; if (msg->FindInt32("index",&index) != B_OK) break; _SelectFilter(index); break; } case kMsgFilterMoved: { int32 from = msg->FindInt32("from"); int32 to = msg->FindInt32("to"); if (from == to) break; if (!_MailSettings()->MoveFilterSettings(from, to)) { BAlert* alert = new BAlert("E-mail", B_TRANSLATE("The filter could not be moved. Deleting " "filter."), B_TRANSLATE("OK")); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(); fListView->RemoveItem(to); break; } break; } default: BView::MessageReceived(msg); break; } } BMailProtocolSettings* FiltersConfigView::_MailSettings() { return fDirection == kIncoming ? &fAccount.InboundSettings() : &fAccount.OutboundSettings(); } FilterList* FiltersConfigView::_FilterList() { return fDirection == kIncoming ? &fInboundFilters : &fOutboundFilters; } void FiltersConfigView::_SaveConfig(int32 index) { if (fFilterView != NULL) { BMailAddOnSettings* settings = _MailSettings()->FilterSettingsAt(index); if (settings != NULL) fFilterView->SaveInto(*settings); } }