2 /// \file Mode_Browse.h
3 /// Mode derived class for database browsing
7 Copyright (C) 2011-2012, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #ifndef __BARRYDESKTOP_MODE_BROWSE_H__
23 #define __BARRYDESKTOP_MODE_BROWSE_H__
27 #include <barry/barry.h>
28 #include <barry/barrysync.h>
29 #include <barry/scoped_lock.h>
33 class GUIDesktopConnector
: public Barry::DesktopConnector
38 GUIDesktopConnector(wxWindow
*parent
, const char *password
,
39 const std::string
&locale
, const Barry::ProbeResult
&result
)
40 : Barry::DesktopConnector(password
, locale
, result
)
45 virtual bool PasswordPrompt(const Barry::BadPassword
&bp
,
46 std::string
&password_result
);
49 // Holds the "right" to use the desktop, and this right expires with the
50 // scope of this class, and no other code can use it while this object exists.
52 // Is copied around by the below auto_ptr<> typedef.
56 Barry::scoped_lock m_lock
;
58 // external interfaces... owned by caller
59 GUIDesktopConnector
&m_gdc
;
62 explicit DesktopInstance(pthread_mutex_t
&mutex
,
63 GUIDesktopConnector
&gdc
)
69 GUIDesktopConnector
& Connector() { return m_gdc
; }
70 Barry::Mode::Desktop
& Desktop() { return m_gdc
.GetDesktop(); }
71 Barry::IConverter
& IC() { return m_gdc
.GetIConverter(); }
74 typedef std::auto_ptr
<DesktopInstance
> DesktopInstancePtr
;
79 /// Protection class that holds the GUIDesktopConnector (i.e. the main
80 /// desktop instance) and a mutex. To access the desktop object, call
81 /// Get(), which locks access for the caller and returns the
82 /// DesktopInstancePtr smart pointer. The lock is released when
83 /// the DesktopInstancePtr goes out of scope.
85 class ThreadableDesktop
88 pthread_mutex_t m_mutex
;
90 // external interfaces... owned by caller
91 GUIDesktopConnector
&m_gdc
;
94 explicit ThreadableDesktop(GUIDesktopConnector
&gdc
)
97 if( pthread_mutex_init(&m_mutex
, NULL
) ) {
98 throw Barry::Error("Failed to create mutex for ThreadableDesktop");
102 DesktopInstancePtr
Get()
104 return DesktopInstancePtr(
105 new DesktopInstance(m_mutex
, m_gdc
));
112 /// Abstract base class representing a single cached record in a database.
113 /// Does not actually contain the record data (base classes hold that), but
114 /// defines what can be done with such a record cache object. (eg. such as
115 /// editing the record)
120 typedef Barry::RecordStateTable::IndexType IndexType
;
123 IndexType m_state_index
;
124 uint32_t m_record_id
;
127 DataCache(IndexType state_index
, uint32_t record_id
)
128 : m_state_index(state_index
)
129 , m_record_id(record_id
)
133 virtual ~DataCache() {}
135 virtual IndexType
GetStateIndex() const { return m_state_index
; }
136 virtual uint32_t GetRecordId() const { return m_record_id
; }
137 virtual void SetIds(IndexType state_index
, uint32_t record_id
)
139 std::cout
<< "DataCache::SetIds(" << state_index
<< ", " << record_id
<< ");" << std::endl
;
140 m_state_index
= state_index
;
141 m_record_id
= record_id
;
144 // set editable to false if you just want to view record
145 // non-buildable records will always be non-editable regardless
146 virtual bool Edit(wxWindow
*parent
, bool editable
,
147 const Barry::TimeZones
&zones
) = 0;
148 virtual bool Card(wxWindow
*parent
, std::string
&vdata
) {return false;}
149 virtual std::string
GetDescription() const = 0;
151 virtual bool IsBuildable() const { return false; }
153 bool operator< (const DataCache
&other
)
155 return GetDescription() < other
.GetDescription();
163 /// Basically a shared_ptr<DataCache>, but with the added operator<()
164 /// overload so that it calls DataCache's operator<(), for sorting
165 /// of objects via this pointer.
167 class DataCachePtr
: public std::tr1::shared_ptr
<DataCache
>
174 explicit DataCachePtr(DataCache
*obj
)
175 : std::tr1::shared_ptr
<DataCache
>(obj
)
179 bool operator< (const DataCachePtr
&other
)
181 return (*this)->operator<( *other
);
188 /// Derived class from DataCache that holds the raw data of a record that
189 /// does not yet have a parser. Unable to do much with such records in
190 /// terms of editing, but still able to be cached in the DBMap.
192 class DBDataCache
: public DataCache
197 DBDataCache(DataCache::IndexType index
, const Barry::DBData
&raw
);
199 virtual bool Edit(wxWindow
*parent
, bool editable
,
200 const Barry::TimeZones
&zones
);
201 virtual std::string
GetDescription() const;
204 // returns true if GUI indicates change (i.e. if dialogreturns wxID_OK)
206 #define HANDLE_PARSER(dbname) \
207 bool EditRecord(wxWindow *parent, bool editable, \
208 const Barry::TimeZones &zones, Barry::dbname &rec);
209 ALL_KNOWN_PARSER_TYPES
214 /// Template class derived from DataCache which holds the parsed record data
215 /// for the templated record type. Allows actions such as editing.
217 template <class RecordT
>
220 , public Barry::Builder
226 RecordCache(DataCache::IndexType index
, const RecordT
&rec
)
227 : DataCache(index
, rec
.GetUniqueId())
230 // if copying from another record, don't copy what
231 // we don't understand
232 m_rec
.Unknowns
.clear();
235 const RecordT
& GetRecord() const { return m_rec
; }
237 // hook SetIds() to grab any new record_ids / UniqueIDs
238 virtual void SetIds(IndexType state_index
, uint32_t record_id
)
240 std::cout
<< "RecordCache::SetIds(" << state_index
<< ", " << record_id
<< ");" << std::endl
;
241 DataCache::SetIds(state_index
, record_id
);
242 m_rec
.SetIds(RecordT::GetDefaultRecType(), record_id
);
245 virtual bool Edit(wxWindow
*parent
, bool editable
,
246 const Barry::TimeZones
&zones
)
248 RecordT copy
= m_rec
;
249 bool changed
= EditRecord(parent
, editable
, zones
, copy
);
250 // FIXME - we could, at this point, add a (copy != m_rec)
251 // check here, to prevent writing a record that has not
252 // changed, but that would require using the FieldHandle<>
253 // system (a lot of code), and it's not a critical feature
255 if( changed
&& editable
) {
262 virtual bool Card(wxWindow
*parent
, std::string
&vdata
)
264 if( !Barry::MimeDump
<RecordT
>::Supported() )
267 std::ostringstream oss
;
268 Barry::MimeDump
<RecordT
>::Dump(oss
, m_rec
);
273 virtual std::string
GetDescription() const
275 return m_rec
.GetDescription();
278 virtual bool IsBuildable() const
280 return ::IsBuildable
<RecordT
>();
284 // Barry::Builder overrides
286 virtual bool BuildRecord(Barry::DBData
&data
, size_t &offset
,
287 const Barry::IConverter
*ic
)
289 Barry::SetDBData
<RecordT
>(m_rec
, data
, offset
, ic
);
293 virtual bool FetchRecord(Barry::DBData
&data
,
294 const Barry::IConverter
*ic
)
297 Barry::SetDBData
<RecordT
>(m_rec
, data
, offset
, ic
);
301 virtual bool EndOfFile() const
310 /// This is a container class that holds a std::list of DataCache-derived
311 /// objects for all the records of a single database.
313 class DBCache
: public Barry::AllRecordStore
, public Barry::Parser
316 typedef Barry::RecordStateTable::IndexType IndexType
;
317 typedef std::list
<DataCachePtr
> DataList
;
318 typedef DataList::iterator iterator
;
319 typedef DataList::const_iterator const_iterator
;
322 ThreadableDesktop
&m_tdesktop
;
323 std::string m_dbname
;
325 Barry::RecordStateTable m_state
;
328 // per-record load state
332 // helper functions, to work around Tasks bug in device
333 bool OverwriteRecord(wxWindow
*parent
, iterator record
);
334 bool DeleteAndAddRecord(wxWindow
*parent
, iterator record
);
337 // loads records in constructor
338 DBCache(ThreadableDesktop
&tdesktop
, const std::string
&dbname
);
341 const std::string
& GetDBName() { return m_dbname
; }
343 iterator
Get(int list_offset
);
344 const_iterator
Get(int list_offset
) const;
345 // returns the numeric index of the record, to keep with GUI
346 int GetIndex(iterator record
) const;
347 int GetIndex(const_iterator record
) const;
349 iterator
Add(wxWindow
*parent
, DataCachePtr p
); // adds to device too,
350 // just like Add() below
351 iterator
Add(wxWindow
*parent
, const Barry::TimeZones
&zones
,
352 iterator copy_record
);
353 bool Edit(wxWindow
*parent
, const Barry::TimeZones
&zones
,
355 bool Delete(wxWindow
*parent
, iterator record
);
357 iterator
begin() { return m_records
.begin(); }
358 iterator
end() { return m_records
.end(); }
359 const_iterator
begin() const { return m_records
.begin(); }
360 const_iterator
end() const { return m_records
.end(); }
362 // For Barry::AllRecordStore
364 #define HANDLE_PARSER(tname) \
365 virtual void operator() (const Barry::tname &);
366 ALL_KNOWN_PARSER_TYPES
369 virtual void ParseRecord(const Barry::DBData
&data
,
370 const Barry::IConverter
*ic
);
376 /// A std::map based container that maps database names with their
377 /// corresponding DBCaches.
382 typedef std::tr1::shared_ptr
<DBCache
> DBCachePtr
;
383 typedef std::map
<std::string
, DBCachePtr
> MapType
;
386 ThreadableDesktop
&m_tdesktop
;
388 pthread_mutex_t m_map_mutex
;
389 pthread_mutex_t m_load_mutex
;
392 DBMap(ThreadableDesktop
&tdesktop
);
394 DBCachePtr
LoadDBCache(const std::string
&dbname
);
395 DBCachePtr
GetDBCache(const std::string
&dbname
);
401 /// The Desktop GUI mode class for browsing databases and manipulating records.
403 class BrowseMode
: public wxEvtHandler
, public Mode
406 DECLARE_EVENT_TABLE() // sets to protected:
412 std::auto_ptr
<GUIDesktopConnector
> m_con
;
413 std::auto_ptr
<ThreadableDesktop
> m_tdesktop
;
414 std::auto_ptr
<DBMap
> m_dbmap
;
415 Barry::DatabaseDatabase m_dbdb
;
416 std::auto_ptr
<Barry::TimeZones
> m_zones
;
419 std::auto_ptr
<wxBoxSizer
> m_top_sizer
;
420 std::auto_ptr
<wxListCtrl
> m_dbdb_list
;
421 std::auto_ptr
<wxListCtrl
> m_record_list
;
422 std::auto_ptr
<wxCheckBox
> m_show_all_checkbox
;
423 std::auto_ptr
<wxButton
> m_import_record_button
;
424 std::auto_ptr
<wxButton
> m_export_record_button
;
425 std::auto_ptr
<wxButton
> m_add_record_button
;
426 std::auto_ptr
<wxButton
> m_copy_record_button
;
427 std::auto_ptr
<wxButton
> m_edit_record_button
;
428 std::auto_ptr
<wxButton
> m_delete_record_button
;
429 std::auto_ptr
<wxStaticText
> m_load_status_text
;
431 // misc supporting data
432 wxString m_device_id_str
;
435 bool m_buildable
; // true if currently displayed db has
436 // a Builder available for it
437 bool m_editable
; // true if currently displayed db has
438 // an edit dialog available for it
439 bool m_cardable
; // true if currently displayed db is
440 // capable of MIME style import/exports
441 bool m_show_all
; // if true, show all databases in list
442 // instead of just the parsable ones
443 std::string m_current_dbname
;
444 long m_current_record_item
;
447 pthread_t m_cache_thread
;
448 volatile bool m_abort_flag
;
451 void CreateControls();
452 int GUItoDBDBIndex(int gui_index
);
454 void FillRecordList(const std::string
&dbname
);
455 void UpdateButtons();
458 // background thread function
459 static void* FillCacheThread(void *bobj
);
462 BrowseMode(wxWindow
*parent
, const Barry::ProbeResult
&device
);
465 void SendStatusEvent(const std::string
&dbname
);
467 // virtual override events (derived from Mode)
468 wxString
GetTitleText() const { return _T("Barry Database Browser"); }
471 void OnDBDBListSelChange(wxListEvent
&event
);
472 void OnRecordListSelChange(wxListEvent
&event
);
473 void OnRecordListActivated(wxListEvent
&event
);
474 void OnShowAll(wxCommandEvent
&event
);
475 void OnImportRecord(wxCommandEvent
&event
);
476 void OnExportRecord(wxCommandEvent
&event
);
477 void OnAddRecord(wxCommandEvent
&event
);
478 void OnCopyRecord(wxCommandEvent
&event
);
479 void OnEditRecord(wxCommandEvent
&event
);
480 void OnDeleteRecord(wxCommandEvent
&event
);
481 void OnStatusEvent(wxCommandEvent
&event
);