2 /// \file BackupWindow.cc
7 Copyright (C) 2007-2009, 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 "BackupWindow.h"
23 #include "DeviceSelectDlg.h"
24 #include "PasswordDlg.h"
25 #include "PromptDlg.h"
26 #include "ConfigDlg.h"
28 #include <gtkmm/aboutdialog.h>
34 BackupWindow::BackupWindow(BaseObjectType
*cobject
,
35 const Glib::RefPtr
<Gnome::Glade::Xml
> &xml
)
36 : Gtk::Window(cobject
)
39 , m_finishedRecords(0)
44 , m_pDeviceNameLabel(0)
49 Gtk::MenuItem
*pItem
= 0;
50 m_xml
->get_widget("menu_file_quit", pItem
);
51 pItem
->signal_activate().connect(
52 sigc::mem_fun(*this, &BackupWindow::on_file_quit
));
54 m_xml
->get_widget("menu_edit_config", pItem
);
55 pItem
->signal_activate().connect(
56 sigc::mem_fun(*this, &BackupWindow::on_edit_config
));
58 m_xml
->get_widget("menu_help_about", pItem
);
59 pItem
->signal_activate().connect(
60 sigc::mem_fun(*this, &BackupWindow::on_help_about
));
62 // get various widget pointers we will use later
63 m_xml
->get_widget("BackupButton", m_pBackupButton
);
64 m_xml
->get_widget("RestoreButton", m_pRestoreButton
);
65 m_xml
->get_widget("progressbar1", m_pProgressBar
);
66 m_xml
->get_widget("statusbar1", m_pStatusBar
);
67 m_xml
->get_widget("entry1", m_pPINEntry
);
68 m_xml
->get_widget("entry2", m_pDatabaseEntry
);
69 m_xml
->get_widget("DeviceNameLabel", m_pDeviceNameLabel
);
71 // setup widget signals
72 m_pBackupButton
->signal_clicked().connect(
73 sigc::mem_fun(*this, &BackupWindow::on_backup
));
74 m_pRestoreButton
->signal_clicked().connect(
75 sigc::mem_fun(*this, &BackupWindow::on_restore
));
77 // setup thread dispatcher signals
78 m_signal_progress
.connect(
79 sigc::mem_fun(*this, &BackupWindow::on_thread_progress
));
80 m_signal_error
.connect(
81 sigc::mem_fun(*this, &BackupWindow::on_thread_error
));
82 m_signal_done
.connect(
83 sigc::mem_fun(*this, &BackupWindow::on_thread_done
));
84 m_signal_erase_db
.connect(
85 sigc::mem_fun(*this, &BackupWindow::on_thread_erase_db
));
87 // setup startup device scan
88 Glib::signal_timeout().connect(
89 sigc::mem_fun(*this, &BackupWindow::on_startup
), 500);
91 m_pStatusBar
->push("Ready");
92 m_pProgressBar
->set_fraction(0.00);
94 // do this last so that any exceptions in the constructor
95 // won't cause a connected signal handler to a non-object
96 // (i.e. ~BackupWindow() won't get called if constructor throws)
97 m_signal_handler_connection
= Glib::add_exception_handler(
98 sigc::mem_fun(*this, &BackupWindow::signal_exception_handler
) );
101 BackupWindow::~BackupWindow()
103 // disconnect the signal, as we're going out of business
104 m_signal_handler_connection
.disconnect();
107 void BackupWindow::ScanAndConnect()
109 m_pStatusBar
->push("Scanning for devices...");
110 m_pStatusBar
->show_now();
120 if( probe
.GetCount() > 1 ) {
121 DeviceSelectDlg
dlg(probe
);
122 if( dlg
.run() == Gtk::RESPONSE_OK
) {
124 nSelection
= probe
.FindActive(pin
);
127 // no selection, exit
132 else if( probe
.GetCount() == 1 ) {
134 pin
= probe
.Get(0).m_pin
;
138 Gtk::MessageDialog
msg("No BlackBerry devices found.");
144 if( nSelection
== -1 ) {
145 Gtk::MessageDialog
msg("Internal error: unable to find pin.");
151 bool out_of_tries
= false, password_required
= false;
152 int remaining_tries
= 0;
154 if( !m_dev
.Connect(probe
.Get(nSelection
)) ) {
155 Gtk::MessageDialog
msg(m_dev
.get_last_error());
161 catch( Barry::BadPassword
&bp
) {
162 out_of_tries
= bp
.out_of_tries();
163 remaining_tries
= bp
.remaining_tries();
164 password_required
= true;
166 catch( Barry::BadSize
&bs
) {
167 std::cerr
<< "Barry::BadSize caught in ScanAndConnect: "
168 << bs
.what() << std::endl
;
170 // BadSize during connect at startup usually means
171 // the device didn't shutdown properly, so try
172 // a reset or two before we give up
173 Usb::Device
dev(probe
.Get(nSelection
).m_dev
);
179 Gtk::MessageDialog
msg(bs
.what());
186 if( password_required
) {
187 // try password repeatedly until out of tries or
188 // the user cancels... or success :-)
190 bool connected
= false;
191 while( !connected
&& !out_of_tries
) try {
192 PasswordDlg
dlg(remaining_tries
);
193 if( dlg
.run() == Gtk::RESPONSE_OK
) {
194 connected
= m_dev
.Password(dlg
.GetPassword());
196 Gtk::MessageDialog
msg(m_dev
.get_last_error());
208 catch( Barry::BadPassword
&bp
) {
209 out_of_tries
= bp
.out_of_tries();
210 remaining_tries
= bp
.remaining_tries();
212 Gtk::MessageDialog
msg(bp
.what());
225 std::ostringstream oss
;
226 oss
<< std::hex
<< pin
;
227 m_pPINEntry
->set_text(oss
.str());
229 // open configuration now that we know which device we're talking to
230 m_pConfig
.reset( new ConfigFile(oss
.str(), m_dev
.GetDBDB()) );
232 SetDeviceName(m_pConfig
->GetDeviceName());
237 void BackupWindow::CheckDeviceName()
239 if( !m_pConfig
->HasDeviceName() ) {
241 dlg
.SetPrompt("Unnamed device found. Please enter a name for it:");
242 if( dlg
.run() == Gtk::RESPONSE_OK
) {
243 m_pConfig
->SetDeviceName(dlg
.GetAnswer());
246 m_pConfig
->SetDeviceName(" ");
248 if( !m_pConfig
->Save() ) {
249 Gtk::MessageDialog
msg("Error saving config: " +
250 m_pConfig
->get_last_error());
256 void BackupWindow::SetDeviceName(const std::string
&name
)
258 // format the device name prompt
259 std::ostringstream dn
;
260 dn
<< "Device: <i>" << m_pConfig
->GetDeviceName() << "</i>";
261 m_pDeviceNameLabel
->set_label(dn
.str());
265 void BackupWindow::SetWorkingMode(const std::string
&taskname
)
268 m_thread_error
= false;
269 m_pBackupButton
->set_sensitive(false);
270 m_pRestoreButton
->set_sensitive(false);
271 m_pStatusBar
->push(taskname
+ " in progress...");
272 m_pProgressBar
->set_fraction(0.00);
275 void BackupWindow::ClearWorkingMode()
278 m_pBackupButton
->set_sensitive(true);
279 m_pRestoreButton
->set_sensitive(true);
281 if( m_finishedRecords
>= m_recordTotal
) {
282 // only reset the progress bar on success
283 m_pProgressBar
->set_fraction(0.00);
286 std::ostringstream oss
;
287 oss
<< m_finishedRecords
<< " total records processed.";
288 m_pDatabaseEntry
->set_text(oss
.str());
291 void BackupWindow::UpdateProgress()
293 double done
= (double)m_finishedRecords
/ m_recordTotal
;
294 // never say 100% unless really done
295 if( done
>= 1.0 && m_finishedRecords
< m_recordTotal
) {
298 m_pProgressBar
->set_fraction(done
);
300 m_pDatabaseEntry
->set_text(m_dev
.GetThreadDBName());
305 void BackupWindow::signal_exception_handler()
310 catch( Glib::Exception
&e
) {
311 // This usually just means a missing .glade file,
312 // so we try to carry on.
313 std::cerr
<< "Glib::Exception caught in main: " << std::endl
;
314 std::cerr
<< e
.what() << std::endl
;
315 Gtk::MessageDialog
msg(e
.what());
319 // anything else, terminate window and pass on to next handler
320 // (which should be in main.cc)
327 //////////////////////////////////////////////////////////////////////////////
330 void BackupWindow::on_backup()
334 Gtk::MessageDialog
msg("Thread already in progress.");
339 // make sure our target directory exists
340 if( !::CheckPath(m_pConfig
->GetPath()) ) {
341 Gtk::MessageDialog
msg("Could not create directory: " + m_pConfig
->GetPath());
347 if( m_pConfig
->GetBackupList().size() == 0 ) {
348 Gtk::MessageDialog
msg("No databases selected in configuration.");
353 // prepare for the progress bar
354 m_recordTotal
= m_dev
.GetDeviceRecordTotal(m_pConfig
->GetBackupList());
355 m_finishedRecords
= 0;
356 m_modeName
= "Backup";
359 if( m_recordTotal
== 0 ) {
360 Gtk::MessageDialog
msg("There are no records available in the selected databases.");
365 // prompt for a backup label, if so configured
366 std::string backupLabel
;
367 if( m_pConfig
->PromptBackupLabel() ) {
369 dlg
.SetPrompt("Please enter a label for this backup (blank is ok):");
370 if( dlg
.run() == Gtk::RESPONSE_OK
) {
371 backupLabel
= dlg
.GetAnswer();
380 m_working
= m_dev
.StartBackup(
381 DeviceInterface::AppComm(&m_signal_progress
,
385 m_pConfig
->GetBackupList(), m_pConfig
->GetPath(),
386 m_pConfig
->GetPIN(), backupLabel
);
388 Gtk::MessageDialog
msg("Error starting backup thread: " +
389 m_dev
.get_last_error());
394 SetWorkingMode("Backup");
397 bool BackupWindow::PromptForRestoreTarball(std::string
&restoreFilename
,
398 const std::string
&start_path
)
400 char buffer
[PATH_MAX
];
401 char *buf
= getcwd(buffer
, PATH_MAX
);
403 // start at the base path given... if it fails, just open
404 // the dialog where we are
405 chdir(start_path
.c_str());
407 Gtk::FileChooserDialog
dlg(*this, "Select backup to restore from");
408 dlg
.add_button(Gtk::Stock::OK
, Gtk::RESPONSE_OK
);
409 dlg
.add_button(Gtk::Stock::CANCEL
, Gtk::RESPONSE_CANCEL
);
410 int result
= dlg
.run();
415 if( result
!= Gtk::RESPONSE_OK
)
418 restoreFilename
= dlg
.get_filename();
422 void BackupWindow::on_restore()
426 Gtk::MessageDialog
msg("Thread already in progress.");
431 std::string restoreFilename
;
432 if( !PromptForRestoreTarball(restoreFilename
, m_pConfig
->GetPath()) )
433 return; // nothing to do
435 // prepare for the progress bar
436 m_finishedRecords
= 0;
437 m_modeName
= "Restore";
440 m_working
= m_dev
.StartRestore(
441 DeviceInterface::AppComm(&m_signal_progress
,
445 m_pConfig
->GetRestoreList(), restoreFilename
, &m_recordTotal
);
446 // m_working = m_dev.StartRestoreAndBackup(
447 // DeviceInterface::AppComm(&m_signal_progress,
450 // &m_signal_erase_db),
451 // m_pConfig->GetRestoreList(), restoreFilename,
452 // m_pConfig->GetPath(), m_pConfig->GetPIN(),
455 Gtk::MessageDialog
msg("Error starting restore thread: " +
456 m_dev
.get_last_error());
460 std::cerr
<< "m_recordTotal for restore: " << m_recordTotal
<< std::endl
;
463 SetWorkingMode("Restore");
466 void BackupWindow::on_file_quit()
472 void BackupWindow::on_edit_config()
474 ConfigDlg
dlg(m_dev
.GetDBDB(), *m_pConfig
);
475 if( dlg
.run() == Gtk::RESPONSE_OK
) {
476 m_pConfig
->SetBackupList(dlg
.GetBackupList());
477 m_pConfig
->SetRestoreList(dlg
.GetRestoreList());
478 m_pConfig
->SetDeviceName(dlg
.GetDeviceName());
479 m_pConfig
->SetPromptBackupLabel(dlg
.GetPromptBackupLabel());
480 if( !m_pConfig
->Save() ) {
481 Gtk::MessageDialog
msg("Error saving config: " +
482 m_pConfig
->get_last_error());
485 SetDeviceName(m_pConfig
->GetDeviceName());
489 void BackupWindow::on_help_about()
491 Gtk::AboutDialog dlg
;
492 dlg
.set_copyright("Copyright (C) 2007-2009, Net Direct Inc.");
494 " This program is free software; you can redistribute it and/or modify\n"
495 " it under the terms of the GNU General Public License as published by\n"
496 " the Free Software Foundation; either version 2 of the License, or\n"
497 " (at your option) any later version.\n"
499 " This program is distributed in the hope that it will be useful,\n"
500 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
501 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
503 " See the GNU General Public License in the COPYING file at the\n"
504 " root directory of this project for more details.\n");
506 std::vector
<std::string
> authors
;
507 authors
.push_back("Chris Frey <cdfrey@foursquare.net>");
509 dlg
.set_authors(authors
);
512 const char *BarryVersion
= Barry::Version(major
, minor
);
513 dlg
.set_name("Barry Backup");
514 dlg
.set_version("0.15");
515 dlg
.set_comments(std::string("Using library: ") + BarryVersion
);
516 dlg
.set_website("http://www.netdirect.ca/software/packages/barry/");
520 bool BackupWindow::on_startup()
529 void BackupWindow::on_thread_progress()
535 void BackupWindow::on_thread_error()
537 m_thread_error
= true;
539 Gtk::MessageDialog
msg(m_modeName
+ " error: " + m_dev
.get_last_thread_error());
543 void BackupWindow::on_thread_done()
545 if( !m_thread_error
) {
546 Gtk::MessageDialog
msg(m_modeName
+ " complete!");
555 void BackupWindow::on_thread_erase_db()
557 std::string name
= m_dev
.GetThreadDBName();
558 m_pDatabaseEntry
->set_text("Erasing database: " + name
);
566 Glib::ustring text = pEntry->get_text();
567 Gtk::MessageDialog dialog("This is the text entered: " + text);
568 // dialog.set_secondary_text(text);
574 // response(Gtk::RESPONSE_CLOSE);
575 // signal_delete_event().emit();
576 // Gtk::Main::quit();