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 "MemoEditDlg.h"
26 #include "windowids.h"
32 using namespace Barry
;
34 BEGIN_EVENT_TABLE(BrowseMode
, wxEvtHandler
)
35 EVT_LIST_ITEM_SELECTED(BrowseMode_DBDBList
,
36 BrowseMode::OnDBDBListSelChange
)
37 EVT_LIST_ITEM_SELECTED(BrowseMode_RecordList
,
38 BrowseMode::OnRecordListSelChange
)
39 EVT_LIST_ITEM_ACTIVATED(BrowseMode_RecordList
,
40 BrowseMode::OnRecordListActivated
)
41 EVT_CHECKBOX (BrowseMode_ShowAllCheckbox
,
42 BrowseMode::OnShowAll
)
43 EVT_BUTTON (BrowseMode_AddRecordButton
,
44 BrowseMode::OnAddRecord
)
45 EVT_BUTTON (BrowseMode_CopyRecordButton
,
46 BrowseMode::OnCopyRecord
)
47 EVT_BUTTON (BrowseMode_EditRecordButton
,
48 BrowseMode::OnEditRecord
)
49 EVT_BUTTON (BrowseMode_DeleteRecordButton
,
50 BrowseMode::OnDeleteRecord
)
54 //////////////////////////////////////////////////////////////////////////////
55 // Standalone functions
57 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Contact
&rec
)
59 ContactEditDlg
edit(parent
, rec
, editable
);
60 return edit
.ShowModal() == wxID_OK
;
63 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Bookmark
&rec
)
68 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Calendar
&rec
)
73 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::CalendarAll
&rec
)
78 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::ContentStore
&rec
)
83 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Folder
&rec
)
88 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Memo
&rec
)
90 MemoEditDlg
edit(parent
, rec
, editable
);
91 return edit
.ShowModal() == wxID_OK
;
94 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Message
&rec
)
99 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::CallLog
&rec
)
104 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::PINMessage
&rec
)
109 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::SavedMessage
&rec
)
114 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::ServiceBook
&rec
)
119 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Sms
&rec
)
124 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Task
&rec
)
129 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::Timezone
&rec
)
134 bool EditRecord(wxWindow
*parent
, bool editable
, Barry::HandheldAgent
&rec
)
140 //////////////////////////////////////////////////////////////////////////////
141 // GUIDesktopConnector
143 bool GUIDesktopConnector::PasswordPrompt(const Barry::BadPassword
&bp
,
144 std::string
&password_result
)
146 // create prompt based on exception data
148 oss
<< "Please enter device password: ("
149 << bp
.remaining_tries()
150 << " tries remaining)";
151 wxString
prompt(oss
.str().c_str(), wxConvUTF8
);
153 // ask user for device password
154 wxString pass
= wxGetPasswordFromUser(prompt
,
155 _T("Device Password"), _T(""), m_parent
);
157 password_result
= pass
.utf8_str();
159 // assume that a blank password means the user wishes to quit...
160 // wxWidgets doesn't seem to handle this very well?
161 return password_result
.size() > 0;
164 //////////////////////////////////////////////////////////////////////////////
167 DBDataCache::DBDataCache(DataCache::IndexType index
, const Barry::DBData
&raw
)
168 : DataCache(index
, raw
.GetUniqueId())
173 bool DBDataCache::Edit(wxWindow
*parent
, bool editable
)
178 std::string
DBDataCache::GetDescription() const
184 //////////////////////////////////////////////////////////////////////////////
187 DBCache::DBCache(ThreadableDesktop
&tdesktop
, const std::string
&dbname
)
188 : m_tdesktop(tdesktop
)
192 DesktopInstancePtr dip
= m_tdesktop
.Get();
195 m_dbid
= dip
->Desktop().GetDBID(m_dbname
);
197 // load the record state table
198 dip
->Desktop().GetRecordStateTable(m_dbid
, m_state
);
201 AllRecordParser
ap(*this, *this);
202 RecordStateTable::StateMapType::iterator i
= m_state
.StateMap
.begin();
203 for( ; i
!= m_state
.StateMap
.end(); ++i
) {
204 m_index
= i
->second
.Index
; // save for the callback
205 dip
->Desktop().GetRecord(m_dbid
, m_index
, ap
);
208 // sort the list of records by description
216 DBCache::iterator
DBCache::Get(int list_offset
)
218 iterator i
= begin();
219 for( ; i
!= end() && list_offset
; ++i
, list_offset
-- )
224 DBCache::const_iterator
DBCache::Get(int list_offset
) const
226 const_iterator i
= begin();
227 for( ; i
!= end() && list_offset
; ++i
, list_offset
-- )
232 int DBCache::GetIndex(iterator record
) const
234 iterator i
= const_cast<DBCache
*> (this)->begin();
235 iterator e
= const_cast<DBCache
*> (this)->end();
236 for( int index
= 0; i
!= e
; ++i
, index
++ ) {
243 int DBCache::GetIndex(const_iterator record
) const
245 const_iterator i
= begin();
246 for( int index
= 0; i
!= end(); ++i
, index
++ ) {
253 DBCache::iterator
DBCache::Add(wxWindow
*parent
, iterator copy_record
)
257 #undef HANDLE_BUILDER
258 #define HANDLE_BUILDER(tname) \
259 if( m_dbname == Barry::tname::GetDBName() ) { \
261 if( copy_record != end() ) { \
262 RecordCache<Barry::tname> *rc = dynamic_cast<RecordCache<Barry::tname>* > (copy_record->get()); \
264 rec = rc->GetRecord(); \
267 p.reset( new RecordCache<Barry::tname>(0, rec) ); \
269 ALL_KNOWN_BUILDER_TYPES
271 // anything else is not addable or buildable
276 if( p
->Edit(parent
, true) ) {
277 // see if this record has a builder
278 Barry::Builder
*bp
= dynamic_cast<Barry::Builder
*> (p
.get());
283 // give record a new UniqueID
284 uint32_t record_id
= m_state
.MakeNewRecordId();
285 cout
<< "New recordID generated: 0x" << hex
<< record_id
<< endl
;
286 p
->SetIds(p
->GetStateIndex(), record_id
);
288 // add record to device
289 DesktopInstancePtr dip
= m_tdesktop
.Get();
290 Barry::Mode::Desktop
&desktop
= dip
->Desktop();
291 desktop
.AddRecord(m_dbid
, *bp
);
293 // update our copy of the record state table from device
294 desktop
.GetRecordStateTable(m_dbid
, m_state
);
295 cout
<< m_state
<< endl
;
297 // find our new record_id in list, to find the state index
299 if( !m_state
.GetIndex(record_id
, &new_index
) ) {
300 throw std::logic_error("Need to reconnect for adding a record?");
303 // update new state_index in the data cache record
304 p
->SetIds(new_index
, record_id
);
306 // add DataCachePtr to our own cache list
307 m_records
.push_front(p
);
309 // return iterator pointing to new record
317 bool DBCache::Edit(wxWindow
*parent
, iterator record
)
319 if( record
== end() )
322 if( (*record
)->Edit(parent
, true) && (*record
)->IsBuildable() ) {
323 // see if this record has a builder
324 Barry::Builder
*bp
= dynamic_cast<Barry::Builder
*> ((*record
).get());
328 cout
<< "Changing device record with index: 0x" << hex
<< (*record
)->GetStateIndex() << endl
;
329 cout
<< m_state
<< endl
;
330 // update the device with new record data
331 DesktopInstancePtr dip
= m_tdesktop
.Get();
332 Barry::Mode::Desktop
&desktop
= dip
->Desktop();
333 desktop
.SetRecord(m_dbid
, (*record
)->GetStateIndex(), *bp
);
342 bool DBCache::Delete(wxWindow
*parent
, iterator record
)
344 if( record
== end() )
347 // prompt user with Yes / No message
348 wxString
desc((*record
)->GetDescription().c_str(), wxConvUTF8
);
349 int choice
= wxMessageBox(_T("Delete record: ") + desc
+ _T("?"),
350 _T("Record Delete"), wxYES_NO
| wxICON_QUESTION
, parent
);
352 // if no, return false
353 if( choice
!= wxYES
)
356 cout
<< "Deleting device record with index: 0x" << hex
<< (*record
)->GetStateIndex() << endl
;
357 cout
<< m_state
<< endl
;
358 // delete record from device
359 DesktopInstancePtr dip
= m_tdesktop
.Get();
360 Barry::Mode::Desktop
&desktop
= dip
->Desktop();
361 desktop
.DeleteRecord(m_dbid
, (*record
)->GetStateIndex());
363 // remove record from cache list
364 m_records
.erase(record
);
368 // For Barry::AllRecordStore
370 #define HANDLE_PARSER(tname) \
371 void DBCache::operator() (const Barry::tname &rec) \
373 DataCachePtr p( new RecordCache<Barry::tname>(m_index, rec) ); \
374 m_records.push_front(p); \
376 ALL_KNOWN_PARSER_TYPES
379 void DBCache::ParseRecord(const Barry::DBData
&data
,
380 const Barry::IConverter
*ic
)
382 DataCachePtr
p( new DBDataCache(m_index
, data
) );
383 m_records
.push_front(p
);
387 //////////////////////////////////////////////////////////////////////////////
390 DBMap::DBMap(ThreadableDesktop
&tdesktop
)
391 : m_tdesktop(tdesktop
)
393 if( pthread_mutex_init(&m_map_mutex
, NULL
) ) {
394 throw Barry::Error("Failed to create map mutex");
397 if( pthread_mutex_init(&m_load_mutex
, NULL
) ) {
398 throw Barry::Error("Failed to create load mutex");
402 DBMap::DBCachePtr
DBMap::LoadDBCache(const std::string
&dbname
)
404 // first, check for pre-loaded data, before the load lock,
405 // to make sure we return pre-loaded data with utmost haste
407 scoped_lock
map_lock(m_map_mutex
);
409 MapType::iterator i
= m_map
.find(dbname
);
410 if( i
!= m_map
.end() )
414 // if not found, lock and load, but be careful, since we
415 // don't want to open a window here for loading a db twice
416 scoped_lock
load_lock(m_load_mutex
);
418 // check again for pre-loaded data, since between
419 // map.unlock and load.lock there could have been
420 // another successful load
422 scoped_lock
map_lock(m_map_mutex
);
424 MapType::iterator i
= m_map
.find(dbname
);
425 if( i
!= m_map
.end() )
429 // do the load, without map.lock, since this can take a
430 // significant amount of time
431 DBCachePtr
p( new DBCache(m_tdesktop
, dbname
) );
433 // lock once more to update the map, and then done
434 scoped_lock
map_lock(m_map_mutex
);
439 DBMap::DBCachePtr
DBMap::GetDBCache(const std::string
&dbname
)
441 scoped_lock
lock(m_map_mutex
);
443 MapType::iterator i
= m_map
.find(dbname
);
444 if( i
!= m_map
.end() )
450 //////////////////////////////////////////////////////////////////////////////
453 BrowseMode::BrowseMode(wxWindow
*parent
, const ProbeResult
&device
)
458 // create device identifying string
459 m_device_id_str
= wxString(device
.GetDisplayName().c_str(), wxConvUTF8
);
462 // connect to the device
464 m_con
.reset( new GUIDesktopConnector(m_parent
, "", "utf-8", device
) );
466 m_tdesktop
.reset( new ThreadableDesktop(*m_con
) );
468 // keep our own copy, and sort by name for later
469 m_dbdb
= m_con
->GetDesktop().GetDBDB();
474 // create our DBMap and give it the threadable desktop,
475 // now that we're finished doing any desktop USB work
476 m_dbmap
.reset( new DBMap(*m_tdesktop
) );
479 // From here down, we assume that our constructor succeeds, with
483 // fire off a background thread to cache database records
484 // in advance... if it fails, don't worry about it
485 m_abort_flag
= false;
486 int ret
= pthread_create(&m_cache_thread
, NULL
,
487 &BrowseMode::FillCacheThread
, this);
489 m_abort_flag
= true; // no need to join later
491 // connect ourselves to the parent's event handling chain
492 // do this last, so that we are guaranteed our destructor
493 // will run, in case of exceptions
494 m_parent
->PushEventHandler(this);
497 BrowseMode::~BrowseMode()
499 // unhook that event handler!
500 m_parent
->PopEventHandler();
502 // make sure the cache thread is finished before we destroy it :-)
503 if( !m_abort_flag
) {
506 pthread_join(m_cache_thread
, &junk
);
510 std::string
& GetDBName(Barry::DatabaseDatabase::Database
&db
)
515 void BrowseMode::CreateControls()
517 m_top_sizer
.reset( new wxBoxSizer(wxVERTICAL
) );
519 // make space for the main header, which is not part of our
521 m_top_sizer
->AddSpacer(MAIN_HEADER_OFFSET
);
525 // add list boxes to main area, the list_sizer
528 wxStaticBoxSizer
*list_sizer
= new wxStaticBoxSizer(wxHORIZONTAL
,
529 m_parent
, m_device_id_str
);
531 // add database listctrl
532 m_dbdb_list
.reset (new wxListCtrl(m_parent
, BrowseMode_DBDBList
,
533 wxDefaultPosition
, wxDefaultSize
,
534 wxLC_REPORT
| wxLC_SINGLE_SEL
) ); //| wxLC_VRULES
535 // int max_db_width = GetMaxWidth(m_dbdb_list.get(),
536 // m_dbdb.Databases.begin(), m_dbdb.Databases.end(),
538 list_sizer
->Add( m_dbdb_list
.get(), 4, wxEXPAND
| wxALL
, 4 );
540 // add the record listctrl
541 m_record_list
.reset(new wxListCtrl(m_parent
, BrowseMode_RecordList
,
542 wxDefaultPosition
, wxDefaultSize
,
543 wxLC_REPORT
| wxLC_SINGLE_SEL
) ); //| wxLC_VRULES
544 list_sizer
->Add( m_record_list
.get(), 5, wxEXPAND
| wxALL
, 4 );
546 // add list sizer to top sizer
547 m_top_sizer
->Add( list_sizer
, 1, wxEXPAND
| wxALL
, 4 );
550 // add "show all" checkbox
553 m_show_all_checkbox
.reset( new wxCheckBox(m_parent
,
554 BrowseMode_ShowAllCheckbox
,
555 _T("Show All Databases"),
556 wxDefaultPosition
, wxDefaultSize
,
558 m_top_sizer
->Add( m_show_all_checkbox
.get(), 0, wxEXPAND
| wxALL
, 4 );
559 m_show_all_checkbox
->SetValue(m_show_all
);
565 // add bottom buttons - these go in the bottom FOOTER area
566 // so their heights must be fixed to MAIN_HEADER_OFFSET
567 // minus a border of 5px top and bottom
568 wxSize
footer(-1, MAIN_HEADER_OFFSET
- 5 - 5);
569 wxBoxSizer
*buttons
= new wxBoxSizer(wxHORIZONTAL
);
570 m_add_record_button
.reset( new wxButton(m_parent
,
571 BrowseMode_AddRecordButton
, _T("Add..."),
572 wxDefaultPosition
, footer
) );
573 m_copy_record_button
.reset( new wxButton(m_parent
,
574 BrowseMode_CopyRecordButton
, _T("Copy..."),
575 wxDefaultPosition
, footer
) );
576 m_edit_record_button
.reset( new wxButton(m_parent
,
577 BrowseMode_EditRecordButton
, _T("Edit..."),
578 wxDefaultPosition
, footer
));
579 m_delete_record_button
.reset( new wxButton(m_parent
,
580 BrowseMode_DeleteRecordButton
, _T("Delete..."),
581 wxDefaultPosition
, footer
) );
582 buttons
->Add(m_add_record_button
.get(), 0, wxRIGHT
, 5);
583 buttons
->Add(m_copy_record_button
.get(), 0, wxRIGHT
, 5);
584 buttons
->Add(m_edit_record_button
.get(), 0, wxRIGHT
, 5);
585 buttons
->Add(m_delete_record_button
.get(), 0, wxRIGHT
, 5);
586 m_top_sizer
->Add(buttons
, 0, wxALL
| wxALIGN_RIGHT
, 5);
589 // recalc size of children and add columns
591 wxSize client_size
= m_parent
->GetClientSize();
592 m_top_sizer
->SetDimension(0, 0,
593 client_size
.GetWidth(), client_size
.GetHeight());
596 wxSize dbdb_size
= m_dbdb_list
->GetClientSize();
597 int scroll_width
= wxSystemSettings::GetMetric(wxSYS_VSCROLL_X
);
598 int size
= dbdb_size
.GetWidth() - scroll_width
;
599 m_dbdb_list
->InsertColumn(0, _T("Databases"), wxLIST_FORMAT_LEFT
,
601 m_dbdb_list
->InsertColumn(1, _T("Count"), wxLIST_FORMAT_LEFT
,
602 size
* 0.20 + scroll_width
); // add back the scroll width
603 // so it doesn't look half-baked when
604 // there is no scroll bar
608 wxSize record_size
= m_record_list
->GetClientSize();
609 m_record_list
->InsertColumn(0, _T("Record Description"),
610 wxLIST_FORMAT_LEFT
, record_size
.GetWidth());
619 // attempt to re-select the devices as we last saw them
620 ReselectDevices(m_device_set->String2Subset(wxGetApp().GetGlobalConfig().GetKey("SelectedDevices")));
626 int BrowseMode::GUItoDBDBIndex(int gui_index
)
631 DatabaseDatabase::DatabaseArrayType::const_iterator
632 i
= m_dbdb
.Databases
.begin(), e
= m_dbdb
.Databases
.end();
633 for( int index
= 0; i
!= e
; ++i
, index
++ ) {
634 // only bump index on the parsable databases
635 if( !m_show_all
&& !IsParsable(i
->Name
) )
648 void BrowseMode::FillDBDBList()
651 m_dbdb_list
->DeleteAllItems();
653 DatabaseDatabase::DatabaseArrayType::const_iterator
654 i
= m_dbdb
.Databases
.begin(), e
= m_dbdb
.Databases
.end();
655 for( int index
= 0; i
!= e
; ++i
, index
++ ) {
656 // Only show parsable databases, depending on GUI
657 if( !m_show_all
&& !IsParsable(i
->Name
) )
661 wxString
text(i
->Name
.c_str(), wxConvUTF8
);
662 long item
= m_dbdb_list
->InsertItem(index
, text
);
666 oss
<< dec
<< i
->RecordCount
;
667 text
= wxString(oss
.str().c_str(), wxConvUTF8
);
668 m_dbdb_list
->SetItem(item
, 1, text
);
674 void BrowseMode::FillRecordList(const std::string
&dbname
)
679 m_record_list
->DeleteAllItems();
682 DBMap::DBCachePtr db
= m_dbmap
->LoadDBCache(dbname
);
684 // cycle through the cache, and insert the descriptions
685 // given for each record
686 DBCache::const_iterator b
= db
->begin(), e
= db
->end();
687 for( int index
= 0; b
!= e
; ++b
, index
++ ) {
688 wxString
text((*b
)->GetDescription().c_str(), wxConvUTF8
);
690 m_record_list
->InsertItem(index
, text
);
693 } catch( Barry::Error
&be
) {
694 cerr
<< be
.what() << endl
;
698 void BrowseMode::UpdateButtons()
700 int selected_count
= m_record_list
->GetSelectedItemCount();
702 // can only add if we have a builder for this record type
703 m_add_record_button
->Enable(m_buildable
);
704 // can only copy or edit if we have a builder, and only 1 is selected
705 m_copy_record_button
->Enable(m_buildable
&& selected_count
== 1);
706 m_edit_record_button
->Enable(m_buildable
&& selected_count
== 1);
707 // can only delete if something is selected
708 m_delete_record_button
->Enable(selected_count
> 0);
711 void BrowseMode::FillCache()
713 // cycle through the dbdb and load all Parsable databases
714 DatabaseDatabase::DatabaseArrayType::const_iterator
715 i
= m_dbdb
.Databases
.begin(), e
= m_dbdb
.Databases
.end();
716 for( ; i
!= e
; ++i
) {
717 if( IsParsable(i
->Name
) ) try {
718 m_dbmap
->LoadDBCache(i
->Name
);
719 } catch( Barry::Error
&be
) {
720 cerr
<< be
.what() << endl
;
731 void* BrowseMode::FillCacheThread(void *bobj
)
733 BrowseMode
*bm
= (BrowseMode
*) bobj
;
738 void BrowseMode::OnDBDBListSelChange(wxListEvent
&event
)
741 int index
= GUItoDBDBIndex(event
.GetIndex());
742 m_current_dbname
= m_dbdb
.Databases
.at(index
).Name
;
743 m_buildable
= ::IsBuildable(m_current_dbname
);
744 m_current_record_item
= -1;
746 FillRecordList(m_current_dbname
);
750 void BrowseMode::OnRecordListSelChange(wxListEvent
&event
)
752 // grab the cache for the current database... Get is ok here,
753 // since the cache is already loaded by the main db list
754 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
758 // grab the record list index
759 m_current_record_item
= event
.GetIndex();
760 // m_current_record_item = m_record_list->GetNextItem(
761 // m_current_record_item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
766 void BrowseMode::OnRecordListActivated(wxListEvent
&event
)
772 void BrowseMode::OnShowAll(wxCommandEvent
&event
)
774 m_show_all
= !m_show_all
;
778 void BrowseMode::OnAddRecord(wxCommandEvent
&event
)
780 // grab the cache for the current database... Get is ok here,
781 // since the cache is already loaded by the main db list
782 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
786 DBCache::iterator i
= p
->Add(m_parent
, p
->end());
787 if( i
!= p
->end() ) {
788 wxString
text((*i
)->GetDescription().c_str(), wxConvUTF8
);
790 // insert new record in same spot as DBCache has it
791 m_current_record_item
= p
->GetIndex(i
);
792 m_record_list
->InsertItem(m_current_record_item
, text
);
796 void BrowseMode::OnCopyRecord(wxCommandEvent
&event
)
798 // grab the cache for the current database... Get is ok here,
799 // since the cache is already loaded by the main db list
800 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
804 DBCache::iterator source
= p
->Get(m_current_record_item
);
805 DBCache::iterator i
= p
->Add(m_parent
, source
);
806 if( i
!= p
->end() ) {
807 wxString
text((*i
)->GetDescription().c_str(), wxConvUTF8
);
809 // insert new record in same spot as DBCache has it
810 m_current_record_item
= p
->GetIndex(i
);
811 m_record_list
->InsertItem(m_current_record_item
, text
);
815 void BrowseMode::OnEditRecord(wxCommandEvent
&event
)
817 // grab the cache for the current database... Get is ok here,
818 // since the cache is already loaded by the main db list
819 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
823 DBCache::iterator i
= p
->Get(m_current_record_item
);
824 if( p
->Edit(m_parent
, i
) ) {
825 wxString
text((*i
)->GetDescription().c_str(), wxConvUTF8
);
826 m_record_list
->SetItem(m_current_record_item
, 0, text
);
830 void BrowseMode::OnDeleteRecord(wxCommandEvent
&event
)
832 // grab the cache for the current database... Get is ok here,
833 // since the cache is already loaded by the main db list
834 DBMap::DBCachePtr p
= m_dbmap
->GetDBCache(m_current_dbname
);
838 DBCache::iterator i
= p
->Get(m_current_record_item
);
839 if( p
->Delete(m_parent
, i
) ) {
840 m_record_list
->DeleteItem(m_current_record_item
);