2 /// \file Mode_Browse.cc
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 #include "Mode_Browse.h"
23 #include "BaseFrame.h"
24 #include "ContactEditDlg.h"
25 #include "CalendarEditDlg.h"
26 #include "MemoEditDlg.h"
27 #include "windowids.h"
33 using namespace Barry
;
35 DEFINE_EVENT_TYPE(BMET_LOAD_STATUS
)
37 BEGIN_EVENT_TABLE(BrowseMode
, wxEvtHandler
)
38 EVT_LIST_ITEM_SELECTED(BrowseMode_DBDBList
,
39 BrowseMode::OnDBDBListSelChange
)
40 EVT_LIST_ITEM_SELECTED(BrowseMode_RecordList
,
41 BrowseMode::OnRecordListSelChange
)
42 EVT_LIST_ITEM_ACTIVATED(BrowseMode_RecordList
,
43 BrowseMode::OnRecordListActivated
)
44 EVT_CHECKBOX (BrowseMode_ShowAllCheckbox
,
45 BrowseMode::OnShowAll
)
46 EVT_BUTTON (BrowseMode_AddRecordButton
,
47 BrowseMode::OnAddRecord
)
48 EVT_BUTTON (BrowseMode_CopyRecordButton
,
49 BrowseMode::OnCopyRecord
)
50 EVT_BUTTON (BrowseMode_EditRecordButton
,
51 BrowseMode::OnEditRecord
)
52 EVT_BUTTON (BrowseMode_DeleteRecordButton
,
53 BrowseMode::OnDeleteRecord
)
54 EVT_COMMAND (wxID_ANY
, BMET_LOAD_STATUS
,
55 BrowseMode::OnStatusEvent
)
59 //////////////////////////////////////////////////////////////////////////////
60 // Standalone functions
62 bool IsEditable(const std::string
&dbname
)
64 // add entry here for each edit dialog available
65 return dbname
== Contact::GetDBName() ||
66 dbname
== Calendar::GetDBName() ||
67 dbname
== Memo::GetDBName();
70 bool EditRecord(wxWindow
*parent
,
72 const Barry::TimeZones
&zones
,
75 ContactEditDlg
edit(parent
, rec
, editable
);
76 return edit
.ShowModal() == wxID_OK
;
79 bool EditRecord(wxWindow
*parent
,
81 const Barry::TimeZones
&zones
,
87 bool EditRecord(wxWindow
*parent
,
89 const Barry::TimeZones
&zones
,
92 CalendarEditDlg
edit(parent
, rec
, editable
, &zones
);
93 return edit
.ShowModal() == wxID_OK
;
96 bool EditRecord(wxWindow
*parent
,
98 const Barry::TimeZones
&zones
,
99 Barry::CalendarAll
&rec
)
104 bool EditRecord(wxWindow
*parent
,
106 const Barry::TimeZones
&zones
,
107 Barry::ContentStore
&rec
)
112 bool EditRecord(wxWindow
*parent
,
114 const Barry::TimeZones
&zones
,
120 bool EditRecord(wxWindow
*parent
,
122 const Barry::TimeZones
&zones
,
125 MemoEditDlg
edit(parent
, rec
, editable
);
126 return edit
.ShowModal() == wxID_OK
;
129 bool EditRecord(wxWindow
*parent
,
131 const Barry::TimeZones
&zones
,
137 bool EditRecord(wxWindow
*parent
,
139 const Barry::TimeZones
&zones
,
145 bool EditRecord(wxWindow
*parent
,
147 const Barry::TimeZones
&zones
,
148 Barry::PINMessage
&rec
)
153 bool EditRecord(wxWindow
*parent
,
155 const Barry::TimeZones
&zones
,
156 Barry::SavedMessage
&rec
)
161 bool EditRecord(wxWindow
*parent
,
163 const Barry::TimeZones
&zones
,
164 Barry::ServiceBook
&rec
)
169 bool EditRecord(wxWindow
*parent
,
171 const Barry::TimeZones
&zones
,
177 bool EditRecord(wxWindow
*parent
,
179 const Barry::TimeZones
&zones
,
185 bool EditRecord(wxWindow
*parent
,
187 const Barry::TimeZones
&zones
,
188 Barry::TimeZone
&rec
)
193 bool EditRecord(wxWindow
*parent
,
195 const Barry::TimeZones
&zones
,
196 Barry::HandheldAgent
&rec
)
202 //////////////////////////////////////////////////////////////////////////////
203 // GUIDesktopConnector
205 bool GUIDesktopConnector::PasswordPrompt(const Barry::BadPassword
&bp
,
206 std::string
&password_result
)
208 // create prompt based on exception data
210 oss
<< "Please enter device password: ("
211 << bp
.remaining_tries()
212 << " tries remaining)";
213 wxString
prompt(oss
.str().c_str(), wxConvUTF8
);
215 // ask user for device password
216 wxString pass
= wxGetPasswordFromUser(prompt
,
217 _T("Device Password"), _T(""), m_parent
);
219 password_result
= pass
.utf8_str();
221 // assume that a blank password means the user wishes to quit...
222 // wxWidgets doesn't seem to handle this very well?
223 return password_result
.size() > 0;
226 //////////////////////////////////////////////////////////////////////////////
229 DBDataCache::DBDataCache(DataCache::IndexType index
, const Barry::DBData
&raw
)
230 : DataCache(index
, raw
.GetUniqueId())
235 bool DBDataCache::Edit(wxWindow
*parent
,
237 const Barry::TimeZones
&zones
)
242 std::string
DBDataCache::GetDescription() const
248 //////////////////////////////////////////////////////////////////////////////
251 DBCache::DBCache(ThreadableDesktop
&tdesktop
, const std::string
&dbname
)
252 : m_tdesktop(tdesktop
)
256 DesktopInstancePtr dip
= m_tdesktop
.Get();
259 m_dbid
= dip
->Desktop().GetDBID(m_dbname
);
261 // load the record state table
262 dip
->Desktop().GetRecordStateTable(m_dbid
, m_state
);
265 AllRecordParser
ap(*this, *this);
266 RecordStateTable::StateMapType::iterator i
= m_state
.StateMap
.begin();
267 for( ; i
!= m_state
.StateMap
.end(); ++i
) {
268 m_index
= i
->second
.Index
; // save for the callback
269 dip
->Desktop().GetRecord(m_dbid
, m_index
, ap
);
272 // sort the list of records by description
280 DBCache::iterator
DBCache::Get(int list_offset
)
282 iterator i
= begin();
283 for( ; i
!= end() && list_offset
; ++i
, list_offset
-- )
288 DBCache::const_iterator
DBCache::Get(int list_offset
) const
290 const_iterator i
= begin();
291 for( ; i
!= end() && list_offset
; ++i
, list_offset
-- )
296 int DBCache::GetIndex(iterator record
) const
298 iterator i
= const_cast<DBCache
*> (this)->begin();
299 iterator e
= const_cast<DBCache
*> (this)->end();
300 for( int index
= 0; i
!= e
; ++i
, index
++ ) {
307 int DBCache::GetIndex(const_iterator record
) const
309 const_iterator i
= begin();
310 for( int index
= 0; i
!= end(); ++i
, index
++ ) {
317 DBCache::iterator
DBCache::Add(wxWindow
*parent
,
318 const Barry::TimeZones
&zones
,
319 iterator copy_record
)
323 #undef HANDLE_BUILDER
324 #define HANDLE_BUILDER(tname) \
325 if( m_dbname == Barry::tname::GetDBName() ) { \
327 if( copy_record != end() ) { \
328 RecordCache<Barry::tname> *rc = dynamic_cast<RecordCache<Barry::tname>* > (copy_record->get()); \
330 rec = rc->GetRecord(); \
333 p.reset( new RecordCache<Barry::tname>(0, rec) ); \
335 ALL_KNOWN_BUILDER_TYPES
337 // anything else is not addable or buildable
342 if( p
->Edit(parent
, true, zones
) ) {
343 // see if this record has a builder
344 Barry::Builder
*bp
= dynamic_cast<Barry::Builder
*> (p
.get());
349 // give record a new UniqueID
350 uint32_t record_id
= m_state
.MakeNewRecordId();
351 cout
<< "New recordID generated: 0x" << hex
<< record_id
<< endl
;
352 p
->SetIds(p
->GetStateIndex(), record_id
);
354 // add record to device
355 DesktopInstancePtr dip
= m_tdesktop
.Get();
356 Barry::Mode::Desktop
&desktop
= dip
->Desktop();
357 desktop
.AddRecord(m_dbid
, *bp
);
359 // update our copy of the record state table from device
360 desktop
.GetRecordStateTable(m_dbid
, m_state
);
361 cout
<< m_state
<< endl
;
363 // find our new record_id in list, to find the state index
365 if( !m_state
.GetIndex(record_id
, &new_index
) ) {
366 throw std::logic_error("Need to reconnect for adding a record?");
369 // update new state_index in the data cache record
370 p
->SetIds(new_index
, record_id
);
372 // add DataCachePtr to our own cache list
373 m_records
.push_front(p
);
375 // return iterator pointing to new record
383 bool DBCache::Edit(wxWindow
*parent
,
384 const Barry::TimeZones
&zones
,
387 if( record
== end() )
390 if( (*record
)->Edit(parent
, true, zones
) && (*record
)->IsBuildable() ) {
391 // see if this record has a builder
392 Barry::Builder
*bp
= dynamic_cast<Barry::Builder
*> ((*record
).get());
396 cout
<< "Changing device record with index: 0x" << hex
<< (*record
)->GetStateIndex() << endl
;
397 cout
<< m_state
<< endl
;
398 // update the device with new record data
399 DesktopInstancePtr dip
= m_tdesktop
.Get();
400 Barry::Mode::Desktop
&desktop
= dip
->Desktop();
401 desktop
.SetRecord(m_dbid
, (*record
)->GetStateIndex(), *bp
);
410 bool DBCache::Delete(wxWindow
*parent
, iterator record
)
412 if( record
== end() )
415 // prompt user with Yes / No message
416 wxString
desc((*record
)->GetDescription().c_str(), wxConvUTF8
);
417 int choice
= wxMessageBox(_T("Delete record: ") + desc
+ _T("?"),
418 _T("Record Delete"), wxYES_NO
| wxICON_QUESTION
, parent
);
420 // if no, return false
421 if( choice
!= wxYES
)
424 cout
<< "Deleting device record with index: 0x" << hex
<< (*record
)->GetStateIndex() << endl
;
425 cout
<< m_state
<< endl
;
426 // delete record from device
427 DesktopInstancePtr dip
= m_tdesktop
.Get();
428 Barry::Mode::Desktop
&desktop
= dip
->Desktop();
429 desktop
.DeleteRecord(m_dbid
, (*record
)->GetStateIndex());
431 // remove record from cache list
432 m_records
.erase(record
);
436 // For Barry::AllRecordStore
438 #define HANDLE_PARSER(tname) \
439 void DBCache::operator() (const Barry::tname &rec) \
441 DataCachePtr p( new RecordCache<Barry::tname>(m_index, rec) ); \
442 m_records.push_front(p); \
444 ALL_KNOWN_PARSER_TYPES
447 void DBCache::ParseRecord(const Barry::DBData
&data
,
448 const Barry::IConverter
*ic
)
450 DataCachePtr
p( new DBDataCache(m_index
, data
) );
451 m_records
.push_front(p
);
455 //////////////////////////////////////////////////////////////////////////////
458 DBMap::DBMap(ThreadableDesktop
&tdesktop
)
459 : m_tdesktop(tdesktop
)
461 if( pthread_mutex_init(&m_map_mutex
, NULL
) ) {
462 throw Barry::Error("Failed to create map mutex");
465 if( pthread_mutex_init(&m_load_mutex
, NULL
) ) {
466 throw Barry::Error("Failed to create load mutex");
470 DBMap::DBCachePtr
DBMap::LoadDBCache(const std::string
&dbname
)
472 // first, check for pre-loaded data, before the load lock,
473 // to make sure we return pre-loaded data with utmost haste
475 scoped_lock
map_lock(m_map_mutex
);
477 MapType::iterator i
= m_map
.find(dbname
);
478 if( i
!= m_map
.end() )
482 // if not found, lock and load, but be careful, since we
483 // don't want to open a window here for loading a db twice
484 scoped_lock
load_lock(m_load_mutex
);
486 // check again for pre-loaded data, since between
487 // map.unlock and load.lock there could have been
488 // another successful load
490 scoped_lock
map_lock(m_map_mutex
);
492 MapType::iterator i
= m_map
.find(dbname
);
493 if( i
!= m_map
.end() )
497 // do the load, without map.lock, since this can take a
498 // significant amount of time
499 DBCachePtr
p( new DBCache(m_tdesktop
, dbname
) );
501 // lock once more to update the map, and then done
502 scoped_lock
map_lock(m_map_mutex
);
507 DBMap::DBCachePtr
DBMap::GetDBCache(const std::string
&dbname
)
509 scoped_lock
lock(m_map_mutex
);
511 MapType::iterator i
= m_map
.find(dbname
);
512 if( i
!= m_map
.end() )
518 //////////////////////////////////////////////////////////////////////////////
521 BrowseMode::BrowseMode(wxWindow
*parent
, const ProbeResult
&device
)
527 // create device identifying string
528 m_device_id_str
= wxString(device
.GetDisplayName().c_str(), wxConvUTF8
);
531 // connect to the device
533 m_con
.reset( new GUIDesktopConnector(m_parent
, "", "utf-8", device
) );
535 m_tdesktop
.reset( new ThreadableDesktop(*m_con
) );
537 // keep our own copy, and sort by name for later
538 m_dbdb
= m_con
->GetDesktop().GetDBDB();
541 // store a copy of the time zone set for record editing
542 if( TimeZones::IsLoadable(m_con
->GetDesktop()) ) {
543 // load time zones from device itself
544 m_zones
.reset( new TimeZones(m_con
->GetDesktop()) );
547 // use static time zone table from Barry library
548 m_zones
.reset( new TimeZones
);
553 // create our DBMap and give it the threadable desktop,
554 // now that we're finished doing any desktop USB work
555 m_dbmap
.reset( new DBMap(*m_tdesktop
) );
558 // From here down, we assume that our constructor succeeds, with
562 // fire off a background thread to cache database records
563 // in advance... if it fails, don't worry about it
564 m_abort_flag
= false;
565 int ret
= pthread_create(&m_cache_thread
, NULL
,
566 &BrowseMode::FillCacheThread
, this);
568 m_abort_flag
= true; // no need to join later
570 // connect ourselves to the parent's event handling chain
571 // do this last, so that we are guaranteed our destructor
572 // will run, in case of exceptions
573 m_parent
->PushEventHandler(this);
576 BrowseMode::~BrowseMode()
578 // unhook that event handler!
579 m_parent
->PopEventHandler();
581 // make sure the cache thread is finished before we destroy it :-)
582 if( !m_abort_flag
) {
585 pthread_join(m_cache_thread
, &junk
);
589 std::string
& GetDBName(Barry::DatabaseDatabase::Database
&db
)
594 void BrowseMode::SendStatusEvent(const std::string
&dbname
)
596 wxCommandEvent
event(BMET_LOAD_STATUS
, wxID_ANY
);
597 event
.SetEventObject(this);
599 if( dbname
.size() ) {
600 wxString
msg(_T("Loading: "));
601 msg
+= wxString(dbname
.c_str(), wxConvUTF8
);
602 event
.SetString(msg
);
605 event
.SetString(_T(""));
608 AddPendingEvent(event
);
611 void BrowseMode::CreateControls()
613 m_top_sizer
.reset( new wxBoxSizer(wxVERTICAL
) );
615 // make space for the main header, which is not part of our
617 m_top_sizer
->AddSpacer(MAIN_HEADER_OFFSET
);
621 // add list boxes to main area, the list_sizer
624 wxStaticBoxSizer
*list_sizer
= new wxStaticBoxSizer(wxHORIZONTAL
,
625 m_parent
, m_device_id_str
);
627 // add database listctrl
628 m_dbdb_list
.reset (new wxListCtrl(m_parent
, BrowseMode_DBDBList
,
629 wxDefaultPosition
, wxDefaultSize
,
630 wxLC_REPORT
| wxLC_SINGLE_SEL
) ); //| wxLC_VRULES
631 // int max_db_width = GetMaxWidth(m_dbdb_list.get(),
632 // m_dbdb.Databases.begin(), m_dbdb.Databases.end(),
634 list_sizer
->Add( m_dbdb_list
.get(), 4, wxEXPAND
| wxALL
, 4 );
636 // add the record listctrl
637 m_record_list
.reset(new wxListCtrl(m_parent
, BrowseMode_RecordList
,
638 wxDefaultPosition
, wxDefaultSize
,
639 wxLC_REPORT
| wxLC_SINGLE_SEL
) ); //| wxLC_VRULES
640 list_sizer
->Add( m_record_list
.get(), 5, wxEXPAND
| wxALL
, 4 );
642 // add list sizer to top sizer
643 m_top_sizer
->Add( list_sizer
, 1, wxEXPAND
| wxALL
, 4 );
646 // add "show all" checkbox and load status static textbox, inside sizer
649 wxBoxSizer
*status_sizer
= new wxBoxSizer(wxHORIZONTAL
);
651 m_show_all_checkbox
.reset( new wxCheckBox(m_parent
,
652 BrowseMode_ShowAllCheckbox
,
653 _T("Show All Databases"),
654 wxDefaultPosition
, wxDefaultSize
,
656 status_sizer
->Add( m_show_all_checkbox
.get(), 0, wxEXPAND
, 0 );
657 m_show_all_checkbox
->SetValue(m_show_all
);
659 status_sizer
->AddStretchSpacer();
661 m_load_status_text
.reset( new wxStaticText(m_parent
,
662 BrowseMode_LoadStatusText
,
664 wxDefaultPosition
, wxSize(200, -1),
665 wxST_NO_AUTORESIZE
) );
666 status_sizer
->Add( m_load_status_text
.get(), 0,
667 wxEXPAND
| wxALIGN_CENTRE_VERTICAL
, 0 );
669 m_top_sizer
->Add( status_sizer
, 0, wxEXPAND
| wxALL
, 4 );
677 // add bottom buttons - these go in the bottom FOOTER area
678 // so their heights must be fixed to MAIN_HEADER_OFFSET
679 // minus a border of 5px top and bottom
680 wxSize
footer(-1, MAIN_HEADER_OFFSET
- 5 - 5);
681 wxBoxSizer
*buttons
= new wxBoxSizer(wxHORIZONTAL
);
682 m_add_record_button
.reset( new wxButton(m_parent
,
683 BrowseMode_AddRecordButton
, _T("Add..."),
684 wxDefaultPosition
, footer
) );
685 m_copy_record_button
.reset( new wxButton(m_parent
,
686 BrowseMode_CopyRecordButton
, _T("Copy..."),
687 wxDefaultPosition
, footer
) );
688 m_edit_record_button
.reset( new wxButton(m_parent
,
689 BrowseMode_EditRecordButton
, _T("Edit..."),
690 wxDefaultPosition
, footer
));
691 m_delete_record_button
.reset( new wxButton(m_parent
,
692 BrowseMode_DeleteRecordButton
, _T("Delete..."),
693 wxDefaultPosition
, footer
) );
694 buttons
->Add(m_add_record_button
.get(), 0, wxRIGHT
, 5);
695 buttons
->Add(m_copy_record_button
.get(), 0, wxRIGHT
, 5);
696 buttons
->Add(m_edit_record_button
.get(), 0, wxRIGHT
, 5);
697 buttons
->Add(m_delete_record_button
.get(), 0, wxRIGHT
, 5);
698 m_top_sizer
->Add(buttons
, 0, wxALL
| wxALIGN_RIGHT
, 5);
701 // recalc size of children and add columns
703 wxSize client_size
= m_parent
->GetClientSize();
704 m_top_sizer
->SetDimension(0, 0,
705 client_size
.GetWidth(), client_size
.GetHeight());
708 wxSize dbdb_size
= m_dbdb_list
->GetClientSize();
709 int scroll_width
= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
);
710 int size
= dbdb_size
.GetWidth() - scroll_width
;
711 m_dbdb_list
->InsertColumn(0, _T("Databases"), wxLIST_FORMAT_LEFT
,
713 m_dbdb_list
->InsertColumn(1, _T("Count"), wxLIST_FORMAT_LEFT
,
714 size
* 0.20 + scroll_width
); // add back the scroll width
715 // so it doesn't look half-baked when
716 // there is no scroll bar
720 wxSize record_size
= m_record_list
->GetClientSize();
721 m_record_list
->InsertColumn(0, _T("Record Description"),
722 wxLIST_FORMAT_LEFT
, record_size
.GetWidth());
731 // attempt to re-select the devices as we last saw them
732 ReselectDevices(m_device_set->String2Subset(wxGetApp().GetGlobalConfig().GetKey("SelectedDevices")));
738 int BrowseMode::GUItoDBDBIndex(int gui_index
)
743 DatabaseDatabase::DatabaseArrayType::const_iterator
744 i
= m_dbdb
.Databases
.begin(), e
= m_dbdb
.Databases
.end();
745 for( int index
= 0; i
!= e
; ++i
, index
++ ) {
746 // only bump index on the parsable databases
747 if( !m_show_all
&& !IsParsable(i
->Name
) )
760 void BrowseMode::FillDBDBList()
763 m_dbdb_list
->DeleteAllItems();
765 DatabaseDatabase::DatabaseArrayType::const_iterator
766 i
= m_dbdb
.Databases
.begin(), e
= m_dbdb
.Databases
.end();
767 for( int index
= 0; i
!= e
; ++i
, index
++ ) {
768 // Only show parsable databases, depending on GUI
769 if( !m_show_all
&& !IsParsable(i
->Name
) )
773 wxString
text(i
->Name
.c_str(), wxConvUTF8
);
774 long item
= m_dbdb_list
->InsertItem(index
, text
);
778 oss
<< dec
<< i
->RecordCount
;
779 text
= wxString(oss
.str().c_str(), wxConvUTF8
);
780 m_dbdb_list
->SetItem(item
, 1, text
);
786 void BrowseMode::FillRecordList(const std::string
&dbname
)
791 m_record_list
->DeleteAllItems();
794 DBMap::DBCachePtr db
= m_dbmap
->LoadDBCache(dbname
);
796 // cycle through the cache, and insert the descriptions
797 // given for each record
798 DBCache::const_iterator b
= db
->begin(), e
= db
->end();
799 for( int index
= 0; b
!= e
; ++b
, index
++ ) {
800 wxString
text((*b
)->GetDescription().c_str(), wxConvUTF8
);
802 m_record_list
->InsertItem(index
, text
);
805 } catch( Barry::Error
&be
) {
806 cerr
<< be
.what() << endl
;
810 void BrowseMode::UpdateButtons()
812 int selected_count
= m_record_list
->GetSelectedItemCount();
814 // can only add if we have a builder and dialog for this record type
815 m_add_record_button
->Enable(m_buildable
&& m_editable
);
817 // can only copy or edit if we have a builder, a dialog, and
818 // only 1 is selected
819 m_copy_record_button
->Enable(
820 m_buildable
&& m_editable
&& selected_count
== 1);
821 m_edit_record_button
->Enable(
822 m_buildable
&& m_editable
&& selected_count
== 1);
824 // can only delete if something is selected
825 m_delete_record_button
->Enable(selected_count
> 0);
828 void BrowseMode::FillCache()
830 // cycle through the dbdb and load all Parsable databases
831 DatabaseDatabase::DatabaseArrayType::const_iterator
832 i
= m_dbdb
.Databases
.begin(), e
= m_dbdb
.Databases
.end();
833 for( ; i
!= e
; ++i
) {
834 if( IsParsable(i
->Name
) ) try {
835 SendStatusEvent(i
->Name
);
836 m_dbmap
->LoadDBCache(i
->Name
);
837 } catch( Barry::Error
&be
) {
838 cerr
<< be
.what() << endl
;
851 void* BrowseMode::FillCacheThread(void *bobj
)
853 BrowseMode
*bm
= (BrowseMode
*) bobj
;
858 void BrowseMode::OnDBDBListSelChange(wxListEvent
&event
)
861 int index
= GUItoDBDBIndex(event
.GetIndex());
862 m_current_dbname
= m_dbdb
.Databases
.at(index
).Name
;
863 m_buildable
= ::IsBuildable(m_current_dbname
);
864 m_editable
= ::IsEditable(m_current_dbname
);
865 m_current_record_item
= -1;
867 FillRecordList(m_current_dbname
);
871 void BrowseMode::OnRecordListSelChange(wxListEvent
&event
)
873 // grab the cache for the current database... Get is ok here,
874 // since the cache is already loaded by the main db list
875 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
879 // grab the record list index
880 m_current_record_item
= event
.GetIndex();
881 // m_current_record_item = m_record_list->GetNextItem(
882 // m_current_record_item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
887 void BrowseMode::OnRecordListActivated(wxListEvent
&event
)
893 void BrowseMode::OnShowAll(wxCommandEvent
&event
)
895 m_show_all
= !m_show_all
;
899 void BrowseMode::OnAddRecord(wxCommandEvent
&event
)
901 // grab the cache for the current database... Get is ok here,
902 // since the cache is already loaded by the main db list
903 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
907 DBCache::iterator i
= p
->Add(m_parent
, *m_zones
, p
->end());
908 if( i
!= p
->end() ) {
909 wxString
text((*i
)->GetDescription().c_str(), wxConvUTF8
);
911 // insert new record in same spot as DBCache has it
912 m_current_record_item
= p
->GetIndex(i
);
913 m_record_list
->InsertItem(m_current_record_item
, text
);
917 void BrowseMode::OnCopyRecord(wxCommandEvent
&event
)
919 // grab the cache for the current database... Get is ok here,
920 // since the cache is already loaded by the main db list
921 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
925 DBCache::iterator source
= p
->Get(m_current_record_item
);
926 DBCache::iterator i
= p
->Add(m_parent
, *m_zones
, source
);
927 if( i
!= p
->end() ) {
928 wxString
text((*i
)->GetDescription().c_str(), wxConvUTF8
);
930 // insert new record in same spot as DBCache has it
931 m_current_record_item
= p
->GetIndex(i
);
932 m_record_list
->InsertItem(m_current_record_item
, text
);
936 void BrowseMode::OnEditRecord(wxCommandEvent
&event
)
938 // grab the cache for the current database... Get is ok here,
939 // since the cache is already loaded by the main db list
940 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
944 DBCache::iterator i
= p
->Get(m_current_record_item
);
945 if( p
->Edit(m_parent
, *m_zones
, i
) ) {
946 wxString
text((*i
)->GetDescription().c_str(), wxConvUTF8
);
947 m_record_list
->SetItem(m_current_record_item
, 0, text
);
951 void BrowseMode::OnDeleteRecord(wxCommandEvent
&event
)
953 // grab the cache for the current database... Get is ok here,
954 // since the cache is already loaded by the main db list
955 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
959 DBCache::iterator i
= p
->Get(m_current_record_item
);
960 if( p
->Delete(m_parent
, i
) ) {
961 m_record_list
->DeleteItem(m_current_record_item
);
965 void BrowseMode::OnStatusEvent(wxCommandEvent
&event
)
967 m_load_status_text
->SetLabel(event
.GetString());