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"
32 using namespace OpenSync
;
34 BEGIN_EVENT_TABLE(GroupCfgDlg
, wxDialog
)
35 EVT_BUTTON (Dialog_GroupCfg_AppConfigButton
,
36 GroupCfgDlg::OnConfigureApp
)
37 EVT_CHECKBOX (Dialog_GroupCfg_ContactsCheck
,
38 GroupCfgDlg::OnSyncTypeCheck
)
39 EVT_CHECKBOX (Dialog_GroupCfg_EventsCheck
,
40 GroupCfgDlg::OnSyncTypeCheck
)
41 EVT_CHECKBOX (Dialog_GroupCfg_NotesCheck
,
42 GroupCfgDlg::OnSyncTypeCheck
)
43 EVT_CHECKBOX (Dialog_GroupCfg_TodosCheck
,
44 GroupCfgDlg::OnSyncTypeCheck
)
45 EVT_TEXT (Dialog_GroupCfg_EngineCombo
,
46 GroupCfgDlg::OnEngineComboChange
)
47 EVT_TEXT (Dialog_GroupCfg_AppCombo
,
48 GroupCfgDlg::OnAppComboChange
)
51 //////////////////////////////////////////////////////////////////////////////
54 GroupCfgDlg::GroupCfgDlg(wxWindow
*parent
,
55 const DeviceEntry
&device
,
56 OpenSync::APISet
&apiset
)
57 : wxDialog(parent
, Dialog_GroupCfg
, _W("Device Sync Configuration"))
62 , m_barry_plugin(m_device
.GetPin())
70 , m_sync_contacts_check(0)
71 , m_sync_events_check(0)
72 , m_sync_notes_check(0)
73 , m_sync_todos_check(0)
78 // make sure there is at least one engine
79 if( !apiset
.os22() && !apiset
.os40() )
80 throw std::logic_error(_C("Must have at least one engine in GroupCfgDlg"));
85 // set window title to device PIN and name
86 string label
= _C("Configure Device - ");
87 label
+= m_device
.GetPin().Str();
88 if( m_device
.GetDeviceName().size() )
89 label
+= " (" + m_device
.GetDeviceName() + ")";
90 SetTitle(wxString(label
.c_str(), wxConvUTF8
));
92 // copy over the extras
93 // and initialize the engine / sync type map with config data
95 if( m_device
.GetExtras() ) {
96 const DeviceExtras
*extras
= m_device
.GetExtras();
97 m_favour_plugin_name
= extras
->m_favour_plugin_name
;
99 m_sync_types
[apiset
.os22()] = extras
->m_sync_types
;
100 m_sync_types
[apiset
.os40()] = extras
->m_sync_types
;
103 // default to all on, in worst case scenario
104 m_sync_types
[apiset
.os22()] = PST_ALL
;
105 m_sync_types
[apiset
.os40()] = PST_ALL
;
108 // initialize current engine pointer
109 if( m_device
.GetEngine() ) {
110 m_engine
= const_cast<OpenSync::API
*> (m_device
.GetEngine());
113 // initialize local group and plugin data
114 if( m_engine
&& m_device
.GetConfigGroup() ) {
115 const Config::Group
*group
= m_device
.GetConfigGroup();
116 // use existing group name, if available
117 m_group_name
= group
->GetGroupName();
119 // copy Barry plugin config, if available
120 if( group
->HasBarryPlugins() )
121 m_barry_plugin
= group
->GetBarryPlugin();
123 // copy non-Barry plugin config, if available
124 const Config::Plugin
*plugin
= group
->GetNonBarryPlugin();
126 appname
= plugin
->GetAppName();
127 m_plugins
[m_engine
][appname
].reset( plugin
->Clone() );
131 m_group_name
= "barrydesktop_" + m_device
.GetPin().Str();
134 SelectCurrentEngine();
136 SelectApplication(appname
);
139 if( m_app_count
== 0 ) {
140 wxMessageBox(_W("No supported applications found. You may need to install some opensync plugins."),
141 _W("No App Found"), wxOK
| wxICON_ERROR
, this);
145 void GroupCfgDlg::CreateLayout()
147 m_topsizer
= new wxBoxSizer(wxVERTICAL
);
148 AddEngineSizer(m_topsizer
);
149 AddConfigSizer(m_topsizer
);
150 AddSyncTypeSizer(m_topsizer
);
151 AddFavourSizer(m_topsizer
);
152 AddButtonSizer(m_topsizer
);
154 SetSizer(m_topsizer
);
155 m_topsizer
->SetSizeHints(this);
156 m_topsizer
->Layout();
159 void GroupCfgDlg::AddEngineSizer(wxSizer
*sizer
)
161 wxSizer
*engine
= new wxStaticBoxSizer(
162 new wxStaticBox(this, wxID_ANY
, _W("OpenSync Engine")),
166 wxArrayString engines
;
167 if( m_apiset
.os22() )
168 engines
.Add(wxString(m_apiset
.os22()->GetVersion(),wxConvUTF8
));
169 if( m_apiset
.os40() )
170 engines
.Add(wxString(m_apiset
.os40()->GetVersion(),wxConvUTF8
));
173 m_engine_combo
= new wxComboBox(this,
174 Dialog_GroupCfg_EngineCombo
, _T(""),
175 wxDefaultPosition
, wxSize(100, -1), engines
,
179 sizer
->Add(engine
, 0, wxTOP
| wxLEFT
| wxRIGHT
| wxEXPAND
, 10);
181 // if only one engine is available, don't bother showing the combo
182 if( !m_apiset
.os22() || !m_apiset
.os40() ) {
183 sizer
->Hide(engine
, true);
187 void GroupCfgDlg::AddConfigSizer(wxSizer
*sizer
)
189 wxSizer
*config
= new wxBoxSizer(wxHORIZONTAL
);
190 AddBarrySizer(config
);
193 sizer
->Add(config
, 1, wxTOP
| wxLEFT
| wxRIGHT
| wxEXPAND
, 10);
196 void GroupCfgDlg::AddBarrySizer(wxSizer
*sizer
)
198 wxSizer
*barry
= new wxStaticBoxSizer(
199 new wxStaticBox(this, wxID_ANY
, _W("Barry Config")),
203 wxSizer
*dname
= new wxBoxSizer(wxHORIZONTAL
);
205 new wxStaticText(this, wxID_ANY
, _W("Name:")),
206 0, wxALIGN_RIGHT
| wxALIGN_CENTRE_VERTICAL
, 2);
208 m_name_edit
= new wxTextCtrl(this, wxID_ANY
, _T("")),
210 barry
->Add(dname
, 0, wxALL
| wxEXPAND
, 5);
212 wxSizer
*password
= new wxBoxSizer(wxHORIZONTAL
);
214 new wxStaticText(this, wxID_ANY
, _W("Password:")),
215 0, wxALIGN_RIGHT
| wxALIGN_CENTRE_VERTICAL
, 2);
217 m_password_edit
= new wxTextCtrl(this, wxID_ANY
, _T(""),
218 wxDefaultPosition
, wxDefaultSize
, wxTE_PASSWORD
),
220 barry
->Add(password
, 0, wxALL
| wxEXPAND
, 5);
223 m_debug_check
= new wxCheckBox(this, wxID_ANY
,
224 _W("Debug output during sync")),
227 sizer
->Add(barry
, 0, wxRIGHT
| wxEXPAND
, 5);
230 void GroupCfgDlg::AddAppSizer(wxSizer
*sizer
)
232 m_appsizer
= new wxStaticBoxSizer(
233 new wxStaticBox(this, wxID_ANY
, _W("Application")),
237 UpdateAppSizer(false);
239 sizer
->Add(m_appsizer
, 0, wxLEFT
| wxEXPAND
, 5);
242 void GroupCfgDlg::UpdateAppSizer(bool relayout
)
245 m_appsizer
->Clear(true);
247 wxArrayString appnames
;
248 LoadAppNames(appnames
);
251 // FIXME - make size of combobox the size of the longest
252 // string in apps? using textextent calcs
254 m_app_combo
= new wxComboBox(this,
255 Dialog_GroupCfg_AppCombo
, _T(""),
256 wxDefaultPosition
, wxSize(200, -1), appnames
,
258 0, wxALL
| wxALIGN_CENTRE
, 5);
260 new wxButton(this, Dialog_GroupCfg_AppConfigButton
,
261 _W("&Configure...")),
262 0, wxALL
| wxALIGN_CENTRE
, 5);
264 // in case this is called after the dialog is already displayed,
265 // we need to readjust everything
267 m_topsizer
->Layout();
270 void GroupCfgDlg::LoadAppNames(wxArrayString
&appnames
)
272 // need to load app names based on engine plugin availability
273 // NOTE - do not load the Barry plugin, since that's already assumed
276 // no engine available
277 appnames
.Add(_W("No engine selected"));
281 string_list_type plugins
;
283 m_engine
->GetPluginNames(plugins
);
285 catch( std::exception
&e
) {
286 barrylog(_C("Exception caught in LoadAppNames: ") << e
.what());
290 // cycle through all available plugins, and add the ones
293 string_list_type::const_iterator i
= plugins
.begin();
294 for( ; i
!= plugins
.end(); ++i
) {
296 if( m_engine
->GetConverter().IsPluginSupported(*i
, &appname
) ) {
297 // found a supported plugin...
300 if( appname
== Config::Barry::AppName() )
303 appnames
.Add( wxString(appname
.c_str(), wxConvUTF8
) );
310 if( m_app_count
== 0 ) {
311 appnames
.Add(_W("No supported plugins available"));
316 void GroupCfgDlg::AddSyncTypeSizer(wxSizer
*sizer
)
318 wxStaticBoxSizer
*checks
= new wxStaticBoxSizer(wxHORIZONTAL
, this,
321 checks
->Add( m_sync_contacts_check
= new wxCheckBox(this,
322 Dialog_GroupCfg_ContactsCheck
, _W("Contacts")),
323 0, wxRIGHT
| wxEXPAND
, 10);
324 checks
->Add( m_sync_events_check
= new wxCheckBox(this,
325 Dialog_GroupCfg_EventsCheck
, _W("Events")),
326 0, wxRIGHT
| wxEXPAND
, 10);
327 checks
->Add( m_sync_notes_check
= new wxCheckBox(this,
328 Dialog_GroupCfg_NotesCheck
, _W("Notes")),
329 0, wxRIGHT
| wxEXPAND
, 10);
330 checks
->Add( m_sync_todos_check
= new wxCheckBox(this,
331 Dialog_GroupCfg_TodosCheck
, _W("To-dos")),
332 0, wxRIGHT
| wxEXPAND
, 10);
335 0, wxTOP
| wxLEFT
| wxRIGHT
| wxEXPAND
, 10);
338 void GroupCfgDlg::AddFavourSizer(wxSizer
*sizer
)
340 wxArrayString labels
;
341 // TRANSLATORS: these 3 strings are options for default
342 // conflict resolution during syncing
343 labels
.Add( _W("Favour device") );
344 labels
.Add( _W("Favour application") );
345 labels
.Add( _W("Ask me") );
347 sizer
->Add( m_favour_radios
= new wxRadioBox(this, wxID_ANY
,
348 _W("To Resolve Conflicts:"),
349 wxDefaultPosition
, wxDefaultSize
,
350 labels
, 1, wxRA_SPECIFY_ROWS
),
351 0, wxTOP
| wxLEFT
| wxRIGHT
| wxEXPAND
, 10);
354 void GroupCfgDlg::AddButtonSizer(wxSizer
*sizer
)
356 wxSizer
*button
= CreateSeparatedButtonSizer(wxOK
| wxCANCEL
);
357 sizer
->Add(button
, 0, wxALL
| wxEXPAND
| wxALIGN_RIGHT
, 10);
360 void GroupCfgDlg::SelectCurrentEngine()
362 if( m_engine_combo
) {
364 m_engine
= m_apiset
.os22() ?
365 m_apiset
.os22() : m_apiset
.os40();
369 m_engine_combo
->SetValue(
370 wxString(m_engine
->GetVersion(), wxConvUTF8
));
376 void GroupCfgDlg::LoadBarryConfig()
378 Config::Barry
&bp
= m_barry_plugin
;
380 // use m_device here, since BarryDesktopApp::GetDeviceName()
381 // may return an empty string if the device is not currently
383 wxString
dname(m_device
.GetDeviceName().c_str(), wxConvUTF8
);
385 m_name_edit
->SetValue(dname
);
386 m_password_edit
->SetValue(wxString(bp
.GetPassword().c_str(), wxConvUTF8
));
387 m_debug_check
->SetValue( bp
.IsDebugMode() );
390 void GroupCfgDlg::SelectApplication(const std::string appname
)
392 m_app_combo
->SetValue(wxString(appname
.c_str(), wxConvUTF8
));
396 void GroupCfgDlg::SelectSyncTypes()
399 SetSyncTypeChecks(PST_NONE
);
400 EnableSyncTypeChecks(PST_NONE
);
404 string app
= GetCurrentAppName();
405 plugin_ptr ap
= GetCurrentPlugin();
407 // calculate the supported sync types
408 // Note: we could also take the Barry plugin config into
409 // consideration here, but so far, we just use the
410 // opensync group config
411 pst_type supported
= PST_NONE
;
413 supported
= m_barry_plugin
.GetSupportedSyncTypes(*m_engine
)
414 & ap
->GetSupportedSyncTypes(*m_engine
);
417 // make sure our current selection is limited by our new
418 // set of supported plugins
419 m_sync_types
[m_engine
] &= supported
;
421 // enable the checkboxes according to our ability
422 EnableSyncTypeChecks(supported
);
424 // set the checkboxes according to our choices
425 SetSyncTypeChecks(m_sync_types
[m_engine
]);
428 void GroupCfgDlg::SelectFavour()
431 m_favour_plugin_name
== Config::Barry::PluginName(*m_engine
) )
433 m_favour_radios
->SetSelection(0);
435 else if( m_engine
&& m_favour_plugin_name
.size() ) {
436 m_favour_radios
->SetSelection(1);
440 m_favour_radios
->SetSelection(2);
444 void GroupCfgDlg::EnableSyncTypeChecks(pst_type types
)
446 m_sync_contacts_check
->Enable( types
& PST_CONTACTS
);
447 m_sync_events_check
->Enable( types
& PST_EVENTS
);
448 m_sync_notes_check
->Enable( types
& PST_NOTES
);
449 m_sync_todos_check
->Enable( types
& PST_TODOS
);
452 void GroupCfgDlg::SetSyncTypeChecks(pst_type types
)
454 m_sync_contacts_check
->SetValue( types
& PST_CONTACTS
);
455 m_sync_events_check
->SetValue( types
& PST_EVENTS
);
456 m_sync_notes_check
->SetValue( types
& PST_NOTES
);
457 m_sync_todos_check
->SetValue( types
& PST_TODOS
);
460 GroupCfgDlg::pst_type
GroupCfgDlg::GetSyncTypeChecks()
462 pst_type types
= PST_NONE
;
463 if( m_sync_contacts_check
->GetValue() ) types
|= PST_CONTACTS
;
464 if( m_sync_events_check
->GetValue() ) types
|= PST_EVENTS
;
465 if( m_sync_notes_check
->GetValue() ) types
|= PST_NOTES
;
466 if( m_sync_todos_check
->GetValue() ) types
|= PST_TODOS
;
470 std::string
GroupCfgDlg::GetCurrentAppName() const
472 wxString app
= m_app_combo
->GetValue();
473 return std::string(app
.utf8_str());
476 GroupCfgDlg::plugin_ptr
GroupCfgDlg::GetCurrentPlugin()
478 string appname
= GetCurrentAppName();
479 appcfg_map
&cfgs
= m_plugins
[m_engine
];
480 appcfg_map::iterator pi
= cfgs
.find(appname
);
481 if( pi
!= cfgs
.end() )
484 return plugin_ptr(); // not found, return empty ptr
487 void GroupCfgDlg::OnConfigureApp(wxCommandEvent
&event
)
489 string app
= GetCurrentAppName();
490 if( app
.size() == 0 ) {
491 wxMessageBox(_W("Please select an application."),
492 _W("Application Config"), wxOK
| wxICON_ERROR
, this);
496 ConfigUI::ptr ui
= ConfigUI::CreateConfigUI(app
);
499 wxMessageBox(_W("No configuration interface available for this Application."),
500 _W("Application Config"),
501 wxOK
| wxICON_ERROR
, this);
505 if( ui
->Configure(this, GetCurrentPlugin()) ) {
506 ConfigUI::plugin_ptr plugin
= ui
->GetPlugin();
508 m_plugins
[m_engine
][app
] = plugin
;
510 // if this is the first time, default to all
511 if( m_sync_types
[m_engine
] == PST_NONE
)
512 m_sync_types
[m_engine
] = PST_ALL
;
514 // update the types checkboxes
520 void GroupCfgDlg::OnEngineComboChange(wxCommandEvent
&event
)
522 // remember what plugin we're using
523 plugin_ptr old_app
= GetCurrentPlugin();
525 // update engine pointer
526 wxString newEngine
= m_engine_combo
->GetValue();
527 if( m_apiset
.os22() && newEngine
== wxString(m_apiset
.os22()->GetVersion(), wxConvUTF8
) ) {
528 m_engine
= m_apiset
.os22();
530 else if( m_apiset
.os40() && newEngine
== wxString(m_apiset
.os40()->GetVersion(), wxConvUTF8
) ) {
531 m_engine
= m_apiset
.os40();
534 // update the application list
537 // if plugin can be configured in new engine, keep our current
538 // config, otherwise, reset
539 if( old_app
.get() && m_engine
->GetConverter().IsPluginSupported(old_app
->GetPluginName(*m_engine
)) ) {
540 // update the app list
541 SelectApplication(old_app
->GetAppName());
544 // leave GUI as is, and zap our plugin data
545 SelectApplication("");
549 void GroupCfgDlg::OnAppComboChange(wxCommandEvent
&event
)
554 void GroupCfgDlg::OnSyncTypeCheck(wxCommandEvent
&event
)
559 m_sync_types
[m_engine
] = GetSyncTypeChecks();
562 bool GroupCfgDlg::TransferDataFromWindow()
564 // engine must be set!
566 wxMessageBox(_W("Please select an engine."),
567 _W("Device Config"), wxOK
| wxICON_ERROR
, this);
571 // make sure the Barry plugin is configured
572 if( !m_barry_plugin
.IsConfigured(*m_engine
) ) {
573 wxMessageBox(_W("Barry doesn't have a PIN number. This should never happen."),
574 _W("Device Config"), wxOK
| wxICON_ERROR
, this);
578 // make sure the application plugin is configured
579 plugin_ptr app
= GetCurrentPlugin();
580 if( !app
.get() || !app
->IsConfigured(*m_engine
) ) {
581 // the app hasn't been configured yet, do it automatically
582 wxCommandEvent event
;
583 OnConfigureApp(event
);
585 app
= GetCurrentPlugin();
586 if( !app
.get() || !app
->IsConfigured(*m_engine
) ) {
587 wxMessageBox(_W("The application plugin is not fully configured."),
588 _W("Application Config"), wxOK
| wxICON_ERROR
, this);
593 // copy over barry specific settings
594 m_device_name
= string(m_name_edit
->GetValue().utf8_str());
595 m_barry_plugin
.SetPassword(string(m_password_edit
->GetValue().utf8_str()));
596 m_barry_plugin
.DebugMode(m_debug_check
->GetValue());
598 // make sure conflict resolution is known
599 int findex
= m_favour_radios
->GetSelection();
602 case 0: // Favour device
603 m_favour_plugin_name
= Config::Barry::PluginName(*m_engine
);
606 case 1: // Favour application
607 m_favour_plugin_name
= app
->GetPluginName(*m_engine
);
611 m_favour_plugin_name
.clear();
615 wxMessageBox(_W("Please select conflict resolution method."),
616 _W("Conflict Resolution"), wxOK
| wxICON_ERROR
, this);
620 // save the new device name
621 wxGetApp().SetDeviceName(m_barry_plugin
.GetPin(), m_device_name
);
623 // save the sync type checkboxes
624 m_sync_types
[m_engine
] = GetSyncTypeChecks();
629 int GroupCfgDlg::ShowModal()
631 int status
= wxDialog::ShowModal();
632 plugin_ptr app
= GetCurrentPlugin();
633 if( status
== wxID_OK
&& app
.get() ) {
634 // construct a new group from user's results
635 m_group
.reset( new Config::Group(m_group_name
) );
636 m_group
->AddPlugin( m_barry_plugin
.Clone() );
637 m_group
->AddPlugin( app
->Clone() );
639 // don't forget the extras
640 m_extras
.reset( new DeviceExtras(m_barry_plugin
.GetPin()) );
641 m_extras
->m_favour_plugin_name
= m_favour_plugin_name
;
642 m_extras
->m_sync_types
= m_sync_types
[m_engine
];