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 // use m_device here, since BarryDesktopApp::GetDeviceName()
378 // may return an empty string if the device is not currently
380 wxString
dname(m_device
.GetDeviceName().c_str(), wxConvUTF8
);
382 m_name_edit
->SetValue(dname
);
383 m_password_edit
->SetValue(wxString(bp
.GetPassword().c_str(), wxConvUTF8
));
384 m_debug_check
->SetValue( bp
.IsDebugMode() );
387 void GroupCfgDlg::SelectApplication(const std::string appname
)
389 m_app_combo
->SetValue(wxString(appname
.c_str(), wxConvUTF8
));
393 void GroupCfgDlg::SelectSyncTypes()
396 SetSyncTypeChecks(PST_NONE
);
397 EnableSyncTypeChecks(PST_NONE
);
401 string app
= GetCurrentAppName();
402 plugin_ptr ap
= GetCurrentPlugin();
404 // calculate the supported sync types
405 // Note: we could also take the Barry plugin config into
406 // consideration here, but so far, we just use the
407 // opensync group config
408 pst_type supported
= PST_NONE
;
410 supported
= m_barry_plugin
.GetSupportedSyncTypes(*m_engine
)
411 & ap
->GetSupportedSyncTypes(*m_engine
);
414 // make sure our current selection is limited by our new
415 // set of supported plugins
416 m_sync_types
[m_engine
] &= supported
;
418 // enable the checkboxes according to our ability
419 EnableSyncTypeChecks(supported
);
421 // set the checkboxes according to our choices
422 SetSyncTypeChecks(m_sync_types
[m_engine
]);
425 void GroupCfgDlg::SelectFavour()
428 m_favour_plugin_name
== Config::Barry::PluginName(*m_engine
) )
430 m_favour_radios
->SetSelection(0);
432 else if( m_engine
&& m_favour_plugin_name
.size() ) {
433 m_favour_radios
->SetSelection(1);
437 m_favour_radios
->SetSelection(2);
441 void GroupCfgDlg::EnableSyncTypeChecks(pst_type types
)
443 m_sync_contacts_check
->Enable( types
& PST_CONTACTS
);
444 m_sync_events_check
->Enable( types
& PST_EVENTS
);
445 m_sync_notes_check
->Enable( types
& PST_NOTES
);
446 m_sync_todos_check
->Enable( types
& PST_TODOS
);
449 void GroupCfgDlg::SetSyncTypeChecks(pst_type types
)
451 m_sync_contacts_check
->SetValue( types
& PST_CONTACTS
);
452 m_sync_events_check
->SetValue( types
& PST_EVENTS
);
453 m_sync_notes_check
->SetValue( types
& PST_NOTES
);
454 m_sync_todos_check
->SetValue( types
& PST_TODOS
);
457 GroupCfgDlg::pst_type
GroupCfgDlg::GetSyncTypeChecks()
459 pst_type types
= PST_NONE
;
460 if( m_sync_contacts_check
->GetValue() ) types
|= PST_CONTACTS
;
461 if( m_sync_events_check
->GetValue() ) types
|= PST_EVENTS
;
462 if( m_sync_notes_check
->GetValue() ) types
|= PST_NOTES
;
463 if( m_sync_todos_check
->GetValue() ) types
|= PST_TODOS
;
467 std::string
GroupCfgDlg::GetCurrentAppName() const
469 wxString app
= m_app_combo
->GetValue();
470 return std::string(app
.utf8_str());
473 GroupCfgDlg::plugin_ptr
GroupCfgDlg::GetCurrentPlugin()
475 string appname
= GetCurrentAppName();
476 appcfg_map
&cfgs
= m_plugins
[m_engine
];
477 appcfg_map::iterator pi
= cfgs
.find(appname
);
478 if( pi
!= cfgs
.end() )
481 return plugin_ptr(); // not found, return empty ptr
484 void GroupCfgDlg::OnConfigureApp(wxCommandEvent
&event
)
486 string app
= GetCurrentAppName();
487 if( app
.size() == 0 ) {
488 wxMessageBox(_T("Please select an application."),
489 _T("Application Config"), wxOK
| wxICON_ERROR
, this);
493 ConfigUI::ptr ui
= ConfigUI::CreateConfigUI(app
);
496 wxMessageBox(_T("No configuration interface available for this Application."),
497 _T("Application Config"),
498 wxOK
| wxICON_ERROR
, this);
502 if( ui
->Configure(this, GetCurrentPlugin()) ) {
503 ConfigUI::plugin_ptr plugin
= ui
->GetPlugin();
505 m_plugins
[m_engine
][app
] = plugin
;
507 // if this is the first time, default to all
508 if( m_sync_types
[m_engine
] == PST_NONE
)
509 m_sync_types
[m_engine
] = PST_ALL
;
511 // update the types checkboxes
517 void GroupCfgDlg::OnEngineComboChange(wxCommandEvent
&event
)
519 // remember what plugin we're using
520 plugin_ptr old_app
= GetCurrentPlugin();
522 // update engine pointer
523 wxString newEngine
= m_engine_combo
->GetValue();
524 if( m_apiset
.os22() && newEngine
== wxString(m_apiset
.os22()->GetVersion(), wxConvUTF8
) ) {
525 m_engine
= m_apiset
.os22();
527 else if( m_apiset
.os40() && newEngine
== wxString(m_apiset
.os40()->GetVersion(), wxConvUTF8
) ) {
528 m_engine
= m_apiset
.os40();
531 // update the application list
534 // if plugin can be configured in new engine, keep our current
535 // config, otherwise, reset
536 if( old_app
.get() && m_engine
->GetConverter().IsPluginSupported(old_app
->GetPluginName(*m_engine
)) ) {
537 // update the app list
538 SelectApplication(old_app
->GetAppName());
541 // leave GUI as is, and zap our plugin data
542 SelectApplication("");
546 void GroupCfgDlg::OnAppComboChange(wxCommandEvent
&event
)
551 void GroupCfgDlg::OnSyncTypeCheck(wxCommandEvent
&event
)
556 m_sync_types
[m_engine
] = GetSyncTypeChecks();
559 bool GroupCfgDlg::TransferDataFromWindow()
561 // engine must be set!
563 wxMessageBox(_T("Please select an engine."),
564 _T("Device Config"), wxOK
| wxICON_ERROR
, this);
568 // make sure the Barry plugin is configured
569 if( !m_barry_plugin
.IsConfigured(*m_engine
) ) {
570 wxMessageBox(_T("Barry doesn't have a PIN number. This should never happen."),
571 _T("Device Config"), wxOK
| wxICON_ERROR
, this);
575 // make sure the application plugin is configured
576 plugin_ptr app
= GetCurrentPlugin();
577 if( !app
.get() || !app
->IsConfigured(*m_engine
) ) {
578 // the app hasn't been configured yet, do it automatically
579 wxCommandEvent event
;
580 OnConfigureApp(event
);
582 app
= GetCurrentPlugin();
583 if( !app
.get() || !app
->IsConfigured(*m_engine
) ) {
584 wxMessageBox(_T("The application plugin is not fully configured."),
585 _T("Application Config"), wxOK
| wxICON_ERROR
, this);
590 // copy over barry specific settings
591 m_device_name
= string(m_name_edit
->GetValue().utf8_str());
592 m_barry_plugin
.SetPassword(string(m_password_edit
->GetValue().utf8_str()));
593 m_barry_plugin
.DebugMode(m_debug_check
->GetValue());
595 // make sure conflict resolution is known
596 int findex
= m_favour_radios
->GetSelection();
599 case 0: // Favour device
600 m_favour_plugin_name
= Config::Barry::PluginName(*m_engine
);
603 case 1: // Favour application
604 m_favour_plugin_name
= app
->GetPluginName(*m_engine
);
608 m_favour_plugin_name
.clear();
612 wxMessageBox(_T("Please select conflict resolution method."),
613 _T("Conflict Resolution"), wxOK
| wxICON_ERROR
, this);
617 // save the new device name
618 wxGetApp().SetDeviceName(m_barry_plugin
.GetPin(), m_device_name
);
620 // save the sync type checkboxes
621 m_sync_types
[m_engine
] = GetSyncTypeChecks();
626 int GroupCfgDlg::ShowModal()
628 int status
= wxDialog::ShowModal();
629 plugin_ptr app
= GetCurrentPlugin();
630 if( status
== wxID_OK
&& app
.get() ) {
631 // construct a new group from user's results
632 m_group
.reset( new Config::Group(m_group_name
) );
633 m_group
->AddPlugin( m_barry_plugin
.Clone() );
634 m_group
->AddPlugin( app
->Clone() );
636 // don't forget the extras
637 m_extras
.reset( new DeviceExtras(m_barry_plugin
.GetPin()) );
638 m_extras
->m_favour_plugin_name
= m_favour_plugin_name
;
639 m_extras
->m_sync_types
= m_sync_types
[m_engine
];