desktop: added timezone list to CalendarEditDlg
[barry.git] / desktop / src / deviceset.cc
blobd430f14541f0db9f4d687e742a143cb92c71e122
1 ///
2 /// \file deviceset.cc
3 /// Class which detects a set of available or known devices
4 /// in an opensync-able system.
5 ///
7 /*
8 Copyright (C) 2009-2012, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "deviceset.h"
24 #include <barry/barry.h>
25 #include <string.h>
26 #include <algorithm>
27 #include <iostream>
28 #include <iomanip>
30 using namespace std;
32 //////////////////////////////////////////////////////////////////////////////
33 // DeviceExtras class
35 DeviceExtras::DeviceExtras(const Barry::Pin &pin)
36 : m_pin(pin)
37 , m_last_sync_time(0)
38 , m_sync_types(PST_NONE)
42 DeviceExtras::DeviceExtras(const Barry::Pin & pin,
43 const Barry::GlobalConfigFile &config,
44 const std::string &group_name)
45 : m_pin(pin)
46 , m_last_sync_time(0)
48 Load(config, group_name);
51 std::string DeviceExtras::MakeBaseKey(const std::string &group_name)
53 ostringstream oss;
54 oss << m_pin.Str() << "-" << group_name << "-";
55 return oss.str();
58 void DeviceExtras::Load(const Barry::GlobalConfigFile &config,
59 const std::string &group_name)
61 string key = MakeBaseKey(group_name);
62 m_favour_plugin_name = config.GetKey(key + "FavourPlugin");
64 string num = config.GetKey(key + "LastSyncTime");
65 m_last_sync_time = atol(num.c_str());
67 using OpenSync::Config::PSTString2Type;
68 using OpenSync::Config::PSTType2String;
69 string stypes = config.GetKey(key + "SyncTypes",
70 PSTType2String(PST_ALL));
71 m_sync_types = PSTString2Type(stypes);
74 void DeviceExtras::Save(Barry::GlobalConfigFile &config,
75 const std::string &group_name)
77 string key = MakeBaseKey(group_name);
78 config.SetKey(key + "FavourPlugin", m_favour_plugin_name);
80 ostringstream oss;
81 oss << m_last_sync_time;
82 config.SetKey(key + "LastSyncTime", oss.str());
84 config.SetKey(key + "SyncTypes",
85 OpenSync::Config::PSTType2String(m_sync_types));
89 //////////////////////////////////////////////////////////////////////////////
90 // DeviceEntry class
92 DeviceEntry::DeviceEntry(const Barry::GlobalConfigFile &config,
93 const Barry::ProbeResult *result,
94 group_ptr group,
95 OpenSync::API *engine,
96 const std::string &secondary_device_name)
97 : m_result(result)
98 , m_group(group)
99 , m_engine(engine)
100 , m_device_name(secondary_device_name)
102 // just make sure that our device name has something in it
103 if( !m_device_name.size() && m_result )
104 m_device_name = m_result->m_cfgDeviceName;
106 // load the extras if available
107 Barry::Pin pin = GetPin();
108 if( pin.Valid() && IsConfigured() ) {
109 m_extras.reset( new DeviceExtras(pin, config,
110 m_group->GetGroupName()) );
114 // returns pointer to the Barry plugin object in m_group
115 // or 0 if not available
116 OpenSync::Config::Barry* DeviceEntry::FindBarry()
118 if( m_group.get() && m_group->HasBarryPlugins() )
119 return &m_group->GetBarryPlugin();
120 return 0;
123 Barry::Pin DeviceEntry::GetPin() const
125 Barry::Pin pin;
127 // load convenience values
128 if( m_result ) {
129 pin = m_result->m_pin;
132 if( m_group.get() && m_group->HasBarryPlugins() ) {
133 const OpenSync::Config::Barry &bp = m_group->GetBarryPlugin();
135 if( bp.GetPin().Valid() ) {
136 // double check for possible conflicting pin numbers
137 if( pin.Valid() ) {
138 if( pin != bp.GetPin() ) {
139 throw std::logic_error("Probe pin != group pin in DeviceEntry");
143 // got a valid pin, save it
144 pin = bp.GetPin();
148 return pin;
151 std::string DeviceEntry::GetDeviceName() const
153 if( m_device_name.size() )
154 return m_device_name;
155 else if( m_result )
156 return m_result->m_cfgDeviceName;
157 else
158 return std::string();
161 std::string DeviceEntry::GetIdentifyingString() const
163 ostringstream oss;
165 oss << GetPin().Str();
166 string name = GetDeviceName();
167 if( name.size() )
168 oss << " (" << name << ")";
170 if( IsConfigured() )
171 oss << ", Group: " << GetConfigGroup()->GetGroupName();
172 else
173 oss << ", Not configured";
175 if( GetEngine() )
176 oss << ", Engine: " << GetEngine()->GetVersion();
178 return oss.str();
181 void DeviceEntry::SetConfigGroup(group_ptr group,
182 OpenSync::API *engine,
183 extras_ptr extras)
185 m_group = group;
186 m_engine = engine;
187 m_extras = extras;
190 std::ostream& operator<< (std::ostream &os, const DeviceEntry &de)
192 os << setfill(' ') << setw(8) << de.GetPin().Str();
193 os << "|" << setfill(' ') << setw(35) << de.GetDeviceName();
194 os << "|" << setfill(' ') << setw(4) << (de.IsConnected() ? "yes" : "no");
195 os << "|" << setfill(' ') << setw(4) << (de.IsConfigured() ? "yes" : "no");
196 os << "|" << setfill(' ') << setw(7)
197 << (de.GetEngine() ? de.GetEngine()->GetVersion() : "");
198 return os;
201 //////////////////////////////////////////////////////////////////////////////
202 // DeviceSet class
204 /// Does a USB probe automatically
205 DeviceSet::DeviceSet(const Barry::GlobalConfigFile &config,
206 OpenSync::APISet &apiset)
207 : m_config(config)
208 , m_apiset(apiset)
210 Barry::Probe probe;
211 m_results = probe.GetResults();
212 LoadSet();
215 /// Skips the USB probe and uses the results set given
216 DeviceSet::DeviceSet(const Barry::GlobalConfigFile &config,
217 OpenSync::APISet &apiset,
218 const Barry::Probe::Results &results)
219 : m_config(config)
220 , m_apiset(apiset)
221 , m_results(results)
223 LoadSet();
226 void DeviceSet::LoadSet()
228 if( m_apiset.os40() )
229 LoadConfigured(*m_apiset.os40());
230 if( m_apiset.os22() )
231 LoadConfigured(*m_apiset.os22());
232 LoadUnconfigured();
233 Sort();
236 /// Constructor helper function. Adds configured DeviceEntry's to the set.
237 /// Does no sorting.
238 void DeviceSet::LoadConfigured(OpenSync::API &api)
240 using namespace OpenSync;
243 // we already have the connected devices in m_results, so
244 // load every Barry-related group that exists in the given API
247 // get group list
248 string_list_type groups;
249 api.GetGroupNames(groups);
251 // for each group
252 for( string_list_type::iterator b = groups.begin(); b != groups.end(); ++b ) {
253 try {
254 // load the group via Config::Group
255 DeviceEntry::group_ptr g( new Config::Group(*b, api,
256 OSCG_THROW_ON_UNSUPPORTED |
257 OSCG_THROW_ON_NO_BARRY |
258 OSCG_THROW_ON_MULTIPLE_BARRIES) );
260 // now that we have a config group, check to see
261 // if the pin in the group's Barry plugin is
262 // available in the probe results... if so, it is
263 // also connected
264 OpenSync::Config::Barry &plugin = g->GetBarryPlugin();
265 Barry::Probe::Results::iterator result =
266 std::find(m_results.begin(), m_results.end(),
267 plugin.GetPin());
268 const Barry::ProbeResult *connected = 0;
269 string dev_name;
270 if( result != m_results.end() ) {
271 connected = &(*result);
272 dev_name = connected->m_cfgDeviceName;
274 else {
275 // the device is not connected, so do a
276 // special load of a possible device config
277 // to load the device name
278 Barry::ConfigFile cf(plugin.GetPin());
279 dev_name = cf.GetDeviceName();
282 // if no LoadError exceptions, add to configured list
283 push_back( DeviceEntry(m_config, connected, g, &api,
284 dev_name) );
287 catch( Config::LoadError &le ) {
288 // if we catch LoadError, it just means that this
289 // isn't a config that Barry Desktop can handle
290 // so just log and skip it
291 barryverbose("DeviceSet::LoadConfigured: " << le.what());
296 void DeviceSet::LoadUnconfigured()
298 // cycle through the probe results, and add any devices for
299 // which their pins do not yet exist in the list
300 for( Barry::Probe::Results::const_iterator i = m_results.begin();
301 i != m_results.end();
302 ++i )
304 iterator p = FindPin(i->m_pin);
305 if( p == end() ) {
306 // this pin isn't in the list yet, so add it
307 // as an unconfigured item
309 // create the DeviceEntry with a null group_ptr
310 DeviceEntry item( m_config, &(*i),
311 DeviceEntry::group_ptr(), 0 );
312 push_back( item );
317 /// Constructor helper function. Loads the device list. Sort by
318 /// pin number, but in the following groups:
320 /// - configured first (both connected and unconnected)
321 /// - unconfigured but connected second
323 /// This should preserve the sort order across multiple loads, to keep
324 /// a relatively consistent listing for the user.
326 namespace {
327 bool DeviceEntryCompare(const DeviceEntry &a, const DeviceEntry &b)
329 if( a.IsConfigured() == b.IsConfigured() )
330 return strcmp(a.GetPin().Str().c_str(),
331 b.GetPin().Str().c_str()) < 0;
332 else
333 return a.IsConfigured();
336 void DeviceSet::Sort()
338 std::sort(begin(), end(), &DeviceEntryCompare);
341 DeviceSet::iterator DeviceSet::FindPin(const Barry::Pin &pin)
343 for( iterator i = begin(); i != end(); ++i ) {
344 if( i->GetPin() == pin )
345 return i;
347 return end();
350 DeviceSet::const_iterator DeviceSet::FindPin(const Barry::Pin &pin) const
352 for( const_iterator i = begin(); i != end(); ++i ) {
353 if( i->GetPin() == pin )
354 return i;
356 return end();
359 DeviceSet::subset_type::const_iterator DeviceSet::FindPin(
360 const DeviceSet::subset_type &subset, const Barry::Pin &pin)
362 for( subset_type::const_iterator i = subset.begin();
363 i != subset.end();
364 ++i )
366 if( (*i)->GetPin() == pin )
367 return i;
369 return subset.end();
372 std::string DeviceSet::Subset2String(const DeviceSet::subset_type &set)
374 std::string list;
376 subset_type::const_iterator i = set.begin();
377 for( ; i != set.end(); ++i ) {
378 if( list.size() )
379 list += " ";
380 list += (*i)->GetPin().Str();
382 return list;
385 DeviceSet::subset_type DeviceSet::String2Subset(const std::string &list)
387 subset_type set;
389 istringstream iss(list);
390 Barry::Pin pin;
392 while( iss >> pin ) {
393 if( !pin.Valid() )
394 continue;
396 // search for pin in device set
397 iterator i = FindPin(pin);
398 if( i != end() )
399 set.push_back(i);
401 return set;
404 DeviceSet::subset_type DeviceSet::FindDuplicates()
406 subset_type dups;
408 for( iterator i = begin(); i != end(); ++i ) {
410 // start with this PIN
411 dups.push_back(i);
413 // search for a duplicate, and add all dups found
414 for( iterator j = begin(); j != end(); ++j ) {
415 // skip ourselves
416 if( j == i )
417 continue;
419 if( i->GetPin() == j->GetPin() ) {
420 // found a duplicate
421 dups.push_back(j);
425 // if we have multiple iterators in dups, we're done
426 if( dups.size() > 1 )
427 return dups;
429 // else, start over
430 dups.clear();
433 return dups;
436 void DeviceSet::KillDuplicates(const subset_type &dups)
438 // anything to do?
439 if( dups.size() == 0 )
440 return; // nope
442 // only one?
443 if( dups.size() == 1 ) {
444 erase(dups[0]);
445 return;
448 // ok, we have multiple dups to erase, so we need to make
449 // a copy of ourselves and skip all matching iterators,
450 // then copy the result back to this
451 base_type copy;
452 for( iterator i = begin(); i != end(); ++i ) {
453 if( find(dups.begin(), dups.end(), i) == dups.end() ) {
454 // not in the dups list, copy it
455 copy.push_back(*i);
459 // copy back
460 clear();
461 base_type::operator=(copy);
464 std::ostream& operator<< (std::ostream &os, const DeviceSet &ds)
466 os << " PIN | Device Name |Con |Cfg |Engine\n";
467 os << "--------+-----------------------------------+----+----+-------\n";
469 for( DeviceSet::const_iterator i = ds.begin(); i != ds.end(); ++i )
470 os << *i << "\n" << i->GetIdentifyingString() << endl;
471 return os;