lib: added implicit ctor converter from DatabaseDatabase to DBListType
[barry/progweb.git] / desktop / src / Mode_Browse.h
blob4fbf494b5047af05906918bef4d47937aa86fafc
1 ///
2 /// \file Mode_Browse.h
3 /// Mode derived class for database browsing
4 ///
6 /*
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__
25 #include "Mode.h"
26 #include "util.h"
27 #include <barry/barry.h>
28 #include <barry/scoped_lock.h>
29 #include <tr1/memory>
30 #include <list>
32 class GUIDesktopConnector : public Barry::DesktopConnector
34 wxWindow *m_parent;
36 public:
37 GUIDesktopConnector(wxWindow *parent, const char *password,
38 const std::string &locale, const Barry::ProbeResult &result)
39 : Barry::DesktopConnector(password, locale, result)
40 , m_parent(parent)
44 virtual bool PasswordPrompt(const Barry::BadPassword &bp,
45 std::string &password_result);
48 // Holds the "right" to use the desktop, and this right expires with the
49 // scope of this class, and no other code can use it while this object exists.
51 // Is copied around by the below auto_ptr<> typedef.
52 class DesktopInstance
54 private:
55 Barry::scoped_lock m_lock;
57 // external interfaces... owned by caller
58 GUIDesktopConnector &m_gdc;
60 public:
61 explicit DesktopInstance(pthread_mutex_t &mutex,
62 GUIDesktopConnector &gdc)
63 : m_lock(mutex)
64 , m_gdc(gdc)
68 GUIDesktopConnector& Connector() { return m_gdc; }
69 Barry::Mode::Desktop& Desktop() { return m_gdc.GetDesktop(); }
70 Barry::IConverter& IC() { return m_gdc.GetIConverter(); }
73 typedef std::auto_ptr<DesktopInstance> DesktopInstancePtr;
76 // ThreadableDesktop
78 /// Protection class that holds the GUIDesktopConnector (i.e. the main
79 /// desktop instance) and a mutex. To access the desktop object, call
80 /// Get(), which locks access for the caller and returns the
81 /// DesktopInstancePtr smart pointer. The lock is released when
82 /// the DesktopInstancePtr goes out of scope.
83 ///
84 class ThreadableDesktop
86 private:
87 pthread_mutex_t m_mutex;
89 // external interfaces... owned by caller
90 GUIDesktopConnector &m_gdc;
92 public:
93 explicit ThreadableDesktop(GUIDesktopConnector &gdc)
94 : m_gdc(gdc)
96 if( pthread_mutex_init(&m_mutex, NULL) ) {
97 throw Barry::Error("Failed to create mutex for ThreadableDesktop");
101 DesktopInstancePtr Get()
103 return DesktopInstancePtr(
104 new DesktopInstance(m_mutex, m_gdc));
109 // DataCache
111 /// Abstract base class representing a single cached record in a database.
112 /// Does not actually contain the record data (base classes hold that), but
113 /// defines what can be done with such a record cache object. (eg. such as
114 /// editing the record)
116 class DataCache
118 public:
119 typedef Barry::RecordStateTable::IndexType IndexType;
121 private:
122 IndexType m_state_index;
123 uint32_t m_record_id;
125 public:
126 DataCache(IndexType state_index, uint32_t record_id)
127 : m_state_index(state_index)
128 , m_record_id(record_id)
132 virtual ~DataCache() {}
134 virtual IndexType GetStateIndex() const { return m_state_index; }
135 virtual uint32_t GetRecordId() const { return m_record_id; }
136 virtual void SetIds(IndexType state_index, uint32_t record_id)
138 std::cout << "DataCache::SetIds(" << state_index << ", " << record_id << ");" << std::endl;
139 m_state_index = state_index;
140 m_record_id = record_id;
143 // set editable to false if you just want to view record
144 // non-buildable records will always be non-editable regardless
145 virtual bool Edit(wxWindow *parent, bool editable,
146 const Barry::TimeZones &zones) = 0;
147 virtual std::string GetDescription() const = 0;
149 virtual bool IsBuildable() const { return false; }
151 bool operator< (const DataCache &other)
153 return GetDescription() < other.GetDescription();
159 // DataCachePtr
161 /// Basically a shared_ptr<DataCache>, but with the added operator<()
162 /// overload so that it calls DataCache's operator<(), for sorting
163 /// of objects via this pointer.
165 class DataCachePtr : public std::tr1::shared_ptr<DataCache>
167 public:
168 DataCachePtr()
172 explicit DataCachePtr(DataCache *obj)
173 : std::tr1::shared_ptr<DataCache>(obj)
177 bool operator< (const DataCachePtr &other)
179 return (*this)->operator<( *other );
184 // DBDataCache
186 /// Derived class from DataCache that holds the raw data of a record that
187 /// does not yet have a parser. Unable to do much with such records in
188 /// terms of editing, but still able to be cached in the DBMap.
190 class DBDataCache : public DataCache
192 Barry::DBData m_raw;
194 public:
195 DBDataCache(DataCache::IndexType index, const Barry::DBData &raw);
197 virtual bool Edit(wxWindow *parent, bool editable,
198 const Barry::TimeZones &zones);
199 virtual std::string GetDescription() const;
202 // returns true if GUI indicates change (i.e. if dialogreturns wxID_OK)
203 #undef HANDLE_PARSER
204 #define HANDLE_PARSER(dbname) \
205 bool EditRecord(wxWindow *parent, bool editable, \
206 const Barry::TimeZones &zones, Barry::dbname &rec);
207 ALL_KNOWN_PARSER_TYPES
210 // RecordCache<>
212 /// Template class derived from DataCache which holds the parsed record data
213 /// for the templated record type. Allows actions such as editing.
215 template <class RecordT>
216 class RecordCache
217 : public DataCache
218 , public Barry::Builder
220 private:
221 RecordT m_rec;
223 public:
224 RecordCache(DataCache::IndexType index, const RecordT &rec)
225 : DataCache(index, rec.GetUniqueId())
226 , m_rec(rec)
228 // if copying from another record, don't copy what
229 // we don't understand
230 m_rec.Unknowns.clear();
233 const RecordT& GetRecord() const { return m_rec; }
235 // hook SetIds() to grab any new record_ids / UniqueIDs
236 virtual void SetIds(IndexType state_index, uint32_t record_id)
238 std::cout << "RecordCache::SetIds(" << state_index << ", " << record_id << ");" << std::endl;
239 DataCache::SetIds(state_index, record_id);
240 m_rec.SetIds(RecordT::GetDefaultRecType(), record_id);
243 virtual bool Edit(wxWindow *parent, bool editable,
244 const Barry::TimeZones &zones)
246 RecordT copy = m_rec;
247 bool changed = EditRecord(parent, editable, zones, copy);
248 // FIXME - we could, at this point, add a (copy != m_rec)
249 // check here, to prevent writing a record that has not
250 // changed, but that would require using the FieldHandle<>
251 // system (a lot of code), and it's not a critical feature
252 // right now
253 if( changed && editable ) {
254 m_rec = copy;
255 return true;
257 return false;
260 virtual std::string GetDescription() const
262 return m_rec.GetDescription();
265 virtual bool IsBuildable() const
267 return ::IsBuildable<RecordT>();
271 // Barry::Builder overrides
273 virtual bool BuildRecord(Barry::DBData &data, size_t &offset,
274 const Barry::IConverter *ic)
276 Barry::SetDBData<RecordT>(m_rec, data, offset, ic);
277 return true;
280 virtual bool FetchRecord(Barry::DBData &data,
281 const Barry::IConverter *ic)
283 size_t offset = 0;
284 Barry::SetDBData<RecordT>(m_rec, data, offset, ic);
285 return true;
288 virtual bool EndOfFile() const
290 return true;
295 // DBCache
297 /// This is a container class that holds a std::list of DataCache-derived
298 /// objects for all the records of a single database.
300 class DBCache : public Barry::AllRecordStore, public Barry::Parser
302 public:
303 typedef Barry::RecordStateTable::IndexType IndexType;
304 typedef std::list<DataCachePtr> DataList;
305 typedef DataList::iterator iterator;
306 typedef DataList::const_iterator const_iterator;
308 private:
309 ThreadableDesktop &m_tdesktop;
310 std::string m_dbname;
311 unsigned int m_dbid;
312 Barry::RecordStateTable m_state;
313 DataList m_records;
315 // per-record load state
316 IndexType m_index;
318 protected:
319 // helper functions, to work around Tasks bug in device
320 bool OverwriteRecord(wxWindow *parent, iterator record);
321 bool DeleteAndAddRecord(wxWindow *parent, iterator record);
323 public:
324 // loads records in constructor
325 DBCache(ThreadableDesktop &tdesktop, const std::string &dbname);
326 virtual ~DBCache();
328 const std::string& GetDBName() { return m_dbname; }
330 iterator Get(int list_offset);
331 const_iterator Get(int list_offset) const;
332 // returns the numeric index of the record, to keep with GUI
333 int GetIndex(iterator record) const;
334 int GetIndex(const_iterator record) const;
336 iterator Add(wxWindow *parent, const Barry::TimeZones &zones,
337 iterator copy_record);
338 bool Edit(wxWindow *parent, const Barry::TimeZones &zones,
339 iterator record);
340 bool Delete(wxWindow *parent, iterator record);
342 iterator begin() { return m_records.begin(); }
343 iterator end() { return m_records.end(); }
344 const_iterator begin() const { return m_records.begin(); }
345 const_iterator end() const { return m_records.end(); }
347 // For Barry::AllRecordStore
348 #undef HANDLE_PARSER
349 #define HANDLE_PARSER(tname) \
350 virtual void operator() (const Barry::tname &);
351 ALL_KNOWN_PARSER_TYPES
353 // For Barry::Parser
354 virtual void ParseRecord(const Barry::DBData &data,
355 const Barry::IConverter *ic);
359 // DBMap
361 /// A std::map based container that maps database names with their
362 /// corresponding DBCaches.
364 class DBMap
366 public:
367 typedef std::tr1::shared_ptr<DBCache> DBCachePtr;
368 typedef std::map<std::string, DBCachePtr> MapType;
370 private:
371 ThreadableDesktop &m_tdesktop;
372 MapType m_map;
373 pthread_mutex_t m_map_mutex;
374 pthread_mutex_t m_load_mutex;
376 public:
377 DBMap(ThreadableDesktop &tdesktop);
379 DBCachePtr LoadDBCache(const std::string &dbname);
380 DBCachePtr GetDBCache(const std::string &dbname);
384 // BrowseMode
386 /// The Desktop GUI mode class for browsing databases and manipulating records.
388 class BrowseMode : public wxEvtHandler, public Mode
390 private:
391 DECLARE_EVENT_TABLE() // sets to protected:
393 private:
394 wxWindow *m_parent;
396 // device interface
397 std::auto_ptr<GUIDesktopConnector> m_con;
398 std::auto_ptr<ThreadableDesktop> m_tdesktop;
399 std::auto_ptr<DBMap> m_dbmap;
400 Barry::DatabaseDatabase m_dbdb;
401 std::auto_ptr<Barry::TimeZones> m_zones;
403 // window controls
404 std::auto_ptr<wxBoxSizer> m_top_sizer;
405 std::auto_ptr<wxListCtrl> m_dbdb_list;
406 std::auto_ptr<wxListCtrl> m_record_list;
407 std::auto_ptr<wxCheckBox> m_show_all_checkbox;
408 std::auto_ptr<wxButton> m_add_record_button;
409 std::auto_ptr<wxButton> m_copy_record_button;
410 std::auto_ptr<wxButton> m_edit_record_button;
411 std::auto_ptr<wxButton> m_delete_record_button;
412 std::auto_ptr<wxStaticText> m_load_status_text;
414 // misc supporting data
415 wxString m_device_id_str;
417 // GUI state
418 bool m_buildable; // true if currently displayed db has
419 // a Builder available for it
420 bool m_editable; // true if currently displayed db has
421 // an edit dialog available for it
422 bool m_show_all; // if true, show all databases in list
423 // instead of just the parsable ones
424 std::string m_current_dbname;
425 long m_current_record_item;
427 // thread state
428 pthread_t m_cache_thread;
429 volatile bool m_abort_flag;
431 protected:
432 void CreateControls();
433 int GUItoDBDBIndex(int gui_index);
434 void FillDBDBList();
435 void FillRecordList(const std::string &dbname);
436 void UpdateButtons();
437 void FillCache();
439 // background thread function
440 static void* FillCacheThread(void *bobj);
442 public:
443 BrowseMode(wxWindow *parent, const Barry::ProbeResult &device);
444 ~BrowseMode();
446 void SendStatusEvent(const std::string &dbname);
448 // virtual override events (derived from Mode)
449 wxString GetTitleText() const { return _T("Barry Database Browser"); }
451 // window events
452 void OnDBDBListSelChange(wxListEvent &event);
453 void OnRecordListSelChange(wxListEvent &event);
454 void OnRecordListActivated(wxListEvent &event);
455 void OnShowAll(wxCommandEvent &event);
456 void OnAddRecord(wxCommandEvent &event);
457 void OnCopyRecord(wxCommandEvent &event);
458 void OnEditRecord(wxCommandEvent &event);
459 void OnDeleteRecord(wxCommandEvent &event);
460 void OnStatusEvent(wxCommandEvent &event);
463 #endif