RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / preferences / mail / FilterConfigView.cpp
blob2d46068587852810ddce1bfcf3d9f5d3df4e5de4
1 /*
2 * Copyright 2007-2016, Haiku, Inc. All rights reserved.
3 * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
4 * Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
5 * Distributed under the terms of the MIT License.
6 */
9 #include "FilterConfigView.h"
11 #include <stdio.h>
13 #include <Alert.h>
14 #include <Bitmap.h>
15 #include <Box.h>
16 #include <Catalog.h>
17 #include <LayoutBuilder.h>
18 #include <Locale.h>
19 #include <MenuItem.h>
20 #include <PopUpMenu.h>
21 #include <ScrollView.h>
24 #undef B_TRANSLATION_CONTEXT
25 #define B_TRANSLATION_CONTEXT "Config Views"
28 // FiltersConfigView
29 const uint32 kMsgFilterMoved = 'flmv';
30 const uint32 kMsgChainSelected = 'chsl';
31 const uint32 kMsgAddFilter = 'addf';
32 const uint32 kMsgRemoveFilter = 'rmfi';
33 const uint32 kMsgFilterSelected = 'fsel';
35 const uint32 kMsgItemDragged = 'itdr';
38 class DragListView : public BListView {
39 public:
40 DragListView(const char* name,
41 list_view_type type = B_SINGLE_SELECTION_LIST,
42 BMessage* itemMovedMsg = NULL)
44 BListView(name, type),
45 fDragging(false),
46 fItemMovedMessage(itemMovedMsg)
50 virtual bool InitiateDrag(BPoint point, int32 index, bool wasSelected)
52 BRect frame(ItemFrame(index));
53 BBitmap *bitmap = new BBitmap(frame.OffsetToCopy(B_ORIGIN), B_RGBA32,
54 true);
55 BView *view = new BView(bitmap->Bounds(), NULL, 0, 0);
56 bitmap->AddChild(view);
58 if (view->LockLooper()) {
59 BListItem *item = ItemAt(index);
60 bool selected = item->IsSelected();
62 view->SetLowColor(225, 225, 225, 128);
63 view->FillRect(view->Bounds());
65 if (selected)
66 item->Deselect();
67 ItemAt(index)->DrawItem(view, view->Bounds(), true);
68 if (selected)
69 item->Select();
71 view->UnlockLooper();
73 fLastDragTarget = -1;
74 fDragIndex = index;
75 fDragging = true;
77 BMessage drag(kMsgItemDragged);
78 drag.AddInt32("index", index);
79 DragMessage(&drag, bitmap, B_OP_ALPHA, point - frame.LeftTop(), this);
81 return true;
84 void DrawDragTargetIndicator(int32 target)
86 PushState();
87 SetDrawingMode(B_OP_INVERT);
89 bool last = false;
90 if (target >= CountItems())
91 target = CountItems() - 1, last = true;
93 BRect frame = ItemFrame(target);
94 if (last)
95 frame.OffsetBy(0,frame.Height());
96 frame.bottom = frame.top + 1;
98 FillRect(frame);
100 PopState();
103 virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *msg)
105 BListView::MouseMoved(point, transit, msg);
107 if ((transit != B_ENTERED_VIEW && transit != B_INSIDE_VIEW)
108 || !fDragging)
109 return;
111 int32 target = IndexOf(point);
112 if (target == -1)
113 target = CountItems();
115 // correct the target insertion index
116 if (target == fDragIndex || target == fDragIndex + 1)
117 target = -1;
119 if (target == fLastDragTarget)
120 return;
122 // remove old target indicator
123 if (fLastDragTarget != -1)
124 DrawDragTargetIndicator(fLastDragTarget);
126 // draw new one
127 fLastDragTarget = target;
128 if (target != -1)
129 DrawDragTargetIndicator(target);
132 virtual void MouseUp(BPoint point)
134 if (fDragging) {
135 fDragging = false;
136 if (fLastDragTarget != -1)
137 DrawDragTargetIndicator(fLastDragTarget);
139 BListView::MouseUp(point);
142 virtual void MessageReceived(BMessage *msg)
144 switch (msg->what) {
145 case kMsgItemDragged:
147 int32 source = msg->FindInt32("index");
148 BPoint point = msg->FindPoint("_drop_point_");
149 ConvertFromScreen(&point);
150 int32 to = IndexOf(point);
151 if (to > fDragIndex)
152 to--;
153 if (to == -1)
154 to = CountItems() - 1;
156 if (source != to) {
157 MoveItem(source,to);
159 if (fItemMovedMessage != NULL) {
160 BMessage msg(fItemMovedMessage->what);
161 msg.AddInt32("from",source);
162 msg.AddInt32("to",to);
163 Messenger().SendMessage(&msg);
166 break;
169 BListView::MessageReceived(msg);
172 private:
173 bool fDragging;
174 int32 fLastDragTarget,fDragIndex;
175 BMessage *fItemMovedMessage;
179 // #pragma mark -
182 class FilterSettingsView : public BBox {
183 public:
184 FilterSettingsView(const BString& label, BMailSettingsView* settingsView)
186 BBox("filter"),
187 fSettingsView(settingsView)
189 SetLabel(label);
191 BView* contents = new BView("contents", 0);
192 AddChild(contents);
194 BLayoutBuilder::Group<>(contents, B_VERTICAL)
195 .SetInsets(B_USE_DEFAULT_SPACING)
196 .Add(fSettingsView);
199 status_t SaveInto(BMailAddOnSettings& settings) const
201 return fSettingsView->SaveInto(settings);
204 private:
205 BMailSettingsView* fSettingsView;
209 // #pragma mark -
212 FiltersConfigView::FiltersConfigView(BMailAccountSettings& account)
214 BGroupView(B_VERTICAL),
215 fAccount(account),
216 fDirection(kIncoming),
217 fInboundFilters(kIncoming),
218 fOutboundFilters(kOutgoing),
219 fFilterView(NULL),
220 fCurrentIndex(-1)
222 BBox* box = new BBox("filters");
223 AddChild(box);
225 BView* contents = new BView(NULL, 0);
226 box->AddChild(contents);
228 BMessage* msg = new BMessage(kMsgChainSelected);
229 msg->AddInt32("direction", kIncoming);
230 BMenuItem* item = new BMenuItem(B_TRANSLATE("Incoming mail filters"), msg);
231 item->SetMarked(true);
232 BPopUpMenu* menu = new BPopUpMenu(B_EMPTY_STRING);
233 menu->AddItem(item);
235 msg = new BMessage(kMsgChainSelected);
236 msg->AddInt32("direction", kOutgoing);
237 item = new BMenuItem(B_TRANSLATE("Outgoing mail filters"), msg);
238 menu->AddItem(item);
240 fChainsField = new BMenuField(NULL, NULL, menu);
241 fChainsField->ResizeToPreferred();
242 box->SetLabel(fChainsField);
244 fListView = new DragListView(NULL, B_SINGLE_SELECTION_LIST,
245 new BMessage(kMsgFilterMoved));
246 fListView->SetSelectionMessage(new BMessage(kMsgFilterSelected));
248 menu = new BPopUpMenu(B_TRANSLATE("Add filter"));
249 menu->SetRadioMode(false);
251 fAddField = new BMenuField(NULL, NULL, menu);
253 fRemoveButton = new BButton(NULL, B_TRANSLATE("Remove"),
254 new BMessage(kMsgRemoveFilter));
256 BLayoutBuilder::Group<>(contents, B_VERTICAL)
257 .SetInsets(B_USE_DEFAULT_SPACING)
258 .Add(new BScrollView(NULL, fListView, 0, false, true))
259 .AddGroup(B_HORIZONTAL)
260 .Add(fAddField)
261 .Add(fRemoveButton)
262 .AddGlue();
264 _SetDirection(fDirection);
268 FiltersConfigView::~FiltersConfigView()
270 // We need to remove the filter manually, as their add-on
271 // is not available anymore in the parent destructor.
272 if (fFilterView != NULL) {
273 RemoveChild(fFilterView);
274 delete fFilterView;
279 void
280 FiltersConfigView::_SelectFilter(int32 index)
282 Hide();
284 // remove old config view
285 if (fFilterView != NULL) {
286 RemoveChild(fFilterView);
287 _SaveConfig(fCurrentIndex);
288 delete fFilterView;
289 fFilterView = NULL;
292 if (index >= 0) {
293 // add new config view
294 BMailAddOnSettings* filterSettings
295 = _MailSettings()->FilterSettingsAt(index);
296 if (filterSettings != NULL) {
297 ::FilterList* filters = _FilterList();
298 BMailSettingsView* view = filters->CreateSettingsView(fAccount,
299 *filterSettings);
300 if (view != NULL) {
301 fFilterView = new FilterSettingsView(
302 filters->DescriptiveName(filterSettings->AddOnRef(),
303 fAccount, NULL), view);
304 AddChild(fFilterView);
309 fCurrentIndex = index;
310 Show();
314 void
315 FiltersConfigView::_SetDirection(direction direction)
317 // remove the filter config view
318 _SelectFilter(-1);
320 for (int32 i = fListView->CountItems(); i-- > 0;) {
321 BStringItem *item = (BStringItem *)fListView->RemoveItem(i);
322 delete item;
325 fDirection = direction;
326 BMailProtocolSettings* protocolSettings = _MailSettings();
327 ::FilterList* filters = _FilterList();
328 filters->Reload();
330 for (int32 i = 0; i < protocolSettings->CountFilterSettings(); i++) {
331 BMailAddOnSettings* settings = protocolSettings->FilterSettingsAt(i);
332 if (filters->InfoIndexFor(settings->AddOnRef()) < 0) {
333 fprintf(stderr, "Removed missing filter: %s\n",
334 settings->AddOnRef().name);
335 protocolSettings->RemoveFilterSettings(i);
336 i--;
337 continue;
340 fListView->AddItem(new BStringItem(filters->DescriptiveName(
341 settings->AddOnRef(), fAccount, settings)));
344 // remove old filter items
345 BMenu* menu = fAddField->Menu();
346 for (int32 i = menu->CountItems(); i-- > 0;) {
347 BMenuItem *item = menu->RemoveItem(i);
348 delete item;
351 for (int32 i = 0; i < filters->CountInfos(); i++) {
352 const FilterInfo& info = filters->InfoAt(i);
354 BMessage* msg = new BMessage(kMsgAddFilter);
355 msg->AddRef("filter", &info.ref);
356 BMenuItem* item = new BMenuItem(filters->SimpleName(i, fAccount), msg);
357 menu->AddItem(item);
360 menu->SetTargetForItems(this);
364 void
365 FiltersConfigView::AttachedToWindow()
367 fChainsField->Menu()->SetTargetForItems(this);
368 fListView->SetTarget(this);
369 fAddField->Menu()->SetTargetForItems(this);
370 fRemoveButton->SetTarget(this);
374 void
375 FiltersConfigView::DetachedFromWindow()
377 _SaveConfig(fCurrentIndex);
381 void
382 FiltersConfigView::MessageReceived(BMessage *msg)
384 switch (msg->what) {
385 case kMsgChainSelected:
387 direction dir;
388 if (msg->FindInt32("direction", (int32*)&dir) != B_OK)
389 break;
391 if (fDirection == dir)
392 break;
394 _SetDirection(dir);
395 break;
397 case kMsgAddFilter:
399 entry_ref ref;
400 if (msg->FindRef("filter", &ref) != B_OK)
401 break;
403 int32 index = _MailSettings()->AddFilterSettings(&ref);
404 if (index < 0)
405 break;
407 fListView->AddItem(new BStringItem(_FilterList()->DescriptiveName(
408 ref, fAccount, _MailSettings()->FilterSettingsAt(index))));
409 break;
411 case kMsgRemoveFilter:
413 int32 index = fListView->CurrentSelection();
414 if (index < 0)
415 break;
416 BStringItem* item = (BStringItem*)fListView->RemoveItem(index);
417 delete item;
419 _SelectFilter(-1);
420 _MailSettings()->RemoveFilterSettings(index);
421 break;
423 case kMsgFilterSelected:
425 int32 index = -1;
426 if (msg->FindInt32("index",&index) != B_OK)
427 break;
429 _SelectFilter(index);
430 break;
432 case kMsgFilterMoved:
434 int32 from = msg->FindInt32("from");
435 int32 to = msg->FindInt32("to");
436 if (from == to)
437 break;
439 if (!_MailSettings()->MoveFilterSettings(from, to)) {
440 BAlert* alert = new BAlert("E-mail",
441 B_TRANSLATE("The filter could not be moved. Deleting "
442 "filter."), B_TRANSLATE("OK"));
443 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
444 alert->Go();
445 fListView->RemoveItem(to);
446 break;
449 break;
451 default:
452 BView::MessageReceived(msg);
453 break;
458 BMailProtocolSettings*
459 FiltersConfigView::_MailSettings()
461 return fDirection == kIncoming
462 ? &fAccount.InboundSettings() : &fAccount.OutboundSettings();
466 FilterList*
467 FiltersConfigView::_FilterList()
469 return fDirection == kIncoming ? &fInboundFilters : &fOutboundFilters;
473 void
474 FiltersConfigView::_SaveConfig(int32 index)
476 if (fFilterView != NULL) {
477 BMailAddOnSettings* settings = _MailSettings()->FilterSettingsAt(index);
478 if (settings != NULL)
479 fFilterView->SaveInto(*settings);