Assorted C++11/formatting cleanups.
[dcpomatic.git] / src / wx / recipients_panel.cc
1 /*
2     Copyright (C) 2015-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "recipients_panel.h"
23 #include "wx_util.h"
24 #include "recipient_dialog.h"
25 #include "dcpomatic_button.h"
26 #include "lib/config.h"
27 #include <list>
28 #include <iostream>
29
30
31 using std::cout;
32 using std::list;
33 using std::make_pair;
34 using std::map;
35 using std::pair;
36 using std::shared_ptr;
37 using std::string;
38 using boost::optional;
39 using namespace dcpomatic;
40
41
42 RecipientsPanel::RecipientsPanel (wxWindow* parent)
43         : wxPanel (parent, wxID_ANY)
44         , _ignore_selection_change (false)
45 {
46         auto sizer = new wxBoxSizer (wxVERTICAL);
47
48 #ifdef __WXGTK3__
49         int const height = 30;
50 #else
51         int const height = -1;
52 #endif
53
54         _search = new wxSearchCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (200, height));
55 #ifndef __WXGTK3__
56         /* The cancel button seems to be strangely broken in GTK3; clicking on it twice sometimes works */
57         _search->ShowCancelButton (true);
58 #endif
59         sizer->Add (_search, 0, wxBOTTOM, DCPOMATIC_SIZER_GAP);
60
61         auto targets = new wxBoxSizer (wxHORIZONTAL);
62         _targets = new wxTreeCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_HIDE_ROOT | wxTR_MULTIPLE | wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT);
63         targets->Add (_targets, 1, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
64
65         add_recipients ();
66
67         auto target_buttons = new wxBoxSizer (wxVERTICAL);
68
69         _add_recipient = new Button (this, _("Add..."));
70         target_buttons->Add (_add_recipient, 1, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
71         _edit_recipient = new Button (this, _("Edit..."));
72         target_buttons->Add (_edit_recipient, 1, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
73         _remove_recipient = new Button (this, _("Remove"));
74         target_buttons->Add (_remove_recipient, 1, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
75
76         targets->Add (target_buttons, 0, 0);
77
78         sizer->Add (targets, 1, wxEXPAND);
79
80         _search->Bind  (wxEVT_TEXT, boost::bind (&RecipientsPanel::search_changed, this));
81         _targets->Bind (wxEVT_TREE_SEL_CHANGED, &RecipientsPanel::selection_changed_shim, this);
82
83         _add_recipient->Bind    (wxEVT_BUTTON, boost::bind (&RecipientsPanel::add_recipient_clicked, this));
84         _edit_recipient->Bind   (wxEVT_BUTTON, boost::bind (&RecipientsPanel::edit_recipient_clicked, this));
85         _remove_recipient->Bind (wxEVT_BUTTON, boost::bind (&RecipientsPanel::remove_recipient_clicked, this));
86
87         SetSizer (sizer);
88 }
89
90
91 RecipientsPanel::~RecipientsPanel ()
92 {
93         _targets->Unbind (wxEVT_TREE_SEL_CHANGED, &RecipientsPanel::selection_changed_shim, this);
94 }
95
96
97 void
98 RecipientsPanel::setup_sensitivity ()
99 {
100         _edit_recipient->Enable (_selected.size() == 1);
101         _remove_recipient->Enable (_selected.size() >= 1);
102 }
103
104
105 void
106 RecipientsPanel::add_recipient (shared_ptr<DKDMRecipient> r)
107 {
108         string search = wx_to_std (_search->GetValue());
109         transform (search.begin(), search.end(), search.begin(), ::tolower);
110
111         if (!search.empty()) {
112                 string name = r->name;
113                 transform (name.begin(), name.end(), name.begin(), ::tolower);
114                 if (name.find(search) == string::npos) {
115                         return;
116                 }
117         }
118
119         _recipients[_targets->AppendItem(_root, std_to_wx(r->name))] = r;
120
121         _targets->SortChildren (_root);
122 }
123
124
125 void
126 RecipientsPanel::add_recipient_clicked ()
127 {
128         auto d = new RecipientDialog (GetParent(), _("Add recipient"));
129         if (d->ShowModal() == wxID_OK) {
130                 auto r = std::make_shared<DKDMRecipient>(d->name(), d->notes(), d->recipient(), d->emails(), d->utc_offset_hour(), d->utc_offset_minute());
131                 Config::instance()->add_dkdm_recipient (r);
132                 add_recipient (r);
133         }
134
135         d->Destroy ();
136 }
137
138
139 void
140 RecipientsPanel::edit_recipient_clicked ()
141 {
142         if (_selected.size() != 1) {
143                 return;
144         }
145
146         auto c = *_selected.begin();
147
148         auto d = new RecipientDialog (
149                 GetParent(), _("Edit recipient"), c.second->name, c.second->notes, c.second->emails, c.second->utc_offset_hour, c.second->utc_offset_minute, c.second->recipient
150                 );
151
152         if (d->ShowModal () == wxID_OK) {
153                 c.second->name = d->name ();
154                 c.second->emails = d->emails ();
155                 c.second->notes = d->notes ();
156                 c.second->utc_offset_hour = d->utc_offset_hour ();
157                 c.second->utc_offset_minute = d->utc_offset_minute ();
158                 _targets->SetItemText (c.first, std_to_wx (d->name()));
159                 Config::instance()->changed (Config::DKDM_RECIPIENTS);
160         }
161
162         d->Destroy ();
163 }
164
165
166 void
167 RecipientsPanel::remove_recipient_clicked ()
168 {
169         for (auto const& i: _selected) {
170                 Config::instance()->remove_dkdm_recipient (i.second);
171                 _targets->Delete (i.first);
172         }
173
174         selection_changed ();
175 }
176
177
178 list<shared_ptr<DKDMRecipient>>
179 RecipientsPanel::recipients () const
180 {
181         list<shared_ptr<DKDMRecipient>> r;
182
183         for (auto const& i: _selected) {
184                 r.push_back (i.second);
185         }
186
187         r.sort ();
188         r.unique ();
189
190         return r;
191 }
192
193
194 void
195 RecipientsPanel::selection_changed_shim (wxTreeEvent &)
196 {
197         selection_changed ();
198 }
199
200
201 void
202 RecipientsPanel::selection_changed ()
203 {
204         if (_ignore_selection_change) {
205                 return;
206         }
207
208         wxArrayTreeItemIds s;
209         _targets->GetSelections (s);
210
211         _selected.clear ();
212
213         for (size_t i = 0; i < s.GetCount(); ++i) {
214                 RecipientMap::const_iterator j = _recipients.find (s[i]);
215                 if (j != _recipients.end ()) {
216                         _selected[j->first] = j->second;
217                 }
218         }
219
220         setup_sensitivity ();
221         RecipientsChanged ();
222 }
223
224
225 void
226 RecipientsPanel::add_recipients ()
227 {
228         _root = _targets->AddRoot ("Foo");
229
230         for (auto i: Config::instance()->dkdm_recipients()) {
231                 add_recipient (i);
232         }
233 }
234
235
236 void
237 RecipientsPanel::search_changed ()
238 {
239         _targets->DeleteAllItems ();
240         _recipients.clear ();
241
242         add_recipients ();
243
244         _ignore_selection_change = true;
245
246         for (auto const& i: _selected) {
247                 /* The wxTreeItemIds will now be different, so we must search by recipient */
248                 auto j = _recipients.begin ();
249                 while (j != _recipients.end() && j->second != i.second) {
250                         ++j;
251                 }
252
253                 if (j != _recipients.end ()) {
254                         _targets->SelectItem (j->first);
255                 }
256         }
257
258         _ignore_selection_change = false;
259 }