2 /// \file GroupCfgDlg.cc
3 /// The configuration dialog used when a user double clicks
4 /// on a device in the device list. It lets the user choose
5 /// the app to sync with Barry, as well as the engine to use.
9 Copyright (C) 2009-2012, Net Direct Inc. (http://www.netdirect.ca/)
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 See the GNU General Public License in the COPYING file at the
21 root directory of this project for more details.
24 #include "GroupCfgDlg.h"
25 #include "windowids.h"
27 #include "barrydesktop.h"
31 using namespace OpenSync
;
33 BEGIN_EVENT_TABLE(GroupCfgDlg
, wxDialog
)
34 EVT_BUTTON (Dialog_GroupCfg_AppConfigButton
,
35 GroupCfgDlg::OnConfigureApp
)
36 EVT_CHECKBOX (Dialog_GroupCfg_ContactsCheck
,
37 GroupCfgDlg::OnSyncTypeCheck
)
38 EVT_CHECKBOX (Dialog_GroupCfg_EventsCheck
,
39 GroupCfgDlg::OnSyncTypeCheck
)
40 EVT_CHECKBOX (Dialog_GroupCfg_NotesCheck
,
41 GroupCfgDlg::OnSyncTypeCheck
)
42 EVT_CHECKBOX (Dialog_GroupCfg_TodosCheck
,
43 GroupCfgDlg::OnSyncTypeCheck
)
44 EVT_TEXT (Dialog_GroupCfg_EngineCombo
,
45 GroupCfgDlg::OnEngineComboChange
)
46 EVT_TEXT (Dialog_GroupCfg_AppCombo
,
47 GroupCfgDlg::OnAppComboChange
)
50 //////////////////////////////////////////////////////////////////////////////
53 GroupCfgDlg::GroupCfgDlg(wxWindow
*parent
,
54 const DeviceEntry
&device
,
55 OpenSync::APISet
&apiset
)
56 : wxDialog(parent
, Dialog_GroupCfg
, _T("Device Sync Configuration"))
61 , m_barry_plugin(m_device
.GetPin())
69 , m_sync_contacts_check(0)
70 , m_sync_events_check(0)
71 , m_sync_notes_check(0)
72 , m_sync_todos_check(0)
77 // make sure there is at least one engine
78 if( !apiset
.os22() && !apiset
.os40() )
79 throw std::logic_error("Must have at least one engine in GroupCfgDlg");
84 // set window title to device PIN and name
85 string label
= "Configure Device - ";
86 label
+= m_device
.GetPin().Str();
87 if( m_device
.GetDeviceName().size() )
88 label
+= " (" + m_device
.GetDeviceName() + ")";
89 SetTitle(wxString(label
.c_str(), wxConvUTF8
));
91 // copy over the extras
92 // and initialize the engine / sync type map with config data
94 if( m_device
.GetExtras() ) {
95 const DeviceExtras
*extras
= m_device
.GetExtras();
96 m_favour_plugin_name
= extras
->m_favour_plugin_name
;
98 m_sync_types
[apiset
.os22()] = extras
->m_sync_types
;
99 m_sync_types
[apiset
.os40()] = extras
->m_sync_types
;
102 // default to all on, in worst case scenario
103 m_sync_types
[apiset
.os22()] = PST_ALL
;
104 m_sync_types
[apiset
.os40()] = PST_ALL
;
107 // initialize current engine pointer
108 if( m_device
.GetEngine() ) {
109 m_engine
= const_cast<OpenSync::API
*> (m_device
.GetEngine());
112 // initialize local group and plugin data
113 if( m_engine
&& m_device
.GetConfigGroup() ) {
114 const Config::Group
*group
= m_device
.GetConfigGroup();
115 // use existing group name, if available
116 m_group_name
= group
->GetGroupName();
118 // copy Barry plugin config, if available
119 if( group
->HasBarryPlugins() )
120 m_barry_plugin
= group
->GetBarryPlugin();
122 // copy non-Barry plugin config, if available
123 const Config::Plugin
*plugin
= group
->GetNonBarryPlugin();
125 appname
= plugin
->GetAppName();
126 m_plugins
[m_engine
][appname
].reset( plugin
->Clone() );
130 m_group_name
= "barrydesktop_" + m_device
.GetPin().Str();
133 SelectCurrentEngine();
135 SelectApplication(appname
);
138 if( m_app_count
== 0 ) {
139 wxMessageBox(_T("No supported applications found. You may need to install some opensync plugins."),
140 _T("No App Found"), wxOK
| wxICON_ERROR
, this);
144 void GroupCfgDlg::CreateLayout()
146 m_topsizer
= new wxBoxSizer(wxVERTICAL
);
147 AddEngineSizer(m_topsizer
);
148 AddConfigSizer(m_topsizer
);
149 AddSyncTypeSizer(m_topsizer
);
150 AddFavourSizer(m_topsizer
);
151 AddButtonSizer(m_topsizer
);
153 SetSizer(m_topsizer
);
154 m_topsizer
->SetSizeHints(this);
155 m_topsizer
->Layout();
158 void GroupCfgDlg::AddEngineSizer(wxSizer
*sizer
)
160 wxSizer
*engine
= new wxStaticBoxSizer(
161 new wxStaticBox(this, wxID_ANY
, _T("OpenSync Engine")),
165 wxArrayString engines
;
166 if( m_apiset
.os22() )
167 engines
.Add(wxString(m_apiset
.os22()->GetVersion(),wxConvUTF8
));
168 if( m_apiset
.os40() )
169 engines
.Add(wxString(m_apiset
.os40()->GetVersion(),wxConvUTF8
));
172 m_engine_combo
= new wxComboBox(this,
173 Dialog_GroupCfg_EngineCombo
, _T(""),
174 wxDefaultPosition
, wxSize(100, -1), engines
,
178 sizer
->Add(engine
, 0, wxTOP
| wxLEFT
| wxRIGHT
| wxEXPAND
, 10);
180 // if only one engine is available, don't bother showing the combo
181 if( !m_apiset
.os22() || !m_apiset
.os40() ) {
182 sizer
->Hide(engine
, true);
186 void GroupCfgDlg::AddConfigSizer(wxSizer
*sizer
)
188 wxSizer
*config
= new wxBoxSizer(wxHORIZONTAL
);
189 AddBarrySizer(config
);
192 sizer
->Add(config
, 1, wxTOP
| wxLEFT
| wxRIGHT
| wxEXPAND
, 10);
195 void GroupCfgDlg::AddBarrySizer(wxSizer
*sizer
)
197 wxSizer
*barry
= new wxStaticBoxSizer(
198 new wxStaticBox(this, wxID_ANY
, _T("Barry Config")),
202 wxSizer
*dname
= new wxBoxSizer(wxHORIZONTAL
);
204 new wxStaticText(this, wxID_ANY
, _T("Name:")),
205 0, wxALIGN_RIGHT
| wxALIGN_CENTRE_VERTICAL
, 2);
207 m_name_edit
= new wxTextCtrl(this, wxID_ANY
, _T("")),
209 barry
->Add(dname
, 0, wxALL
| wxEXPAND
, 5);
211 wxSizer
*password
= new wxBoxSizer(wxHORIZONTAL
);
213 new wxStaticText(this, wxID_ANY
, _T("Password:")),
214 0, wxALIGN_RIGHT
| wxALIGN_CENTRE_VERTICAL
, 2);
216 m_password_edit
= new wxTextCtrl(this, wxID_ANY
, _T(""),
217 wxDefaultPosition
, wxDefaultSize
, wxTE_PASSWORD
),
219 barry
->Add(password
, 0, wxALL
| wxEXPAND
, 5);
222 m_debug_check
= new wxCheckBox(this, wxID_ANY
,
223 _T("Debug output during sync")),
226 sizer
->Add(barry
, 0, wxRIGHT
| wxEXPAND
, 5);
229 void GroupCfgDlg::AddAppSizer(wxSizer
*sizer
)
231 m_appsizer
= new wxStaticBoxSizer(
232 new wxStaticBox(this, wxID_ANY
, _T("Application")),
236 UpdateAppSizer(false);
238 sizer
->Add(m_appsizer
, 0, wxLEFT
| wxEXPAND
, 5);
241 void GroupCfgDlg::UpdateAppSizer(bool relayout
)
244 m_appsizer
->Clear(true);
246 wxArrayString appnames
;
247 LoadAppNames(appnames
);
250 // FIXME - make size of combobox the size of the longest
251 // string in apps? using textextent calcs
253 m_app_combo
= new wxComboBox(this,
254 Dialog_GroupCfg_AppCombo
, _T(""),
255 wxDefaultPosition
, wxSize(200, -1), appnames
,
257 0, wxALL
| wxALIGN_CENTRE
, 5);
259 new wxButton(this, Dialog_GroupCfg_AppConfigButton
,
260 _T("&Configure...")),
261 0, wxALL
| wxALIGN_CENTRE
, 5);
263 // in case this is called after the dialog is already displayed,
264 // we need to readjust everything
266 m_topsizer
->Layout();
269 void GroupCfgDlg::LoadAppNames(wxArrayString
&appnames
)
271 // need to load app names based on engine plugin availability
272 // NOTE - do not load the Barry plugin, since that's already assumed
275 // no engine available
276 appnames
.Add(_T("No engine selected"));
280 string_list_type plugins
;
282 m_engine
->GetPluginNames(plugins
);
284 catch( std::exception
&e
) {
285 barrylog("Exception caught in LoadAppNames: " << e
.what());
289 // cycle through all available plugins, and add the ones
292 string_list_type::const_iterator i
= plugins
.begin();
293 for( ; i
!= plugins
.end(); ++i
) {
295 if( m_engine
->GetConverter().IsPluginSupported(*i
, &appname
) ) {
296 // found a supported plugin...
299 if( appname
== Config::Barry::AppName() )
302 appnames
.Add( wxString(appname
.c_str(), wxConvUTF8
) );
309 if( m_app_count
== 0 ) {
310 appnames
.Add(_T("No supported plugins available"));
315 void GroupCfgDlg::AddSyncTypeSizer(wxSizer
*sizer
)
317 wxStaticBoxSizer
*checks
= new wxStaticBoxSizer(wxHORIZONTAL
, this,
320 checks
->Add( m_sync_contacts_check
= new wxCheckBox(this,
321 Dialog_GroupCfg_ContactsCheck
, _T("Contacts")),
322 0, wxRIGHT
| wxEXPAND
, 10);
323 checks
->Add( m_sync_events_check
= new wxCheckBox(this,
324 Dialog_GroupCfg_EventsCheck
, _T("Events")),
325 0, wxRIGHT
| wxEXPAND
, 10);
326 checks
->Add( m_sync_notes_check
= new wxCheckBox(this,
327 Dialog_GroupCfg_NotesCheck
, _T("Notes")),
328 0, wxRIGHT
| wxEXPAND
, 10);
329 checks
->Add( m_sync_todos_check
= new wxCheckBox(this,
330 Dialog_GroupCfg_TodosCheck
, _T("To-dos")),
331 0, wxRIGHT
| wxEXPAND
, 10);
334 0, wxTOP
| wxLEFT
| wxRIGHT
| wxEXPAND
, 10);
337 void GroupCfgDlg::AddFavourSizer(wxSizer
*sizer
)
339 wxArrayString labels
;
340 labels
.Add( _T("Favour device") );
341 labels
.Add( _T("Favour application") );
342 labels
.Add( _T("Ask me") );
344 sizer
->Add( m_favour_radios
= new wxRadioBox(this, wxID_ANY
,
345 _T("To Resolve Conflicts:"),
346 wxDefaultPosition
, wxDefaultSize
,
347 labels
, 1, wxRA_SPECIFY_ROWS
),
348 0, wxTOP
| wxLEFT
| wxRIGHT
| wxEXPAND
, 10);
351 void GroupCfgDlg::AddButtonSizer(wxSizer
*sizer
)
353 wxSizer
*button
= CreateSeparatedButtonSizer(wxOK
| wxCANCEL
);
354 sizer
->Add(button
, 0, wxALL
| wxEXPAND
| wxALIGN_RIGHT
, 10);
357 void GroupCfgDlg::SelectCurrentEngine()
359 if( m_engine_combo
) {
361 m_engine
= m_apiset
.os22() ?
362 m_apiset
.os22() : m_apiset
.os40();
366 m_engine_combo
->SetValue(
367 wxString(m_engine
->GetVersion(), wxConvUTF8
));
373 void GroupCfgDlg::LoadBarryConfig()
375 Config::Barry
&bp
= m_barry_plugin
;
377 wxString
dname(wxGetApp().GetDeviceName(bp
.GetPin()).c_str(), wxConvUTF8
);
379 m_name_edit
->SetValue(dname
);
380 m_password_edit
->SetValue(wxString(bp
.GetPassword().c_str(), wxConvUTF8
));
381 m_debug_check
->SetValue( bp
.IsDebugMode() );
384 void GroupCfgDlg::SelectApplication(const std::string appname
)
386 m_app_combo
->SetValue(wxString(appname
.c_str(), wxConvUTF8
));
390 void GroupCfgDlg::SelectSyncTypes()
393 SetSyncTypeChecks(PST_NONE
);
394 EnableSyncTypeChecks(PST_NONE
);
398 string app
= GetCurrentAppName();
399 plugin_ptr ap
= GetCurrentPlugin();
401 // calculate the supported sync types
402 // Note: we could also take the Barry plugin config into
403 // consideration here, but so far, we just use the
404 // opensync group config
405 pst_type supported
= PST_NONE
;
407 supported
= m_barry_plugin
.GetSupportedSyncTypes(*m_engine
)
408 & ap
->GetSupportedSyncTypes(*m_engine
);
411 // make sure our current selection is limited by our new
412 // set of supported plugins
413 m_sync_types
[m_engine
] &= supported
;
415 // enable the checkboxes according to our ability
416 EnableSyncTypeChecks(supported
);
418 // set the checkboxes according to our choices
419 SetSyncTypeChecks(m_sync_types
[m_engine
]);
422 void GroupCfgDlg::SelectFavour()
425 m_favour_plugin_name
== Config::Barry::PluginName(*m_engine
) )
427 m_favour_radios
->SetSelection(0);
429 else if( m_engine
&& m_favour_plugin_name
.size() ) {
430 m_favour_radios
->SetSelection(1);
434 m_favour_radios
->SetSelection(2);
438 void GroupCfgDlg::EnableSyncTypeChecks(pst_type types
)
440 m_sync_contacts_check
->Enable( types
& PST_CONTACTS
);
441 m_sync_events_check
->Enable( types
& PST_EVENTS
);
442 m_sync_notes_check
->Enable( types
& PST_NOTES
);
443 m_sync_todos_check
->Enable( types
& PST_TODOS
);
446 void GroupCfgDlg::SetSyncTypeChecks(pst_type types
)
448 m_sync_contacts_check
->SetValue( types
& PST_CONTACTS
);
449 m_sync_events_check
->SetValue( types
& PST_EVENTS
);
450 m_sync_notes_check
->SetValue( types
& PST_NOTES
);
451 m_sync_todos_check
->SetValue( types
& PST_TODOS
);
454 GroupCfgDlg::pst_type
GroupCfgDlg::GetSyncTypeChecks()
456 pst_type types
= PST_NONE
;
457 if( m_sync_contacts_check
->GetValue() ) types
|= PST_CONTACTS
;
458 if( m_sync_events_check
->GetValue() ) types
|= PST_EVENTS
;
459 if( m_sync_notes_check
->GetValue() ) types
|= PST_NOTES
;
460 if( m_sync_todos_check
->GetValue() ) types
|= PST_TODOS
;
464 std::string
GroupCfgDlg::GetCurrentAppName() const
466 wxString app
= m_app_combo
->GetValue();
467 return std::string(app
.utf8_str());
470 GroupCfgDlg::plugin_ptr
GroupCfgDlg::GetCurrentPlugin()
472 string appname
= GetCurrentAppName();
473 appcfg_map
&cfgs
= m_plugins
[m_engine
];
474 appcfg_map::iterator pi
= cfgs
.find(appname
);
475 if( pi
!= cfgs
.end() )
478 return plugin_ptr(); // not found, return empty ptr
481 void GroupCfgDlg::OnConfigureApp(wxCommandEvent
&event
)
483 string app
= GetCurrentAppName();
484 if( app
.size() == 0 ) {
485 wxMessageBox(_T("Please select an application."),
486 _T("Application Config"), wxOK
| wxICON_ERROR
, this);
490 ConfigUI::ptr ui
= ConfigUI::CreateConfigUI(app
);
493 wxMessageBox(_T("No configuration interface available for this Application."),
494 _T("Application Config"),
495 wxOK
| wxICON_ERROR
, this);
499 if( ui
->Configure(this, GetCurrentPlugin()) ) {
500 ConfigUI::plugin_ptr plugin
= ui
->GetPlugin();
502 m_plugins
[m_engine
][app
] = plugin
;
504 // if this is the first time, default to all
505 if( m_sync_types
[m_engine
] == PST_NONE
)
506 m_sync_types
[m_engine
] = PST_ALL
;
508 // update the types checkboxes
514 void GroupCfgDlg::OnEngineComboChange(wxCommandEvent
&event
)
516 // remember what plugin we're using
517 plugin_ptr old_app
= GetCurrentPlugin();
519 // update engine pointer
520 wxString newEngine
= m_engine_combo
->GetValue();
521 if( m_apiset
.os22() && newEngine
== wxString(m_apiset
.os22()->GetVersion(), wxConvUTF8
) ) {
522 m_engine
= m_apiset
.os22();
524 else if( m_apiset
.os40() && newEngine
== wxString(m_apiset
.os40()->GetVersion(), wxConvUTF8
) ) {
525 m_engine
= m_apiset
.os40();
528 // update the application list
531 // if plugin can be configured in new engine, keep our current
532 // config, otherwise, reset
533 if( old_app
.get() && m_engine
->GetConverter().IsPluginSupported(old_app
->GetPluginName(*m_engine
)) ) {
534 // update the app list
535 SelectApplication(old_app
->GetAppName());
538 // leave GUI as is, and zap our plugin data
539 SelectApplication("");
543 void GroupCfgDlg::OnAppComboChange(wxCommandEvent
&event
)
548 void GroupCfgDlg::OnSyncTypeCheck(wxCommandEvent
&event
)
553 m_sync_types
[m_engine
] = GetSyncTypeChecks();
556 bool GroupCfgDlg::TransferDataFromWindow()
558 // engine must be set!
560 wxMessageBox(_T("Please select an engine."),
561 _T("Device Config"), wxOK
| wxICON_ERROR
, this);
565 // make sure the Barry plugin is configured
566 if( !m_barry_plugin
.IsConfigured(*m_engine
) ) {
567 wxMessageBox(_T("Barry doesn't have a PIN number. This should never happen."),
568 _T("Device Config"), wxOK
| wxICON_ERROR
, this);
572 // make sure the application plugin is configured
573 plugin_ptr app
= GetCurrentPlugin();
574 if( !app
.get() || !app
->IsConfigured(*m_engine
) ) {
575 // the app hasn't been configured yet, do it automatically
576 wxCommandEvent event
;
577 OnConfigureApp(event
);
579 app
= GetCurrentPlugin();
580 if( !app
.get() || !app
->IsConfigured(*m_engine
) ) {
581 wxMessageBox(_T("The application plugin is not fully configured."),
582 _T("Application Config"), wxOK
| wxICON_ERROR
, this);
587 // copy over barry specific settings
588 m_device_name
= string(m_name_edit
->GetValue().utf8_str());
589 m_barry_plugin
.SetPassword(string(m_password_edit
->GetValue().utf8_str()));
590 m_barry_plugin
.DebugMode(m_debug_check
->GetValue());
592 // make sure conflict resolution is known
593 int findex
= m_favour_radios
->GetSelection();
596 case 0: // Favour device
597 m_favour_plugin_name
= Config::Barry::PluginName(*m_engine
);
600 case 1: // Favour application
601 m_favour_plugin_name
= app
->GetPluginName(*m_engine
);
605 m_favour_plugin_name
.clear();
609 wxMessageBox(_T("Please select conflict resolution method."),
610 _T("Conflict Resolution"), wxOK
| wxICON_ERROR
, this);
614 // save the new device name
615 wxGetApp().SetDeviceName(m_barry_plugin
.GetPin(), m_device_name
);
617 // save the sync type checkboxes
618 m_sync_types
[m_engine
] = GetSyncTypeChecks();
623 int GroupCfgDlg::ShowModal()
625 int status
= wxDialog::ShowModal();
626 plugin_ptr app
= GetCurrentPlugin();
627 if( status
== wxID_OK
&& app
.get() ) {
628 // construct a new group from user's results
629 m_group
.reset( new Config::Group(m_group_name
) );
630 m_group
->AddPlugin( m_barry_plugin
.Clone() );
631 m_group
->AddPlugin( app
->Clone() );
633 // don't forget the extras
634 m_extras
.reset( new DeviceExtras(m_barry_plugin
.GetPin()) );
635 m_extras
->m_favour_plugin_name
= m_favour_plugin_name
;
636 m_extras
->m_sync_types
= m_sync_types
[m_engine
];