Bumped copyright dates for 2013
[barry.git] / desktop / src / Mode_Browse.h
blob866000058177dcd0a8ff172ba5e598b214d6245d
1 ///
2 /// \file Mode_Browse.h
3 /// Mode derived class for database browsing
4 ///
6 /*
7 Copyright (C) 2011-2013, 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/barrysync.h>
29 #include <barry/scoped_lock.h>
30 #include <tr1/memory>
31 #include <list>
32 #include "wxi18n.h"
34 class GUIDesktopConnector : public Barry::DesktopConnector
36 wxWindow *m_parent;
38 public:
39 GUIDesktopConnector(wxWindow *parent, const char *password,
40 const std::string &locale, const Barry::ProbeResult &result)
41 : Barry::DesktopConnector(password, locale, result)
42 , m_parent(parent)
46 virtual bool PasswordPrompt(const Barry::BadPassword &bp,
47 std::string &password_result);
50 // Holds the "right" to use the desktop, and this right expires with the
51 // scope of this class, and no other code can use it while this object exists.
53 // Is copied around by the below auto_ptr<> typedef.
54 class DesktopInstance
56 private:
57 Barry::scoped_lock m_lock;
59 // external interfaces... owned by caller
60 GUIDesktopConnector &m_gdc;
62 public:
63 explicit DesktopInstance(pthread_mutex_t &mutex,
64 GUIDesktopConnector &gdc)
65 : m_lock(mutex)
66 , m_gdc(gdc)
70 GUIDesktopConnector& Connector() { return m_gdc; }
71 Barry::Mode::Desktop& Desktop() { return m_gdc.GetDesktop(); }
72 Barry::IConverter& IC() { return m_gdc.GetIConverter(); }
75 typedef std::auto_ptr<DesktopInstance> DesktopInstancePtr;
78 // ThreadableDesktop
80 /// Protection class that holds the GUIDesktopConnector (i.e. the main
81 /// desktop instance) and a mutex. To access the desktop object, call
82 /// Get(), which locks access for the caller and returns the
83 /// DesktopInstancePtr smart pointer. The lock is released when
84 /// the DesktopInstancePtr goes out of scope.
85 ///
86 class ThreadableDesktop
88 private:
89 pthread_mutex_t m_mutex;
91 // external interfaces... owned by caller
92 GUIDesktopConnector &m_gdc;
94 public:
95 explicit ThreadableDesktop(GUIDesktopConnector &gdc)
96 : m_gdc(gdc)
98 if( pthread_mutex_init(&m_mutex, NULL) ) {
99 throw Barry::Error(_C("Failed to create mutex for ThreadableDesktop"));
103 DesktopInstancePtr Get()
105 return DesktopInstancePtr(
106 new DesktopInstance(m_mutex, m_gdc));
111 // DataCache
113 /// Abstract base class representing a single cached record in a database.
114 /// Does not actually contain the record data (base classes hold that), but
115 /// defines what can be done with such a record cache object. (eg. such as
116 /// editing the record)
118 class DataCache
120 public:
121 typedef Barry::RecordStateTable::IndexType IndexType;
123 private:
124 IndexType m_state_index;
125 uint32_t m_record_id;
127 public:
128 DataCache(IndexType state_index, uint32_t record_id)
129 : m_state_index(state_index)
130 , m_record_id(record_id)
134 virtual ~DataCache() {}
136 virtual IndexType GetStateIndex() const { return m_state_index; }
137 virtual uint32_t GetRecordId() const { return m_record_id; }
138 virtual void SetIds(IndexType state_index, uint32_t record_id)
140 std::cout << "DataCache::SetIds(" << state_index << ", " << record_id << ");" << std::endl;
141 m_state_index = state_index;
142 m_record_id = record_id;
145 // set editable to false if you just want to view record
146 // non-buildable records will always be non-editable regardless
147 virtual bool Edit(wxWindow *parent, bool editable,
148 const Barry::TimeZones &zones) = 0;
149 virtual bool Card(wxWindow *parent, std::string &vdata) {return false;}
150 virtual std::string GetDescription() const = 0;
152 virtual bool IsBuildable() const { return false; }
154 bool operator< (const DataCache &other)
156 return GetDescription() < other.GetDescription();
162 // DataCachePtr
164 /// Basically a shared_ptr<DataCache>, but with the added operator<()
165 /// overload so that it calls DataCache's operator<(), for sorting
166 /// of objects via this pointer.
168 class DataCachePtr : public std::tr1::shared_ptr<DataCache>
170 public:
171 DataCachePtr()
175 explicit DataCachePtr(DataCache *obj)
176 : std::tr1::shared_ptr<DataCache>(obj)
180 bool operator< (const DataCachePtr &other)
182 return (*this)->operator<( *other );
187 // DBDataCache
189 /// Derived class from DataCache that holds the raw data of a record that
190 /// does not yet have a parser. Unable to do much with such records in
191 /// terms of editing, but still able to be cached in the DBMap.
193 class DBDataCache : public DataCache
195 Barry::DBData m_raw;
197 public:
198 DBDataCache(DataCache::IndexType index, const Barry::DBData &raw);
200 virtual bool Edit(wxWindow *parent, bool editable,
201 const Barry::TimeZones &zones);
202 virtual std::string GetDescription() const;
205 // returns true if GUI indicates change (i.e. if dialogreturns wxID_OK)
206 #undef HANDLE_PARSER
207 #define HANDLE_PARSER(dbname) \
208 bool EditRecord(wxWindow *parent, bool editable, \
209 const Barry::TimeZones &zones, Barry::dbname &rec);
210 ALL_KNOWN_PARSER_TYPES
213 // RecordCache<>
215 /// Template class derived from DataCache which holds the parsed record data
216 /// for the templated record type. Allows actions such as editing.
218 template <class RecordT>
219 class RecordCache
220 : public DataCache
221 , public Barry::Builder
223 private:
224 RecordT m_rec;
226 public:
227 RecordCache(DataCache::IndexType index, const RecordT &rec)
228 : DataCache(index, rec.GetUniqueId())
229 , m_rec(rec)
231 // if copying from another record, don't copy what
232 // we don't understand
233 m_rec.Unknowns.clear();
236 const RecordT& GetRecord() const { return m_rec; }
238 // hook SetIds() to grab any new record_ids / UniqueIDs
239 virtual void SetIds(IndexType state_index, uint32_t record_id)
241 std::cout << "RecordCache::SetIds(" << state_index << ", " << record_id << ");" << std::endl;
242 DataCache::SetIds(state_index, record_id);
243 m_rec.SetIds(RecordT::GetDefaultRecType(), record_id);
246 virtual bool Edit(wxWindow *parent, bool editable,
247 const Barry::TimeZones &zones)
249 RecordT copy = m_rec;
250 bool changed = EditRecord(parent, editable, zones, copy);
251 // FIXME - we could, at this point, add a (copy != m_rec)
252 // check here, to prevent writing a record that has not
253 // changed, but that would require using the FieldHandle<>
254 // system (a lot of code), and it's not a critical feature
255 // right now
256 if( changed && editable ) {
257 m_rec = copy;
258 return true;
260 return false;
263 virtual bool Card(wxWindow *parent, std::string &vdata)
265 if( !Barry::MimeDump<RecordT>::Supported() )
266 return false;
268 std::ostringstream oss;
269 Barry::MimeDump<RecordT>::Dump(oss, m_rec);
270 vdata = oss.str();
271 return true;
274 virtual std::string GetDescription() const
276 return m_rec.GetDescription();
279 virtual bool IsBuildable() const
281 return ::IsBuildable<RecordT>();
285 // Barry::Builder overrides
287 virtual bool BuildRecord(Barry::DBData &data, size_t &offset,
288 const Barry::IConverter *ic)
290 Barry::SetDBData<RecordT>(m_rec, data, offset, ic);
291 return true;
294 virtual bool FetchRecord(Barry::DBData &data,
295 const Barry::IConverter *ic)
297 size_t offset = 0;
298 Barry::SetDBData<RecordT>(m_rec, data, offset, ic);
299 return true;
302 virtual bool EndOfFile() const
304 return true;
309 // DBCache
311 /// This is a container class that holds a std::list of DataCache-derived
312 /// objects for all the records of a single database.
314 class DBCache : public Barry::AllRecordStore, public Barry::Parser
316 public:
317 typedef Barry::RecordStateTable::IndexType IndexType;
318 typedef std::list<DataCachePtr> DataList;
319 typedef DataList::iterator iterator;
320 typedef DataList::const_iterator const_iterator;
322 private:
323 ThreadableDesktop &m_tdesktop;
324 std::string m_dbname;
325 unsigned int m_dbid;
326 Barry::RecordStateTable m_state;
327 DataList m_records;
329 // per-record load state
330 IndexType m_index;
332 protected:
333 // helper functions, to work around Tasks bug in device
334 bool OverwriteRecord(wxWindow *parent, iterator record);
335 bool DeleteAndAddRecord(wxWindow *parent, iterator record);
337 public:
338 // loads records in constructor
339 DBCache(ThreadableDesktop &tdesktop, const std::string &dbname);
340 virtual ~DBCache();
342 const std::string& GetDBName() { return m_dbname; }
344 iterator Get(int list_offset);
345 const_iterator Get(int list_offset) const;
346 // returns the numeric index of the record, to keep with GUI
347 int GetIndex(iterator record) const;
348 int GetIndex(const_iterator record) const;
350 iterator Add(wxWindow *parent, DataCachePtr p); // adds to device too,
351 // just like Add() below
352 iterator Add(wxWindow *parent, const Barry::TimeZones &zones,
353 iterator copy_record);
354 bool Edit(wxWindow *parent, const Barry::TimeZones &zones,
355 iterator record);
356 bool Delete(wxWindow *parent, iterator record);
358 iterator begin() { return m_records.begin(); }
359 iterator end() { return m_records.end(); }
360 const_iterator begin() const { return m_records.begin(); }
361 const_iterator end() const { return m_records.end(); }
363 // For Barry::AllRecordStore
364 #undef HANDLE_PARSER
365 #define HANDLE_PARSER(tname) \
366 virtual void operator() (const Barry::tname &);
367 ALL_KNOWN_PARSER_TYPES
369 // For Barry::Parser
370 virtual void ParseRecord(const Barry::DBData &data,
371 const Barry::IConverter *ic);
375 // DBMap
377 /// A std::map based container that maps database names with their
378 /// corresponding DBCaches.
380 class DBMap
382 public:
383 typedef std::tr1::shared_ptr<DBCache> DBCachePtr;
384 typedef std::map<std::string, DBCachePtr> MapType;
386 private:
387 ThreadableDesktop &m_tdesktop;
388 MapType m_map;
389 pthread_mutex_t m_map_mutex;
390 pthread_mutex_t m_load_mutex;
392 public:
393 DBMap(ThreadableDesktop &tdesktop);
395 DBCachePtr LoadDBCache(const std::string &dbname);
396 DBCachePtr GetDBCache(const std::string &dbname);
400 // BrowseMode
402 /// The Desktop GUI mode class for browsing databases and manipulating records.
404 class BrowseMode : public wxEvtHandler, public Mode
406 private:
407 DECLARE_EVENT_TABLE() // sets to protected:
409 private:
410 wxWindow *m_parent;
412 // device interface
413 std::auto_ptr<GUIDesktopConnector> m_con;
414 std::auto_ptr<ThreadableDesktop> m_tdesktop;
415 std::auto_ptr<DBMap> m_dbmap;
416 Barry::DatabaseDatabase m_dbdb;
417 std::auto_ptr<Barry::TimeZones> m_zones;
419 // window controls
420 std::auto_ptr<wxBoxSizer> m_top_sizer;
421 std::auto_ptr<wxListCtrl> m_dbdb_list;
422 std::auto_ptr<wxListCtrl> m_record_list;
423 std::auto_ptr<wxCheckBox> m_show_all_checkbox;
424 std::auto_ptr<wxButton> m_import_record_button;
425 std::auto_ptr<wxButton> m_export_record_button;
426 std::auto_ptr<wxButton> m_add_record_button;
427 std::auto_ptr<wxButton> m_copy_record_button;
428 std::auto_ptr<wxButton> m_edit_record_button;
429 std::auto_ptr<wxButton> m_delete_record_button;
430 std::auto_ptr<wxStaticText> m_load_status_text;
432 // misc supporting data
433 wxString m_device_id_str;
435 // GUI state
436 bool m_buildable; // true if currently displayed db has
437 // a Builder available for it
438 bool m_editable; // true if currently displayed db has
439 // an edit dialog available for it
440 bool m_cardable; // true if currently displayed db is
441 // capable of MIME style import/exports
442 bool m_show_all; // if true, show all databases in list
443 // instead of just the parsable ones
444 std::string m_current_dbname;
445 long m_current_record_item;
447 // thread state
448 pthread_t m_cache_thread;
449 volatile bool m_abort_flag;
451 protected:
452 void CreateControls();
453 int GUItoDBDBIndex(int gui_index);
454 void FillDBDBList();
455 void FillRecordList(const std::string &dbname);
456 void UpdateButtons();
457 void FillCache();
459 // background thread function
460 static void* FillCacheThread(void *bobj);
462 public:
463 BrowseMode(wxWindow *parent, const Barry::ProbeResult &device);
464 ~BrowseMode();
466 void SendStatusEvent(const std::string &dbname);
468 // virtual override events (derived from Mode)
469 wxString GetTitleText() const { return _W("Barry Database Browser"); }
471 // window events
472 void OnDBDBListSelChange(wxListEvent &event);
473 void OnRecordListSelChange(wxListEvent &event);
474 void OnRecordListActivated(wxListEvent &event);
475 void OnShowAll(wxCommandEvent &event);
476 void OnImportRecord(wxCommandEvent &event);
477 void OnExportRecord(wxCommandEvent &event);
478 void OnAddRecord(wxCommandEvent &event);
479 void OnCopyRecord(wxCommandEvent &event);
480 void OnEditRecord(wxCommandEvent &event);
481 void OnDeleteRecord(wxCommandEvent &event);
482 void OnStatusEvent(wxCommandEvent &event);
485 #endif