Kitlist  1.1.0
kitlistgui.cpp
Go to the documentation of this file.
1 /*
2 
3  This file is part of Kitlist, a program to maintain a simple list
4  of items and assign items to one or more categories.
5 
6  Copyright (C) 2008-2021 Frank Dean
7 
8  Kitlist is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  Kitlist is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Kitlist. If not, see <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #include "kitlistgui.hpp"
24 #include "printing.hpp"
25 #include "yamlconfig.hpp"
26 #include <cassert>
27 // #include <gtk/gtk.h>
28 // #include <gtkmm.h>
29 #include <glibmm/i18n.h>
30 #include <glibmm/refptr.h>
31 #include <glibmm/ustring.h>
32 #include <gtkmm/aboutdialog.h>
33 #include <gtkmm/cellrenderertoggle.h>
34 #include <gtkmm/clipboard.h>
35 #include <gtkmm/filechooserdialog.h>
36 #include <gtkmm/menuitem.h>
37 #include <gtkmm/messagedialog.h>
38 #include <gtkmm/stock.h>
39 #include <gtkmm/targetentry.h>
40 #include <gtkmm/window.h>
41 #include <libglademm/xml.h>
42 #include <libxml++/libxml++.h>
43 #include <string>
44 #include <iostream>
45 #include <fstream>
46 #include <sstream>
47 #include <sys/stat.h>
48 #include <config.h>
49 
50 
51 using namespace std;
52 
53 namespace {
54 
56  const string GLADE_APP_FILE = "kitlist.glade";
57 
59  const guint SB_ITEM_COUNT = 1000;
61  const guint SB_SAVE = SB_ITEM_COUNT + 1;
63  const guint SB_MSG = SB_SAVE + 1;
64 
66  const guint SB_PRINT = SB_MSG + 1;
67 
69  const char item_target_custom[] = "kitlistclipboard";
71  const char item_target_text[] = "text/plain";
72 
74  const char XML_ELEMENT_ID[] = "id";
75 
77  const Glib::ustring DEFAULT_FILENAME_EXTENSION = ".kit";
78 
80  const Glib::ustring PDF_FILENAME_EXTENSION = ".pdf";
81 
83  const Glib::ustring DEFAULT_FILENAME = "kitlist" + DEFAULT_FILENAME_EXTENSION;
84 
86  const Glib::ustring GCONF_KEY = "/apps/kitlist";
87 
89  const Glib::ustring GCONF_KEY_CURRENT_FILENAME = GCONF_KEY + "/current_filename";
90 
92  const Glib::ustring GCONF_KEY_PAGE_TITLE = GCONF_KEY + "/page_title";
93 
94 #ifdef KITLIST_DEBUG
95 #ifdef GCONF
96  const Glib::ustring GCONF_KEY_DEBUG_LOG = GCONF_KEY + "/debug_log_filename";
98 #endif
99 #endif
100 
102  const Glib::ustring GCONF_KEY_RECENT_FILES = GCONF_KEY + "/recent_files";
103 
105  const Glib::ustring GCONF_KEY_MAX_RECENT_FILES = GCONF_KEY + "/max_recent_files";
106 
107 } // anonymous namespace
108 
109 
110 #ifdef KITLIST_DEBUG
111 void my_log_handler(const gchar *log_domain,
112  GLogLevelFlags log_level,
113  const gchar *message,
114  gpointer data) {
115  g_print("KITLIST: %s\n", message);
116  ofstream* fout = (ofstream*) data;
117  if (fout) {
118  *fout << message << endl;
119  }
120 }
121 #endif
122 
123 
124 typedef Gtk::TreeModel::Children type_children;
125 
135 const bool file_exists(const Glib::ustring& filename) {
136  struct stat fileinfo;
137  bool retval;
138  retval = !(stat(filename.c_str(), &fileinfo));
139  // g_debug("file_exists: %s", retval ? "true" : "false");
140  return retval;
141 }
142 
143 
145 const string load_resource_glade_file(const Glib::ustring& filename) {
146  vector<string> locs;
147  locs.push_back(filename);
148  locs.push_back("../" + filename);
149  locs.push_back("./src/" + filename);
150  locs.push_back(string(PACKAGE_DATA_DIR) + "/glade/" + filename);
151  for (std::vector<string>::iterator i = locs.begin(); i != locs.end(); ++i) {
152  if (file_exists(*i))
153  return *i;
154  }
155  return "";
156 }
157 
164 Glib::RefPtr<Gnome::Glade::Xml> get_glade_ref_ptr(const string& filename,
165  const Glib::ustring& root = Glib::ustring(),
166  const Glib::ustring& domain = Glib::ustring()) {
167  Glib::RefPtr<Gnome::Glade::Xml> refXml;
168  try {
169 #ifdef GLIBMM_EXCEPTIONS_ENABLED
170  refXml = Gnome::Glade::Xml::create(load_resource_glade_file(filename), root, domain);
171 #else
172  std::auto_ptr<Gnome::Glade::XmlError> ex;
173  refXml = Gnome::Glade::Xml::create(load_resource_glade_file(filename), root, domain, ex);
174  if (ex.get())
175  g_error(_("Error loading Glade file: %s"), ex->what().c_str());
176 #endif
177  } catch (const Gnome::Glade::XmlError& ex) {
178  g_error(_("Error loading Glade file: %s"), ex.what().c_str());
179  throw ex;
180  }
181  return refXml;
182 }
183 
184 
193 KitListGui::KitListGui(int argc, char **argv, Service& service)
194  : m_kit(argc, argv),
195  m_ignore_list_events(false),
196  m_window(0),
197  m_window_preferences(0),
198  m_entry_page_title(0),
199  m_window_add_item(0),
200  m_window_add_category(0),
201  m_entry_add_item(0),
202  m_entry_add_category(0),
203  m_file_save_menu_item(0),
204  m_file_save_tool_button(0),
205  m_paste_menu_item(0),
206  m_paste_tool_button(0),
207  m_checkbutton_add_item(0),
208  m_category_combo(0),
209  m_item_tree_view(0),
210  m_ref_item_tree_model(0),
211  m_service(service),
212  m_status_bar(0),
213  m_state(ADD_CATEGORY),
214  m_current_cat_id(-1) {
215  m_ref_page_setup = Gtk::PageSetup::create();
216  m_ref_printer_settings = Gtk::PrintSettings::create();
217  init();
218 }
219 
220 
222 #ifdef KITLIST_DEBUG
223  if (m_slog) {
224  m_slog->close();
225  delete m_slog;
226  }
227 #endif
228 }
229 
230 
233  m_kit.run(*m_window);
234  if (m_service.is_model_dirty()) {
235  g_warning("WARNING: Application is closing with unsaved changes");
236  }
237 }
238 
239 
241  gint retval = DEFAULT_MAX_RECENT_FILES;
242  return retval;
243 }
244 
245 
247 bool KitListGui::confirm_lose_changes(const Glib::ustring& message) {
248  // Prompt to abandon changes
249  Gtk::MessageDialog dialog(*m_window,
250  message,
251  false,
252  Gtk::MESSAGE_WARNING,
253  Gtk::BUTTONS_NONE);
254  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
255  dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_APPLY);
256  dialog.add_button(_("_Discard Changes"), Gtk::RESPONSE_CLOSE);
257  int result = dialog.run();
258  switch (result) {
259  case (Gtk::RESPONSE_CANCEL) :
260  return false;
261  case (Gtk::RESPONSE_APPLY) :
262 #ifdef XML_DAO
263  if (m_filename.length() > 0) {
265  m_service.set_model_dirty(false);
266  return true;
267  }
268  return false;
269 #else
270  m_service.save();
271  m_service.set_model_dirty(false);
272  return true;
273 #endif
274  case (Gtk::RESPONSE_CLOSE) :
275  return true;
276  default :
277  return false;
278  }
279 }
280 
281 
286 #ifdef GCONF
287  // Get the current list from GConf
288  std::deque<Glib::ustring> mru =
289  m_ref_gconf_client->get_string_list(GCONF_KEY_RECENT_FILES);
290 #else
291  std::deque<Glib::ustring> mru = m_yaml_config.get_recent_filenames();
292 #endif // GCONF
293 
295  if (m_recent_files_menu_item->has_submenu()) {
296  m_recent_files_menu_item->remove_submenu();
297  }
298  Gtk::Menu* recent_menu = Gtk::manage(new Gtk::Menu);
299  // g_debug("Creating new recent files submenu");
300  m_recent_files_menu_item->set_submenu(*recent_menu);
301  for (std::deque<Glib::ustring>::iterator i = mru.begin();
302  i != mru.end();
303  ++i) {
304  Gtk::MenuItem* m = Gtk::manage(new Gtk::MenuItem(*i));
305  m->signal_activate().connect(
306  sigc::bind<Glib::ustring>(
307  sigc::mem_fun(*this, &KitListGui::on_menu_recent_file), *i)
308  );
309  recent_menu->add(*m);
310  recent_menu->show_all_children();
311  }
312  } else {
313  g_warning("Couldn't find recent files menu item");
314  }
315 }
316 
317 
324 void KitListGui::update_recent_files(const Glib::ustring& filename) {
325 #ifdef GCONF
326  // g_debug("Adding %s to recent file list", filename.c_str());
327  // Get the current list from GConf
328  std::deque<Glib::ustring> mru =
329  m_ref_gconf_client->get_string_list(GCONF_KEY_RECENT_FILES);
330  // Remove filename from list
331  for (std::deque<Glib::ustring>::iterator i = mru.begin(); i != mru.end(); ++i) {
332  if (*i == filename) {
333  mru.erase(i);
334  break;
335  }
336  }
337  // Add add to front
338  mru.push_front(filename);
339  while (mru.size() > get_max_recent_files()) {
340  mru.pop_back();
341  }
342 
343  // Save the updated list
344  m_ref_gconf_client->set_string_list(GCONF_KEY_RECENT_FILES, mru);
345 
346 
348 #else
349  m_yaml_config.add_recent_filename(filename.c_str());
351 #endif // GCONF
352 }
353 
354 
356 bool KitListGui::on_delete_event(GdkEventAny* event) {
357  if (m_service.is_model_dirty() &&
358  !confirm_lose_changes(_("Your changes will be lost if you quit now"))) {
359  return true;
360  }
361  // user has chosen to abandon changes
362  // Clear the dirty state so that it can be tested in run().
363  // See the notes under KitListGui::run()
364  m_service.set_model_dirty(false);
365  return false;
366 }
367 
368 
371  if (m_service.is_model_dirty() &&
372  !confirm_lose_changes(_("Your changes will be lost if you quit now"))) {
373  return;
374  }
375  // user has chosen to abandon changes
376  // Clear the dirty state so that it can be tested in run().
377  // See the notes under KitListGui::run()
378  m_service.set_model_dirty(false);
379  m_window->hide();
380 }
381 
382 
388  if (m_status_bar)
389  m_status_bar->pop(SB_SAVE);
390  if (m_service.is_model_dirty() &&
391  !confirm_lose_changes(_("Your changes will be lost if you continue"))) {
392  return;
393  }
394 #ifndef TRANSITION_DAO
395  if (m_service.require_filename()) {
396 #endif
397  m_filename.clear();
398 #ifdef GCONF
399  if (m_ref_gconf_client) {
400 #ifdef GLIBMM_EXCEPTIONS_ENABLED
401  m_ref_gconf_client->unset(GCONF_KEY_CURRENT_FILENAME);
402 #else
403  std::auto_ptr<Glib::Error> error;
404  m_ref_gconf_client->unset(GCONF_KEY_CURRENT_FILENAME, error);
405  if (error.get())
406  g_warning("GConf error: %s", error->what().c_str());
407 #endif //GLIBMM_EXCEPTIONS_ENABLED
408  }
409 #else
411 #endif // GCONF
413  // Don't select a category, as it may no longer be relevant,
414  // after all, we've just loaded a new model.
417 #ifndef TRANSITION_DAO
418  } else {
419  if (m_status_bar)
420  m_status_bar->push(_("New databases must be created manually"), SB_SAVE);
421  }
422 #endif
423 }
424 
425 
433  if (m_status_bar)
434  m_status_bar->pop(SB_SAVE);
435  if (m_service.is_model_dirty() &&
436  !confirm_lose_changes(_("Your changes will be lost if you continue"))) {
437  return;
438  }
439  // Prompt select file to open
440  Gtk::FileChooserDialog dialog(_("Open File"), Gtk::FILE_CHOOSER_ACTION_OPEN);
441  dialog.set_transient_for(*m_window);
442 
443  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
444  dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
445 
446  Gtk::FileFilter filter_xml;
447  filter_xml.set_name(_("Kit files"));
448 #ifdef WIN32
449  filter_xml.add_pattern("*" + DEFAULT_FILENAME_EXTENSION);
450 #else
451  filter_xml.add_pattern("*" + DEFAULT_FILENAME_EXTENSION);
452  // filter_xml.add_mime_type("application/xml");
453 #endif
454  dialog.add_filter(filter_xml);
455 
456  Gtk::FileFilter filter_any;
457  filter_any.set_name(_("Any files"));
458  filter_any.add_pattern("*");
459  dialog.add_filter(filter_any);
460 
461  int result = dialog.run();
462  dialog.hide();
463  Glib::ustring filename;
464  switch(result) {
465  case(Gtk::RESPONSE_OK):
466  filename = dialog.get_filename();
467  break;
468  case(Gtk::RESPONSE_CANCEL):
469  return;
470  default:
471  return;
472  }
473  open_file(filename);
474 }
475 
476 
481 void KitListGui::open_file(const Glib::ustring& filename) {
482  m_service.open_as_xml(filename);
483  m_filename = filename;
485 
486 #ifdef GCONF
487  if (m_ref_gconf_client) {
488 #ifdef GLIBMM_EXCEPTIONS_ENABLED
489  m_ref_gconf_client->set(GCONF_KEY_CURRENT_FILENAME, m_filename);
490 #else
491  std::auto_ptr<Glib::Error> error;
492  m_ref_gconf_client->set(GCONF_KEY_CURRENT_FILENAME, m_filename, error);
493  if (error.get())
494  g_warning("GConf error: %s", error->what().c_str());
495 #endif //GLIBMM_EXCEPTIONS_ENABLED
496  }
497 #else // GCONF
499 #endif
500 
501  // Don't select a category, as it may no longer be relevant,
502  // after all, we've just loaded a new model.
505 }
506 
507 
514 void KitListGui::safe_open_file(const Glib::ustring& filename) {
515  if (m_status_bar)
516  m_status_bar->pop(SB_SAVE);
517  if (m_service.is_model_dirty() &&
518  !confirm_lose_changes(_("Your changes will be lost if you continue"))) {
519  return;
520  }
521  open_file(filename);
522 }
523 
524 
529  if (m_status_bar)
530  m_status_bar->pop(SB_SAVE);
531  if (m_service.is_model_dirty()) {
532  // Some persistence models may require a filename to be
533  // chosen, others (e.g. database) may be defined through
534  // another mechanism. If a filename has not been set, then
535  // fire up save-as instead.
536  if (m_service.require_filename() && m_filename.size() == 0) {
537  on_menu_save_as();
538  } else {
539  Glib::ustring msg = _("Saving changes...");
540  if (m_status_bar)
541  m_status_bar->push(msg, SB_SAVE);
542 #ifndef XML_DAO
543  m_service.save();
544 #else
547 #ifdef GCONF
548  if (m_ref_gconf_client) {
549 #ifdef GLIBMM_EXCEPTIONS_ENABLED
550  m_ref_gconf_client->set(GCONF_KEY_CURRENT_FILENAME,
551  m_filename);
552 #else
553  std::auto_ptr<Glib::Error> error;
554  m_ref_gconf_client->set(GCONF_KEY_CURRENT_FILENAME, m_filename, error);
555  if (error.get())
556  g_warning("GConf error: %s", error->what().c_str());
557 #endif //GLIBMM_EXCEPTIONS_ENABLED
558  }
559 #else // GCONF
561 #endif // GCONF
562 #endif // !XML_DAO
563  if (m_status_bar)
564  m_status_bar->pop(SB_SAVE);
565  msg = _("Saved");
566  if (m_status_bar)
567  m_status_bar->push(msg, SB_SAVE);
568  }
569  } else {
570  if (m_status_bar)
571  m_status_bar->push(Glib::ustring(_("Nothing to save")), SB_SAVE);
572  }
573 }
574 
575 
580  if (m_status_bar) {
581  m_status_bar->pop(SB_SAVE);
582  m_status_bar->push(_("Choosing target filename"), SB_SAVE);
583  }
585  if (m_status_bar) {
586  m_status_bar->pop(SB_SAVE);
587  m_status_bar->push(_("Saving..."), SB_SAVE);
588  }
589 
592 
593  if (m_status_bar) {
594  m_status_bar->pop(SB_SAVE);
595  m_status_bar->push(_("Saved"), SB_SAVE);
596  }
597 #ifdef GCONF
598  if (m_ref_gconf_client) {
599 #ifdef GLIBMM_EXCEPTIONS_ENABLED
600  m_ref_gconf_client->set(GCONF_KEY_CURRENT_FILENAME, m_filename);
601 #else
602  std::auto_ptr<Glib::Error> error;
603  m_ref_gconf_client->set(GCONF_KEY_CURRENT_FILENAME, m_filename, error);
604  if (error.get())
605  g_warning("GConf error: %s", error->what().c_str());
606 #endif //GLIBMM_EXCEPTIONS_ENABLED
607  }
608 #else // GCONF
610 #endif // GCONF
611 
612  // Disable save if we're using a database otherwise we'll be
613  // trying to save to the database, not the file with the model
614  // being potentially inconsistent with the database.
615 
616 // Don't think we need this as we've now disabled NEW and OPEN
617 // #ifndef XML_DAO
618 // m_file_save_menu_item->set_sensitive(false);
619 // m_file_save_tool_button->set_sensitive(false);
620 // #endif
621  } else {
622  if (m_status_bar) {
623  m_status_bar->pop(SB_SAVE);
624  m_status_bar->push(_("Save cancelled"), SB_SAVE);
625  }
626  }
627 }
628 
629 
633 void KitListGui::on_printoperation_status_changed(const Glib::RefPtr<Gtk::PrintOperation>& op) {
634  if (m_status_bar)
635  m_status_bar->pop(SB_PRINT);
636  Glib::ustring status_msg;
637  if (op->is_finished())
638  status_msg = _("Print job completed");
639  else
640  status_msg = op->get_status_string();
641 
642  m_status_bar->push(status_msg, SB_PRINT);
643 }
644 
648 void KitListGui::on_printoperation_done(Gtk::PrintOperationResult result, const Glib::RefPtr<Gtk::PrintOperation>& op) {
649  if (result == Gtk::PRINT_OPERATION_RESULT_ERROR) {
650  Gtk::MessageDialog err_dialog(*this->m_window, _("Error printing list"), false,
651  Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
652  err_dialog.run();
653  } else if (result == Gtk::PRINT_OPERATION_RESULT_APPLY)
654  m_ref_printer_settings = op->get_print_settings();;
655  if (! op->is_finished())
656  op->signal_status_changed().connect(sigc::bind(sigc::mem_fun(*this, &KitListGui::on_printoperation_status_changed), op));
657 }
658 
659 
664  Glib::RefPtr<KitPrintOperation> op = KitPrintOperation::create();
666  op->set_items(items);
667  op->set_track_print_status();
668  op->set_default_page_setup(m_ref_page_setup);
669  op->set_print_settings(m_ref_printer_settings);
670  op->set_page_title(m_page_title);
671  op->signal_done().connect(sigc::bind(sigc::mem_fun(*this, &KitListGui::on_printoperation_done), op));
672 
673 #ifdef GLIBMM_EXCEPTIONS_ENABLED
674  try {
675  op->run();
676  } catch (const Gtk::PrintError& ex) {
677  g_error("An error occured while trying to run a print operation: %s", ex.what().c_str());
678  }
679 #else
680  std::auto_ptr<Glib::Error> error;
681  op->run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, error);
682  if (error.get())
683  g_warning("Error running print job: %s",
684  error->what().c_str());
685 #endif //GLIBMM_EXCEPTIONS_ENABLED
686 }
687 
688 
693  if (m_status_bar) {
694  m_status_bar->pop(SB_SAVE);
695  m_status_bar->push(_("Choosing export filename"), SB_SAVE);
696  }
697  Glib::ustring pdf_filename;
698  if (choose_pdf_filename(pdf_filename)) {
699  if (m_status_bar) {
700  m_status_bar->pop(SB_SAVE);
701  m_status_bar->push(_("Exporting..."), SB_SAVE);
702  }
703  Glib::RefPtr<KitPrintOperation> op = KitPrintOperation::create();
705  op->set_items(items);
706  op->set_track_print_status();
707  op->set_default_page_setup(m_ref_page_setup);
708  op->set_print_settings(m_ref_printer_settings);
709  op->set_page_title(m_page_title);
710  // op->signal_done().connect(sigc::bind(sigc::mem_fun(*this, &KitListGui::on_printoperation_done), op));
711  op->set_export_filename(pdf_filename);
712 
713  #ifdef GLIBMM_EXCEPTIONS_ENABLED
714  try {
715  op->run(Gtk::PRINT_OPERATION_ACTION_EXPORT);
716  } catch (const Gtk::PrintError& ex) {
717  g_error("An error occured while trying to run a print operation: %s", ex.what().c_str());
718  }
719  #else
720  std::auto_ptr<Glib::Error> error;
721  op->run(Gtk::PRINT_OPERATION_ACTION_EXPORT, error);
722  if (error.get())
723  g_warning("Error running print job: %s",
724  error->what().c_str());
725  #endif //GLIBMM_EXCEPTIONS_ENABLED
726 
727  if (m_status_bar) {
728  m_status_bar->pop(SB_SAVE);
729  m_status_bar->push(_("PDF exported"), SB_SAVE);
730  }
731  } else {
732  if (m_status_bar) {
733  m_status_bar->pop(SB_SAVE);
734  m_status_bar->push(_("Export cancelled"), SB_SAVE);
735  }
736  }
737 }
738 
742 void KitListGui::on_menu_recent_file(const Glib::ustring& filename) {
743  // g_debug("Most recent files menu clicked: %s", filename.c_str());
744  if (m_service.is_model_dirty() &&
745  !confirm_lose_changes(_("Your changes will be lost if you continue"))) {
746  return;
747  }
748  m_service.open_as_xml(filename);
749  m_filename = filename;
751 
752 #ifdef GCONF
753  if (m_ref_gconf_client) {
754 #ifdef GLIBMM_EXCEPTIONS_ENABLED
755  m_ref_gconf_client->set(GCONF_KEY_CURRENT_FILENAME, m_filename);
756 #else
757  std::auto_ptr<Glib::Error> error;
758  m_ref_gconf_client->set(GCONF_KEY_CURRENT_FILENAME, m_filename, error);
759  if (error.get())
760  g_warning("GConf error: %s", error->what().c_str());
761 #endif //GLIBMM_EXCEPTIONS_ENABLED
762  }
763 #else // GCONF
765 #endif // GCONF
766 
767  // Don't select a category, as it may no longer be relevant,
768  // after all, we've just loaded a new model.
771 }
772 
773 
779  Glib::RefPtr<Gtk::TreeSelection> ref_tree_selection =
780  m_item_tree_view->get_selection();
781  if (ref_tree_selection) {
782  if (ref_tree_selection->get_mode() == Gtk::SELECTION_MULTIPLE) {
783  Gtk::TreeSelection::ListHandle_Path rows = ref_tree_selection->get_selected_rows();
784  for (Glib::Container_Helpers::ListHandleIterator<Gtk::TreePath_Traits> path = rows.begin(); path != rows.end(); ++path) {
785  Gtk::TreeModel::iterator iter = m_ref_item_tree_model->get_iter(*path);
786  Gtk::TreeModel::Row row = *iter;
787  int id = row[m_item_cols.m_col_num];
788  ModelItem* item = m_service.find_item(id);
789  if (item) {
790  retval->push_back(item);
791  } else {
792  g_warning("Failed to find item to delete in model");
793  }
794  } // for
795  } else {
796  Gtk::TreeModel::iterator iter = ref_tree_selection->get_selected();
797  if (iter) {
798  Gtk::TreeModel::Row row = *iter;
799  int id = row[m_item_cols.m_col_num];
800  ModelItem* item = m_service.find_item(id);
801  if (item) {
802  retval->push_back(item);
803  } else {
804  g_warning("Failed to find item to delete in model");
805  }
806  } else {
807  g_warning("Couldn't find the selected item or items");
808  }
809  } // else {Single Selection}
810  } else {
811  g_warning("Couldn't identify selection");
812  }
813  return retval;
814 }
815 
816 
824  Glib::RefPtr<Gtk::TreeSelection> ref_tree_selection =
825  m_item_tree_view->get_selection();
826  if (ref_tree_selection) {
827  if (ref_tree_selection->get_mode() == Gtk::SELECTION_MULTIPLE) {
828  ref_tree_selection->selected_foreach_iter( sigc::mem_fun(*this, &KitListGui::selected_row_callback));
830  } else {
831  Gtk::TreeModel::iterator iter = ref_tree_selection->get_selected();
832  if (iter) {
833  Gtk::TreeModel::Row row = *iter;
834  int id = row[m_item_cols.m_col_num];
835  m_ref_item_tree_model->erase(iter);
836  if (!m_service.delete_item(id))
837  g_warning("Failed to find the item to delete in the model");
838  } else {
839  g_warning("Couldn't find the selected item or items");
840  }
841  } // else {Single Selection}
842  } else {
843  g_warning("Couldn't identify selection");
844  }
845 }
846 
847 
856  Gtk::MessageDialog dialog(*m_window,
857  _("Delete the selected items?"),
858  false,
859  Gtk::MESSAGE_QUESTION,
860  Gtk::BUTTONS_YES_NO);
861  int result = dialog.run();
862  switch (result) {
863  case (Gtk::RESPONSE_YES) :
865  break;
866  case (Gtk::RESPONSE_NO) :
867  break;
868  default:
869  g_warning("Unexpected button");
870  break;
871  }
872 }
873 
874 
879  xmlpp::Document document;
880  xmlpp::Element* nodeRoot = document.create_root_node("kitlist");
881  assert(nodeRoot);
882  nodeRoot->add_child_text("\n");
884  for (ModelItemIter i = items->begin(); i != items->end(); ++i) {
885  xmlpp::Element* nodeChild = nodeRoot->add_child("item");
886  ostringstream os;
887  os << (*i)->get_id();
888  nodeChild->set_attribute(XML_ELEMENT_ID, os.str());
889  // Enable the following lines to create a more readable XML document
890  nodeChild->set_child_text((*i)->get_description());
891  nodeRoot->add_child_text("\n");
892  }
893  m_clipboard_items = document.write_to_string();
894 
895  Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get(/*gdk_atom_intern("CLIPBOARD", false)*/);
896  std::list<Gtk::TargetEntry> listTargets;
897  listTargets.push_back( Gtk::TargetEntry(item_target_custom) );
898  listTargets.push_back( Gtk::TargetEntry(item_target_text) );
899  refClipboard->set( listTargets,
900  sigc::mem_fun(*this, &KitListGui::on_clipboard_get),
901  sigc::mem_fun(*this, &KitListGui::on_clipboard_clear) );
903  return items;
904 }
905 
906 
912  long cat_id = get_selected_category();
913  if (cat_id != -1) {
915  if (items) {
916  ModelCategory* category = m_service.find_category(cat_id);
917  if (category) {
919  category->remove_items(items);
920  category->set_dirty(true);
921  }
923  }
924  delete items;
925  } else {
926  if (m_status_bar) {
927  m_status_bar->pop(SB_MSG);
928  m_status_bar->push(_("Items can only be cut when a category is selected"), SB_MSG);
929  }
930  }
931 }
932 
933 
939  delete items;
940 }
941 
942 
947  // Tell the clipboard to call our method when it is ready
948  Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get(/*gdk_atom_intern("CLIPBOARD", false)*/);
949  refClipboard->request_contents(item_target_text, sigc::mem_fun(
950  *this,
954 }
955 
956 
961  //m_item_tree_view->select_all();
962  Glib::RefPtr<Gtk::TreeSelection> selection =
963  m_item_tree_view->get_selection();
964  if (selection)
965  selection->select_all();
966  m_item_tree_view->grab_focus();
967 }
968 
969 
973  m_current_cat_id = -1;
974  if (m_window_add_category) {
975  m_window_add_category->set_title(_("Add Category"));
976  if (m_entry_add_category) {
977  m_entry_add_category->set_text("");
978  }
979  m_entry_add_category->grab_focus();
980  m_window_add_category->show();
981  } else {
982  g_warning("\"window_add_category\" resource is missing");
983  }
984 }
985 
986 
998  m_window_add_category->hide();
999  if (m_entry_add_category) {
1000  Category* category = NULL;
1001  if (m_state == ADD_CATEGORY) {
1002  category = m_service.create_category();
1003  } else {
1005  }
1006  if (category != NULL) {
1007  category->set_name(m_entry_add_category->get_text());
1009  ((ModelCategory*) category)->set_dirty(true);
1010  refresh_category_list(category->get_id());
1012  }
1013  }
1014 }
1015 
1016 
1017 
1023  m_window_add_category->hide();
1024 }
1025 
1026 
1034  long cat_id = get_selected_category();
1035  if (cat_id == -1) {
1036  if (m_status_bar) {
1037  m_status_bar->pop(SB_MSG);
1038  m_status_bar->push(_("No category selected"), SB_MSG);
1039  }
1040  } else {
1041  Gtk::MessageDialog dialog(*m_window,
1042  _("Delete the current category?"),
1043  false,
1044  Gtk::MESSAGE_QUESTION,
1045  Gtk::BUTTONS_YES_NO);
1046  int result = dialog.run();
1047  switch (result) {
1048  case (Gtk::RESPONSE_YES) :
1049  m_service.delete_category(cat_id);
1052  break;
1053  case (Gtk::RESPONSE_NO) :
1054  break;
1055  default:
1056  g_warning("Unexpected button");
1057  break;
1058  }
1059  }
1060 }
1061 
1062 
1069  if (m_window_add_category) {
1070  m_window_add_category->set_title(_("Rename Category"));
1071  if (m_current_cat_id != -1) {
1073  if (category != NULL && m_entry_add_category) {
1074  m_entry_add_category->set_text(category->get_name());
1075  }
1076  m_entry_add_category->grab_focus();
1077  m_window_add_category->show();
1078  } else {
1079  if (m_status_bar) {
1080  m_status_bar->pop(SB_MSG);
1081  m_status_bar->push(_("No category selected"), SB_MSG);
1082  }
1083  }
1084  } else {
1085  g_warning("\"window_add_category\" resource is missing");
1086  }
1087 }
1088 
1089 
1094  Gtk::AboutDialog dialog;
1095  dialog.set_name(PACKAGE_NAME);
1096  dialog.set_copyright("(c) 2008-2021 Frank Dean");
1097  dialog.set_version(PACKAGE_VERSION);
1098  std::vector<Glib::ustring> authors;
1099  authors.push_back("frank.dean@fdsd.co.uk");
1100  dialog.set_authors(authors);
1101  dialog.run();
1102 }
1103 
1104 
1108 void KitListGui::set_selected(bool checked) {
1110  m_service.select_items(items, checked);
1112  delete items;
1113 }
1114 
1115 
1123  delete items;
1124 }
1125 
1126 
1130 void KitListGui::on_clipboard_get(Gtk::SelectionData& selection_data, guint) {
1131  const std::string target = selection_data.get_target();
1132 
1133  if (target == item_target_custom) {
1134  selection_data.set_text(m_clipboard_items);
1135  } else if (target == item_target_text) {
1136  selection_data.set_text(m_clipboard_items);
1137  } else {
1138  g_warning("KitList::on_clipboard_get(): Unexpected clipboard target format");
1139  }
1140 }
1141 
1142 
1162 }
1163 
1164 
1173  long cat_id = get_selected_category();
1174  if (cat_id != -1) {
1175  m_service.copy_items(items, cat_id);
1177  }
1178 }
1179 
1180 
1184 void KitListGui::paste_from_xml(const Glib::ustring& document) {
1185  try {
1186  if (document.length() > 0) {
1187  xmlpp::DomParser parser;
1188  parser.set_substitute_entities();
1189  parser.parse_memory(document);
1190  const xmlpp::Node* nodeRoot = parser.get_document()->get_root_node();
1191  ModelItemContainer items;
1192  xmlpp::Node::NodeList nodes = nodeRoot->get_children();
1193  for (xmlpp::Node::NodeList::iterator iter = nodes.begin(); iter != nodes.end(); ++iter) {
1194  const xmlpp::Node* node = (*iter);
1195  // const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
1196  const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node);
1197  if (nodeElement && node->get_name() == "item") {
1198  xmlpp::Attribute* attribute = nodeElement->get_attribute(XML_ELEMENT_ID);
1199  if (attribute) {
1200  Glib::ustring s = attribute->get_value();
1201  long id = atol(s.c_str());
1202  ModelItem* item = m_service.find_item(id);
1203  if (item) {
1204  items.push_back(item);
1205  }
1206  }
1207  }
1208  }
1209  add_items(items);
1210  }
1211  } catch (std::exception ex) {
1212  g_warning("Error pasting clipboard - perhaps it was empty");
1213  }
1214 }
1215 
1216 
1220 void KitListGui::on_clipboard_received(const Gtk::SelectionData& selection_data) {
1221  const std::string target = selection_data.get_target();
1222  Glib::ustring s;
1223  if (target == item_target_custom || target == item_target_text) {
1224  m_clipboard_items = selection_data.get_data_as_string();
1225  } else {
1226  g_warning("KitList::on_clipboard_get(): Unexpected clipboard target format");
1227  }
1228 }
1229 
1230 
1235  // use the user's locale for this stream
1236  ostringstream os;
1237  os.imbue(std::locale(""));
1238  os << n << " " << (n == 1 ? _("item") : _("items"));
1239  if (m_status_bar) {
1241 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1242  m_status_bar->push(Glib::locale_to_utf8(os.str()), SB_ITEM_COUNT);
1243 #else
1244  std::auto_ptr<Glib::Error> ex;
1245  m_status_bar->push(Glib::locale_to_utf8(os.str(), ex), SB_ITEM_COUNT);
1246 
1247  if (ex.get())
1248  g_warning("Error updating the status bar: %s", ex->what().c_str());
1249 #endif // GLIBMM_EXCEPTIONS_ENABLED
1250  }
1251 }
1252 
1253 
1259 void KitListGui::on_cell_edit(const Glib::ustring s) {
1261  return;
1262  m_service.set_model_dirty(true);
1263 }
1264 
1265 
1276 bool KitListGui::choose_filename(Glib::ustring& filename) {
1277  bool retval = false;
1278  bool loop = true;
1279  while (loop) {
1280  Gtk::FileChooserDialog dialog(_("Save File"), Gtk::FILE_CHOOSER_ACTION_SAVE);
1281  dialog.set_transient_for(*m_window);
1282 
1283  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1284  dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
1285 
1286  Gtk::FileFilter filter_xml;
1287  filter_xml.set_name(_("XML files"));
1288 
1289 #ifdef WIN32
1290  filter_xml.add_pattern("*" + DEFAULT_FILENAME_EXTENSION);
1291 #else
1292  filter_xml.add_pattern("*" + DEFAULT_FILENAME_EXTENSION);
1293  // filter_xml.add_mime_type("application/xml");
1294 #endif
1295 
1296  dialog.add_filter(filter_xml);
1297 
1298  Gtk::FileFilter filter_any;
1299  filter_any.set_name(_("Any files"));
1300  filter_any.add_pattern("*");
1301  dialog.add_filter(filter_any);
1302 
1303  int result = dialog.run();
1304  dialog.hide();
1305 
1306  switch(result) {
1307  case(Gtk::RESPONSE_OK):
1308  filename = dialog.get_filename();
1309  retval = true;
1310  break;
1311  case(Gtk::RESPONSE_CANCEL):
1312  break;
1313  default:
1314  break;
1315  }
1316  if (retval) {
1317  // Add file default extension if no extension
1318  Glib::ustring::size_type i = filename.find(".");
1319  if (i < 0 || i > filename.length()) {
1320  filename += DEFAULT_FILENAME_EXTENSION;
1321 
1322  }
1323  // Prompt for overwrite if the file exists
1324  if (file_exists(filename)) {
1325  Gtk::MessageDialog dialog(*m_window,
1326  _("Overwrite existing file?"),
1327  false,
1328  Gtk::MESSAGE_WARNING,
1329  Gtk::BUTTONS_NONE);
1330  dialog.add_button(Gtk::Stock::NO, Gtk::RESPONSE_NO);
1331  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1332  dialog.add_button(Gtk::Stock::YES, Gtk::RESPONSE_YES);
1333  dialog.set_default_response(Gtk::RESPONSE_NO);
1334  int result = dialog.run();
1335  switch (result) {
1336  case (Gtk::RESPONSE_CANCEL) :
1337  retval = false;
1338  loop = false;
1339  break;
1340  case (Gtk::RESPONSE_NO) :
1341  retval = false;
1342  loop = true;
1343  break;
1344  case (Gtk::RESPONSE_YES) :
1345  loop = false;
1346  break;
1347  default :
1348  retval = false;
1349  loop = false;
1350  break;
1351  }
1352 
1353  } else {
1354  loop = false;
1355  }
1356  } else {
1357  loop = false;
1358  }
1359  } // while loop
1360  return retval;
1361 }
1362 
1363 
1374 bool KitListGui::choose_pdf_filename(Glib::ustring& filename) {
1375  bool retval = false;
1376  bool loop = true;
1377  while (loop) {
1378  Gtk::FileChooserDialog dialog(_("Export to PDF"), Gtk::FILE_CHOOSER_ACTION_SAVE);
1379  dialog.set_transient_for(*m_window);
1380 
1381  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1382  dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
1383 
1384  Gtk::FileFilter filter_pdf;
1385  filter_pdf.set_name(_("PDF files"));
1386  filter_pdf.add_pattern("*" + PDF_FILENAME_EXTENSION);
1387  dialog.add_filter(filter_pdf);
1388 
1389  Gtk::FileFilter filter_any;
1390  filter_any.set_name(_("Any files"));
1391  filter_any.add_pattern("*");
1392  dialog.add_filter(filter_any);
1393 
1394  int result = dialog.run();
1395  dialog.hide();
1396 
1397  switch(result) {
1398  case(Gtk::RESPONSE_OK):
1399  filename = dialog.get_filename();
1400  retval = true;
1401  break;
1402  case(Gtk::RESPONSE_CANCEL):
1403  break;
1404  default:
1405  break;
1406  }
1407  if (retval) {
1408  // Add file default extension if no extension
1409  Glib::ustring::size_type i = filename.find(".");
1410  if (i < 0 || i > filename.length()) {
1411  filename += PDF_FILENAME_EXTENSION;
1412 
1413  }
1414  // Prompt for overwrite if the file exists
1415  if (file_exists(filename)) {
1416  Gtk::MessageDialog dialog(*m_window,
1417  _("Overwrite existing file?"),
1418  false,
1419  Gtk::MESSAGE_WARNING,
1420  Gtk::BUTTONS_NONE);
1421  dialog.add_button(Gtk::Stock::NO, Gtk::RESPONSE_NO);
1422  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1423  dialog.add_button(Gtk::Stock::YES, Gtk::RESPONSE_YES);
1424  dialog.set_default_response(Gtk::RESPONSE_NO);
1425  int result = dialog.run();
1426  switch (result) {
1427  case (Gtk::RESPONSE_CANCEL) :
1428  retval = false;
1429  loop = false;
1430  break;
1431  case (Gtk::RESPONSE_NO) :
1432  retval = false;
1433  loop = true;
1434  break;
1435  case (Gtk::RESPONSE_YES) :
1436  loop = false;
1437  break;
1438  default :
1439  retval = false;
1440  loop = false;
1441  break;
1442  }
1443 
1444  } else {
1445  loop = false;
1446  }
1447  } else {
1448  loop = false;
1449  }
1450  } // while loop
1451  return retval;
1452 }
1453 
1454 
1459  Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get();
1460  refClipboard->request_targets( sigc::mem_fun(*this, &KitListGui::paste_status_received) );
1461 }
1462 
1463 
1470 void KitListGui::paste_status_received(const Glib::StringArrayHandle& targets_array) {
1471  std::list<std::string> targets = targets_array;
1472  bool can_paste = false;
1473  for (std::list<std::string>::iterator i = targets.begin(); i != targets.end(); ++i) {
1474  if ( *i == item_target_custom || *i == item_target_text) {
1475  can_paste = true;
1476  break;
1477  }
1478  }
1479  // Enable/disable paste button appropriately
1480  if (m_paste_menu_item)
1481  m_paste_menu_item->set_sensitive(can_paste);
1482 
1483  if (m_paste_tool_button)
1484  m_paste_tool_button->set_sensitive(can_paste);
1485 }
1486 
1487 
1488 
1497 void KitListGui::on_row_changed(const Gtk::TreeModel::Path path, const Gtk::TreeModel::iterator iter) {
1499  return;
1500  m_service.set_model_dirty(true);
1501  Gtk::TreeModel::Row row = *iter;
1502  int id = row[m_item_cols.m_col_num];
1503  Glib::ustring us = row[m_item_cols.m_col_text];
1504  string s(us);
1505  if (!m_service.update_item(id, s, row[m_item_cols.m_col_checked]))
1506  g_warning("Unable to find the item in the model: %d", id);
1507 }
1508 
1509 
1513 void KitListGui::selected_row_callback(const Gtk::TreeModel::iterator& iter) {
1514  Gtk::TreeModel::Row row = *iter;
1515  int id = row[m_item_cols.m_col_num];
1516  if (!m_service.delete_item(id))
1517  g_warning("Failed to find item to delete in model");
1518 }
1519 
1520 
1521 // void KitListGui::on_row_deleted(Gtk::TreeModel::Path path) {
1522 // m_dirty = true;
1523 // Gtk::TreeModel::iterator iter = m_ref_item_tree_model->get_iter(path);
1524 // if (iter) {
1525 // Gtk::TreeModel::Row row = *iter;
1526 // int id = row[m_item_cols.m_col_num];
1527 // ModelItem* item = m_model->findItem(id);
1528 // if (item) {
1529 // item->setDirty(true);
1530 // item->setDeleted(true);
1531 // } else {
1532 // cerr << _("Couldn't find item with id ") << id << endl;
1533 // }
1534 // } else {
1535 // cerr << _("Couldn't find model row being deleted") << endl;
1536 // }
1537 // }
1538 
1539 
1544  m_ignore_list_events = true;
1545  int cat_id = get_selected_category();
1546  // Fetch new list of items
1547  m_ref_item_tree_model->clear();
1548  ItemContainer *items = m_service.get_items(cat_id);
1549  if (items)
1550  sort(items->begin(), items->end(), ItemCompareName());
1551 
1552  // Rebuild the model for the list view
1553  size_t count = 0;
1554  if (items && !items->empty()) {
1555  for (ItemIter i = items->begin(); i != items->end(); ++i) {
1556  if (m_service.filter((*i)->get_checked())) {
1557  // Add a row to the model
1558  count++;
1559  Gtk::TreeModel::iterator item_iter = m_ref_item_tree_model->append();
1560  Gtk::TreeModel::Row row = *item_iter;
1561  row[m_item_cols.m_col_text] = (*i)->get_description();
1562  row[m_item_cols.m_col_num] = (*i)->get_id();
1563  row[m_item_cols.m_col_checked] = (*i)->get_checked();
1564  }
1565  }
1566  }
1567  if (items)
1568  delete items;
1569  update_item_count(count);
1570  m_ignore_list_events = false;
1571 }
1572 
1573 
1583  m_ignore_list_events = true;
1584 
1585  if (cat_id == -2)
1586  cat_id = get_selected_category();
1588  sort(c->begin(), c->end(), CategoryCompareName());
1589  m_ref_category_list_store->clear();
1590  Gtk::TreeModel::iterator iter = m_ref_category_list_store->append();
1591  Gtk::TreeModel::iterator active; // the row containing our category id
1592  Gtk::TreeModel::Row row = *iter;
1593  ostringstream os;
1594  // use the user's locale for this stream
1595  os.imbue(std::locale(""));
1596  os << "-- " << _("Show all items") << " --";
1597 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1598  row[m_category_cols.m_col_text] = Glib::locale_to_utf8(os.str());
1599 #else
1600  std::auto_ptr<Glib::Error> ex;
1601  row[m_category_cols.m_col_text] = Glib::locale_to_utf8(os.str(), ex);
1602  if (ex.get()) {
1603  g_warning("Failed to add item to category combo model: %s", ex->what().c_str());
1604  }
1605 #endif
1606  row[m_category_cols.m_col_num] = -1;
1607  if (!c->empty()) {
1608  for (CategoryIter i = c->begin(); i != c->end(); ++i) {
1609  ModelCategory* category = (ModelCategory*) *i;
1610  if ( !category->is_deleted() ) {
1611  // Add a row to the model
1612  iter = m_ref_category_list_store->append();
1613  row = *iter;
1614  row[m_category_cols.m_col_text] = category->get_name();
1615  row[m_category_cols.m_col_num] = category->get_id();
1616  if (category->get_id() == cat_id)
1617  active = iter;
1618  }
1619  }
1620  }
1621  delete c;
1622  if (!active || cat_id == -1)
1623  m_category_combo->set_active(0);
1624  else
1625  m_category_combo->set_active(active);
1626  m_ignore_list_events = false;
1627 }
1628 
1629 
1634  if (m_window_preferences) {
1635  if (m_entry_page_title) {
1636  m_entry_page_title->set_text(m_page_title);
1637  m_entry_page_title->grab_focus();
1638  m_window_preferences->show();
1639  } else {
1640  g_warning("\"entry_page_title\" resource is missing");
1641  }
1642  } else {
1643  g_warning("\"window_preferences\" resource is missing");
1644  }
1645 }
1646 
1647 void KitListGui::set_page_title(const Glib::ustring page_title) {
1648  m_page_title = page_title;
1649 #ifdef GCONF
1650 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1651  m_ref_gconf_client->set(GCONF_KEY_PAGE_TITLE, m_page_title);
1652 #else
1653  std::auto_ptr<Glib::Error> error;
1654  m_ref_gconf_client->set(GCONF_KEY_PAGE_TITLE, m_page_title, error);
1655  if (error.get())
1656  g_warning("GConf error setting page title: %s",
1657  error->what().c_str());
1658 #endif //GLIBMM_EXCEPTIONS_ENABLED
1659 #else
1661 #endif //GCONF
1662 }
1663 
1669  set_page_title(m_entry_page_title->get_text());
1670  m_window_preferences->hide();
1671 }
1672 
1673 
1675  m_window_preferences->hide();
1676 }
1677 
1678 
1683  if (m_window_add_item) {
1685  m_entry_add_item->grab_focus();
1686  m_window_add_item->show();
1687  } else {
1688  g_warning("\"window_add_item\" resource is missing");
1689  }
1690 }
1691 
1692 
1697  if (m_entry_add_item) {
1698  m_entry_add_item->set_text("");
1699  }
1700 }
1701 
1702 
1710  long retval = -1;
1711  Gtk::TreeModel::iterator iter = m_category_combo->get_active();
1712  if (iter) {
1713  Gtk::TreeModel::Row row = *iter;
1714  if (row) {
1715  retval = row[m_category_cols.m_col_num];
1716  }
1717  }
1718  return retval;
1719 }
1720 
1721 
1727  m_window_add_item->hide();
1728 
1729  // Find the current category
1730  long cat_id = get_selected_category();
1731 
1732  Item* item = m_service.create_item(cat_id);
1733  if (m_entry_add_item)
1734  item->set_description(m_entry_add_item->get_text());
1736  item->set_checked(m_checkbutton_add_item->get_active());
1737 
1739 }
1740 
1741 
1747  m_window_add_item->hide();
1748 }
1749 
1750 
1756  return;
1758 }
1759 
1760 
1763  m_window->present();
1764 }
1765 
1771 
1772  // Fetch startup preferences
1773 #ifdef XML_DAO
1774  Glib::ustring filename;
1775 #endif //XML_DAO
1776 
1777 #ifdef KITLIST_DEBUG
1778  Glib::ustring log_filename;
1779 #endif //KITLIST_DEBUB
1780 
1781 #ifdef GCONF
1782 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1783  try {
1784 #endif //GLIBMM_EXCEPTIONS_ENABLED
1785  Gnome::Conf::init();
1786  m_ref_gconf_client = Gnome::Conf::Client::get_default_client();
1787 
1788 #ifdef XML_DAO
1789  Gnome::Conf::Value value = Gnome::Conf::VALUE_INVALID;
1790 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1791  m_ref_gconf_client->add_dir(GCONF_KEY);
1792  value = m_ref_gconf_client->get(GCONF_KEY_CURRENT_FILENAME);
1793 #else
1794  std::auto_ptr<Glib::Error> error;
1795  m_ref_gconf_client->add_dir(GCONF_KEY,
1796  Gnome::Conf::CLIENT_PRELOAD_NONE,
1797  error);
1798  if (error.get())
1799  g_warning("GConf error: %s", error->what().c_str());
1800  value = m_ref_gconf_client->get(GCONF_KEY_CURRENT_FILENAME, error);
1801  if (error.get())
1802  g_warning("GConf error getting current filename: %s",
1803  error->what().c_str());
1804 #endif //GLIBMM_EXCEPTIONS_ENABLED
1805  if (value.get_type() == Gnome::Conf::VALUE_STRING) {
1806  filename = value.to_string();
1807  }
1808 #endif //XML_DAO
1809 
1810 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1811  value = m_ref_gconf_client->get(GCONF_KEY_PAGE_TITLE);
1812 #else
1813  value = m_ref_gconf_client->get(GCONF_KEY_PAGE_TITLE, error);
1814  if (error.get())
1815  g_warning("GConf error getting page title: %s",
1816  error->what().c_str());
1817 #endif // GLIBMM_EXCEPTIONS_ENABLED
1818  if (value.get_type() == Gnome::Conf::VALUE_STRING) {
1819  m_page_title = value.to_string();
1820  } else if (value.get_type() == Gnome::Conf::VALUE_INVALID) {
1821  // The default page title for printing
1823  }
1824 
1825  // Get default logfile name from GConf
1826 #ifdef KITLIST_DEBUG
1827 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1828  value = m_ref_gconf_client->get(GCONF_KEY_DEBUG_LOG);
1829 #else
1830  value = m_ref_gconf_client->get(GCONF_KEY_DEBUG_LOG, error);
1831  if (error.get())
1832  g_warning("GConf error getting log filename: %s",
1833  error->what().c_str());
1834 #endif // GLIBMM_EXCEPTIONS_ENABLED
1835  if (value.get_type() == Gnome::Conf::VALUE_STRING) {
1836  log_filename = value.to_string();
1837  } else if (value.get_type() == Gnome::Conf::VALUE_INVALID) {
1838  log_filename = "/tmp/kitlist.log";
1839 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1840  m_ref_gconf_client->set(GCONF_KEY_DEBUG_LOG, log_filename);
1841 #else
1842  std::auto_ptr<Glib::Error> error;
1843  m_ref_gconf_client->set(GCONF_KEY_DEBUG_LOG, log_filename, error);
1844  if (error.get())
1845  g_warning("GConf error setting log filename: %s",
1846  error->what().c_str());
1847 #endif //GLIBMM_EXCEPTIONS_ENABLED
1848  }
1849 #endif //KITLIST_DEBUG
1850 
1851 #ifdef GLIBMM_EXCEPTIONS_ENABLED
1852  } catch (const Glib::Error& ex) {
1853  g_warning("GConf error: %s", ex.what().c_str());
1854  }
1855 #endif //GLIBMM_EXCEPTIONS_ENABLED
1856 #else // GCONF
1857  // Try getting the value from XDG config file
1859  filename = m_yaml_config.get_current_filename();
1860 #ifdef KITLIST_DEBUG
1861  log_filename = m_yaml_config.get_debug_log_filename();
1862 #endif //KITLIST_DEBUG
1863 #endif // GCONF
1864 
1865 #ifdef KITLIST_DEBUG
1866  m_slog = new ofstream(log_filename.c_str(), ios_base::trunc);
1867  g_log_set_handler(NULL, (GLogLevelFlags) (G_LOG_LEVEL_MASK |
1868  G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION),
1869  my_log_handler, m_slog);
1870 #endif //KITLIST_DEBUG
1871 
1872  Glib::RefPtr<Gnome::Glade::Xml> refXml = get_glade_ref_ptr(GLADE_APP_FILE);
1873  refXml->get_widget("main", m_window);
1874  refXml->get_widget("statusbar", m_status_bar);
1875  refXml->get_widget("window_preferences", m_window_preferences);
1876  refXml->get_widget("entry_page_title", m_entry_page_title);
1877  refXml->get_widget("window_add_item", m_window_add_item);
1878  refXml->get_widget("window_add_category", m_window_add_category);
1879  m_window->signal_delete_event().connect( sigc::mem_fun(*this, &KitListGui::on_delete_event) );
1880 
1881  // Handle quit
1882  Gtk::MenuItem* p_menu_item = 0;
1883  refXml->get_widget("menu_file_quit", p_menu_item);
1884  if (p_menu_item)
1885  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_quit) );
1886  Gtk::ToolButton* p_tool_button = 0;
1887  refXml->get_widget("tool_button_quit", p_tool_button);
1888  if (p_tool_button)
1889  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_quit) );
1890 
1891  // Handle preferences
1892  p_menu_item = 0;
1893  refXml->get_widget("menu_preferences", p_menu_item);
1894  if (p_menu_item)
1895  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_preferences) );
1896 
1897  // Handle delete item
1898  p_menu_item = 0;
1899  refXml->get_widget("menu_delete_item", p_menu_item);
1900  if (p_menu_item)
1901  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_delete) );
1902  p_tool_button = 0;
1903  refXml->get_widget("tool_button_delete", p_tool_button);
1904  if (p_tool_button)
1905  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_delete) );
1906 
1907  // Handle add item
1908  p_menu_item = 0;
1909  refXml->get_widget("menu_add_item", p_menu_item);
1910  if (p_menu_item)
1911  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_add) );
1912  p_tool_button = 0;
1913  refXml->get_widget("tool_button_add", p_tool_button);
1914  if (p_tool_button)
1915  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_add) );
1916 
1917  Gtk::Button* p_button = 0;
1918  refXml->get_widget("preferences_ok_button", p_button);
1919  if (p_button)
1920  p_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::close_preferences_window) );
1921  refXml->get_widget("preferences_cancel_button", p_button);
1922  if (p_button)
1923  p_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::cancel_preferences_window) );
1924  refXml->get_widget("add_item_ok_button", p_button);
1925  if (p_button)
1926  p_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::close_add_item_window) );
1927  p_button = 0;
1928  refXml->get_widget("add_item_cancel_button", p_button);
1929  if (p_button)
1930  p_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::cancel_add_item_window) );
1931  refXml->get_widget("entry_item_desc", m_entry_add_item);
1932  assert(m_entry_add_item);
1933  refXml->get_widget("item_checkbutton", m_checkbutton_add_item);
1934  assert(m_checkbutton_add_item);
1935 
1936  // Handle file new
1937  p_menu_item = 0;
1938  refXml->get_widget("menu_new", p_menu_item);
1939  if (p_menu_item) {
1940  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_file_new) );
1941  p_menu_item->set_sensitive(m_service.require_filename());
1942  }
1943  p_tool_button = 0;
1944  refXml->get_widget("tool_button_new", p_tool_button);
1945  if (p_tool_button) {
1946  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_file_new) );
1947  p_tool_button->set_sensitive(m_service.require_filename());
1948  }
1949 
1950  // Handle file open
1951  p_menu_item = 0;
1952  refXml->get_widget("menu_open", p_menu_item);
1953  if (p_menu_item) {
1954  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_file_open) );
1955  p_menu_item->set_sensitive(m_service.require_filename());
1956  }
1957  p_tool_button = 0;
1958  refXml->get_widget("tool_button_open", p_tool_button);
1959  if (p_tool_button) {
1960  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_file_open) );
1961  p_tool_button->set_sensitive(m_service.require_filename());
1962  }
1963 
1964  // Handle save
1965  refXml->get_widget("menu_save", m_file_save_menu_item);
1967  m_file_save_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_save) );
1968  refXml->get_widget("tool_button_save", m_file_save_tool_button);
1970  m_file_save_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_save) );
1971  }
1972 
1973  // Handle save_as
1974  p_menu_item = 0;
1975  refXml->get_widget("menu_save_as", p_menu_item);
1976  if (p_menu_item) {
1977  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_save_as) );
1978 #ifdef TRANSITION_DAO
1979  p_menu_item->set_sensitive(true);
1980 #else
1981  p_menu_item->set_sensitive(m_service.require_filename());
1982 #endif
1983  }
1984 
1985  // Handle print
1986  p_menu_item = 0;
1987  refXml->get_widget("menu_print", p_menu_item);
1988  if (p_menu_item)
1989  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_print) );
1990  p_tool_button = 0;
1991  refXml->get_widget("tool_button_print", p_tool_button);
1992  if (p_tool_button)
1993  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_print) );
1994  // Export to PDF
1995  p_menu_item = 0;
1996  refXml->get_widget("menu_export_pdf", p_menu_item);
1997  if (p_menu_item)
1998  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_export_to_pdf) );
1999 
2000  // Recent files
2001  refXml->get_widget("menu_recent", m_recent_files_menu_item);
2002 
2003  // Handle cut
2004  p_menu_item = 0;
2005  refXml->get_widget("menu_cut", p_menu_item);
2006  if (p_menu_item)
2007  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_cut) );
2008  p_tool_button = 0;
2009  refXml->get_widget("tool_button_cut", p_tool_button);
2010  if (p_tool_button)
2011  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_cut) );
2012 
2013  // Handle copy
2014  p_menu_item = 0;
2015  refXml->get_widget("menu_copy", p_menu_item);
2016  if (p_menu_item)
2017  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_copy) );
2018  p_tool_button = 0;
2019  refXml->get_widget("tool_button_copy", p_tool_button);
2020  if (p_tool_button)
2021  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_copy) );
2022 
2023  // Handle paste
2024  refXml->get_widget("menu_paste", m_paste_menu_item);
2025  if (m_paste_menu_item)
2026  m_paste_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_paste) );
2027  refXml->get_widget("tool_button_paste", m_paste_tool_button);
2028  if (m_paste_tool_button)
2029  m_paste_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_paste) );
2030 
2031  // Handle menu show_all
2032  p_menu_item = 0;
2033  refXml->get_widget("show_all", p_menu_item);
2034  if (p_menu_item)
2035  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_show_all) );
2036  p_tool_button = 0;
2037  refXml->get_widget("tool_button_show_all", p_tool_button);
2038  if (p_tool_button)
2039  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_show_all) );
2040 
2041  // Handle menu show_checked
2042  p_menu_item = 0;
2043  refXml->get_widget("show_checked", p_menu_item);
2044  if (p_menu_item)
2045  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_show_checked) );
2046  p_tool_button = 0;
2047  refXml->get_widget("tool_button_show_checked", p_tool_button);
2048  if (p_tool_button)
2049  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_show_checked) );
2050 
2051  // Handle menu show_unchecked
2052  p_menu_item = 0;
2053  refXml->get_widget("show_unchecked", p_menu_item);
2054  if (p_menu_item)
2055  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_show_unchecked) );
2056  p_tool_button = 0;
2057  refXml->get_widget("tool_button_show_unchecked", p_tool_button);
2058  if (p_tool_button)
2059  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_show_unchecked) );
2060 
2061  // Handle menu refresh_view
2062  p_menu_item = 0;
2063  refXml->get_widget("refresh_view", p_menu_item);
2064  if (p_menu_item)
2065  p_menu_item->signal_activate().connect ( sigc::mem_fun(*this, &KitListGui::refresh_item_list) );
2066  p_tool_button = 0;
2067  refXml->get_widget("tool_button_refresh", p_tool_button);
2068  if (p_tool_button)
2069  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::refresh_item_list) );
2070 
2071  // Handle menu select_all
2072  p_menu_item = 0;
2073  refXml->get_widget("select_all", p_menu_item);
2074  if (p_menu_item)
2075  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_select_all) );
2076  p_tool_button = 0;
2077  refXml->get_widget("tool_button_select_all", p_tool_button);
2078  if (p_tool_button)
2079  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_select_all) );
2080 
2081  // Handle menu check_selected
2082  p_menu_item = 0;
2083  refXml->get_widget("check_selected", p_menu_item);
2084  if (p_menu_item)
2085  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_check_selected) );
2086  p_tool_button = 0;
2087  refXml->get_widget("tool_button_check_selected", p_tool_button);
2088  if (p_tool_button)
2089  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_check_selected) );
2090 
2091  // Handle menu uncheck_selected
2092  p_menu_item = 0;
2093  refXml->get_widget("uncheck_selected", p_menu_item);
2094  if (p_menu_item)
2095  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_uncheck_selected) );
2096  p_tool_button = 0;
2097  refXml->get_widget("tool_button_uncheck_selected", p_tool_button);
2098  if (p_tool_button)
2099  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::on_menu_uncheck_selected) );
2100 
2101  // Handle menu toggle_selected
2102  p_menu_item = 0;
2103  refXml->get_widget("toggle_selected", p_menu_item);
2104  if (p_menu_item)
2105  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::toggle_selected) );
2106  p_tool_button = 0;
2107  refXml->get_widget("tool_button_toggle_selected", p_tool_button);
2108  if (p_tool_button)
2109  p_tool_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::toggle_selected) );
2110 
2111  // Handle create_category
2112  p_menu_item = 0;
2113  refXml->get_widget("create_category", p_menu_item);
2114  if (p_menu_item)
2115  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_create_category) );
2116 
2117 #ifdef XML_DAO
2119 #else
2120  m_recent_files_menu_item->set_sensitive(false);
2121 #endif
2122 
2123  p_button = 0;
2124  refXml->get_widget("add_category_ok_button", p_button);
2125  if (p_button)
2126  p_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::close_add_category_window) );
2127  p_button = 0;
2128  refXml->get_widget("add_category_cancel_button", p_button);
2129  if (p_button)
2130  p_button->signal_clicked().connect( sigc::mem_fun(*this, &KitListGui::cancel_add_category_window) );
2131  refXml->get_widget("entry_category_name", m_entry_add_category);
2132  assert(m_entry_add_category);
2133 
2134  // Handle delete_category
2135  p_menu_item = 0;
2136  refXml->get_widget("delete_category", p_menu_item);
2137  if (p_menu_item)
2138  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_delete_category) );
2139 
2140  // Handle rename_category
2141  p_menu_item = 0;
2142  refXml->get_widget("rename_category", p_menu_item);
2143  if (p_menu_item)
2144  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_rename_category) );
2145 
2146  // Handle menu help_about
2147  p_menu_item = 0;
2148  refXml->get_widget("help_about", p_menu_item);
2149  if (p_menu_item)
2150  p_menu_item->signal_activate().connect( sigc::mem_fun(*this, &KitListGui::on_menu_help_about) );
2151 
2152  // Populate categories
2153  m_ref_category_list_store = Gtk::ListStore::create(m_category_cols);
2154  // Link the model to the category combo
2155  refXml->get_widget("categoryCombo", m_category_combo);
2157 
2159  m_category_combo->signal_changed().connect( sigc::mem_fun(*this, &KitListGui::on_category_change) );
2160 
2161  // Populate items
2162  m_ref_item_tree_model = Gtk::ListStore::create(m_item_cols);
2163  refXml->get_widget("item_treeview", m_item_tree_view);
2164  // Link the model to the item list
2166  ItemContainer* items = m_service.get_items();
2167  if (!items->empty()) {
2168  sort(items->begin(), items->end(), ItemCompareName());
2169  for (ItemIter i = items->begin(); i != items->end(); ++i) {
2170  // Add a row to the model
2171  Gtk::TreeModel::iterator itemIter = m_ref_item_tree_model->append();
2172  Gtk::TreeModel::Row row = *itemIter;
2173  row[m_item_cols.m_col_text] = (*i)->get_description();
2174  row[m_item_cols.m_col_num] = (*i)->get_id();
2175  row[m_item_cols.m_col_checked] = (*i)->get_checked();
2176  }
2177  }
2178  m_ref_item_tree_model->signal_row_changed().connect( sigc::mem_fun(*this, &KitListGui::on_row_changed) );
2179 // m_ref_item_tree_model->signal_row_deleted().connect( sigc::mem_fun(*this, &KitListGui::on_row_deleted) );
2180  update_item_count(items->size());
2181  delete items;
2182  // Column heading
2183  m_item_tree_view->append_column_editable(_("Checked"), m_item_cols.m_col_checked);
2184  // Column heading
2185  m_item_tree_view->append_column_editable(_("Item"), m_item_cols.m_col_text);
2186 // Gtk::CellRendererToggle* cr = (Gtk::CellRendererToggle*) m_item_tree_view->get_column_cell_renderer(CHECKED_COL_POSITION);
2187 // assert(cr);
2188 // if (cr)
2189 // cr->signal_toggled().connect( sigc::mem_fun(*this, &KitListGui::on_cell_edit) );
2190 // else
2191 // cerr << _("Error: Can't find toggle cell renderer for column ")
2192 // << CHECKED_COL_POSITION << endl;
2193  Glib::RefPtr<Gtk::TreeSelection> ref_tree_selection =
2194  m_item_tree_view->get_selection();
2195  ref_tree_selection->set_mode(Gtk::SELECTION_MULTIPLE);
2196  m_ignore_list_events = false;
2197  m_service.set_model_dirty(false);
2198 #ifdef XML_DAO
2199  if (filename.length() == 0 || !file_exists(filename)) {
2200  // Use default filename
2201  filename = Glib::build_filename(
2202  Glib::get_home_dir(),
2204  // g_debug("Set filename to: %s", filename.c_str());
2205  m_filename = filename;
2206  }
2207  if (filename.length() > 0 && file_exists(filename)) {
2208  // g_debug("Loading %s", filename.c_str());
2209  m_filename = filename;
2213  }
2214 #endif
2215 }
void run()
Starts the GUI application running.
Definition: kitlistgui.cpp:232
virtual bool choose_pdf_filename(Glib::ustring &filename)
Displays a file chooser dialog for a user to choose a filename for export to PDF. ...
virtual void cancel_add_category_window()
Called when the add/rename category dialog is closed using the &#39;Cancel&#39; button.
Gtk::MenuItem * m_recent_files_menu_item
The recent files menu item.
Definition: kitlistgui.hpp:146
Gtk::ComboBox * m_category_combo
The combo box holding a list of categories.
Definition: kitlistgui.hpp:154
Gtk::Window * m_window_preferences
The &#39;Preferences&#39; dialog.
Definition: kitlistgui.hpp:130
Gtk::TreeModel::Children type_children
Definition: kitlistgui.cpp:124
ModelItemContainer::iterator ModelItemIter
Definition: kitmodel.hpp:82
virtual void on_menu_show_all()
Causes all items to be displayed.
Definition: kitlistgui.hpp:218
virtual void on_menu_delete()
Called when the user chooses to delete items.
Definition: kitlistgui.cpp:855
virtual void on_menu_cut()
Definition: kitlistgui.cpp:911
virtual bool on_delete_event(GdkEventAny *event)
Called when the application is closed by the user.
Definition: kitlistgui.cpp:356
Gtk::Window * m_window
The main application window.
Definition: kitlistgui.hpp:128
ModelCategory * find_category(long cat_id)
Definition: service.cpp:133
const Glib::ustring GCONF_KEY_CURRENT_FILENAME
GConf entry for the current filename.
Definition: kitlistgui.cpp:89
const Glib::ustring GCONF_KEY_MAX_RECENT_FILES
GConf entry for max recent files.
Definition: kitlistgui.cpp:105
Glib::ustring get_debug_log_filename()
the name of the debug log file.
Definition: yamlconfig.hpp:120
void on_printoperation_status_changed(const Glib::RefPtr< Gtk::PrintOperation > &op)
Called when the print status changes.
Definition: kitlistgui.cpp:633
virtual void on_menu_create_category()
Called when the user chooses to create a new category.
Definition: kitlistgui.cpp:971
Category * create_category()
Creates a new category.
Definition: service.cpp:220
enum gui_state m_state
Indicates whether a category is being created or renamed.
Definition: kitlistgui.hpp:180
std::string get_name()
Definition: category.hpp:47
Gtk::Window * m_window_add_category
The &#39;Add Category&#39; dialog.
Definition: kitlistgui.hpp:136
Represents a Category combined with GuiState attributes.
Definition: kitmodel.hpp:94
virtual void on_menu_quit()
Called when the user chooses to quit the application.
Definition: kitlistgui.cpp:370
virtual void update_item_count(size_t n)
const guint SB_SAVE
Status bar message constant for save notifications.
Definition: kitlistgui.cpp:61
virtual void select_items(ModelItemContainer *items, bool checked=true)
Checks or unchecks all the passed items.
Definition: service.cpp:238
virtual void update_recent_files_menu()
Updates the recent files sub menu.
Definition: kitlistgui.cpp:285
ItemContainer::iterator ItemIter
Definition: item.hpp:92
CategoryContainer::iterator CategoryIter
Definition: category.hpp:85
virtual void delete_selected_items()
Deletes the currently selected items.
Definition: kitlistgui.cpp:823
long m_current_cat_id
temporary reference to a category id, usually being renamed
Definition: kitlistgui.hpp:181
Gtk::Entry * m_entry_page_title
the text entry field for the page title
Definition: kitlistgui.hpp:132
virtual void update_recent_files(const Glib::ustring &filename)
Definition: kitlistgui.cpp:324
virtual void on_menu_recent_file(const Glib::ustring &filename)
displays the most recent files menu
Definition: kitlistgui.cpp:742
Glib::ustring m_page_title
The page title to be used when printing the item list.
Definition: kitlistgui.hpp:116
void set_dirty(bool dirty=true)
Definition: kitmodel.hpp:46
virtual void close_add_category_window()
Called when the add/rename category dialog is closed using the &#39;OK&#39; button.
Definition: kitlistgui.cpp:997
STL namespace.
YamlConfig m_yaml_config
Definition: kitlistgui.hpp:102
const bool file_exists(const Glib::ustring &filename)
Returns true if the passed file exists.
Definition: kitlistgui.cpp:135
Gtk::Window * m_window_add_item
The &#39;Add Item&#39; dialog.
Definition: kitlistgui.hpp:134
virtual void init_add_item_window()
std::vector< Item * > ItemContainer
Definition: item.hpp:91
Gtk::CheckButton * m_checkbutton_add_item
The check button field of the &#39;Add Item&#39; dialog.
Definition: kitlistgui.hpp:152
Gtk::TreeModelColumn< int > m_col_num
Definition: kitlistgui.hpp:88
Gtk::Statusbar * m_status_bar
The application status bar.
Definition: kitlistgui.hpp:168
virtual void set_selected(bool checked)
ModelItemColumns m_item_cols
The definition of the item list&#39;s columns.
Definition: kitlistgui.hpp:162
void add_recent_filename(Glib::ustring filename)
Adds a filename to the list of recently used filenames.
Definition: yamlconfig.cpp:141
virtual void remove_items(ModelItemContainer *items)
Removes all the passed items from this ModelCategory.
Definition: kitmodel.cpp:122
virtual void set_checked(bool checked)
Definition: item.hpp:49
virtual void on_menu_save()
Saves the current application state.
Definition: kitlistgui.cpp:528
Gtk::ToolButton * m_paste_tool_button
The toolbar paste button.
Definition: kitlistgui.hpp:150
void set_name(const std::string name)
Definition: category.hpp:46
virtual void cancel_add_item_window()
Glib::ustring get_current_filename()
The current filename.
Definition: yamlconfig.hpp:93
Gtk::Entry * m_entry_add_category
The text entry field of the &#39;Add Category&#39; dialog.
Definition: kitlistgui.hpp:140
void set_current_filename(Glib::ustring filename)
Sets the current filename.
Definition: yamlconfig.hpp:98
virtual void on_clipboard_clear()
This method gets called after a second &#39;copy&#39; operation.
virtual void on_menu_check_selected()
Marks all selected items as checked.
Definition: kitlistgui.hpp:225
Gtk::Entry * m_entry_add_item
The text entry field of the &#39;Add Item&#39; dialog.
Definition: kitlistgui.hpp:138
const string GLADE_APP_FILE
Resource file name.
Definition: kitlistgui.cpp:56
virtual void on_menu_show_unchecked()
Causes only unchecked items to be displayed.
Definition: kitlistgui.hpp:222
virtual void on_category_change()
void open_as_xml(const Glib::ustring &filename)
Loads a new data model from the named XML document.
Definition: service.cpp:70
KitListGui(int argc, char **argv, Service &service)
Definition: kitlistgui.cpp:193
virtual void set_page_title(const Glib::ustring page_title)
virtual void open_file(const Glib::ustring &filename)
Opens an existing XML document.
Definition: kitlistgui.cpp:481
Service & m_service
The business/service object.
Definition: kitlistgui.hpp:164
Glib::RefPtr< Gtk::PageSetup > m_ref_page_setup
Printer page setup settings.
Definition: kitlistgui.hpp:170
Comparator used for sorting Items by name.
Definition: item.hpp:61
virtual void init()
ItemContainer * get_items(long cat_id=-1)
Returns a list of items.
Definition: service.cpp:305
std::vector< ModelItem * > ModelItemContainer
Definition: kitmodel.hpp:81
Item * create_item(long cat_id)
Creates a new ModelItem and associates it with the specified category.
Definition: service.cpp:159
virtual long get_selected_category()
Returns the ID of the currently selected Category.
Gtk::Main m_kit
The main application.
Definition: kitlistgui.hpp:126
Glib::RefPtr< Gtk::ListStore > m_ref_item_tree_model
The model backing the item list.
Definition: kitlistgui.hpp:166
bool m_ignore_list_events
Temporarily ignore events on the item list.
Definition: kitlistgui.hpp:124
Gtk::TreeModelColumn< Glib::ustring > m_col_text
Definition: kitlistgui.hpp:86
virtual void on_menu_paste()
Called when the user chooses the &#39;paste&#39; menu option.
Definition: kitlistgui.cpp:946
Glib::RefPtr< Gnome::Glade::Xml > get_glade_ref_ptr(const string &filename, const Glib::ustring &root=Glib::ustring(), const Glib::ustring &domain=Glib::ustring())
Returns a reference to the Glade resource file.
Definition: kitlistgui.cpp:164
virtual void on_clipboard_received(const Gtk::SelectionData &selection_data)
bool delete_category(long cat_id)
Flags a category as deleted.
Definition: service.cpp:200
Glib::ustring m_filename
The filename currently associated with the loaded model.
Definition: kitlistgui.hpp:114
const std::string DEFAULT_PAGE_TITLE
The default page title for printing.
Definition: yamlconfig.hpp:32
virtual ModelItemContainer * get_selected_items()
Returns a list of items selected in the item list.
Definition: kitlistgui.cpp:777
Glib::ustring get_page_title()
The page title to use for printing or creating a PDF.
Definition: yamlconfig.hpp:102
const char item_target_custom[]
Key used for custom clipboard.
Definition: kitlistgui.cpp:69
const char XML_ELEMENT_ID[]
Tag name for the ID element in the clipbard XML document.
Definition: kitlistgui.cpp:74
virtual void on_menu_show_checked()
Causes only checked items to be displayed.
Definition: kitlistgui.hpp:220
virtual void on_menu_preferences()
void on_printoperation_done(Gtk::PrintOperationResult result, const Glib::RefPtr< Gtk::PrintOperation > &op)
Called when the printer operation is done.
Definition: kitlistgui.cpp:648
Glib::ustring m_clipboard_items
Holder for items pasted to the clipboard.
Definition: kitlistgui.hpp:122
Represents an Item.
Definition: item.hpp:37
virtual void cancel_preferences_window()
virtual void paste_status_received(const Glib::StringArrayHandle &targets_array)
virtual bool choose_filename(Glib::ustring &filename)
Displays a file chooser dialog for a user to choose a filename.
virtual void add_items(const ModelItemContainer &items)
Associates the passed list of items with the currently selected category.
void save_as_xml(const Glib::ustring &filename)
Saves the model&#39;s state to an XML document.
Definition: service.cpp:111
virtual void close_preferences_window()
CategoryContainer * get_categories()
Returns a list of all categories.
Definition: service.cpp:354
bool update_item(long id, const std::string description, bool checked)
Updates the attributes of an item.
Definition: service.cpp:282
virtual ModelItemContainer * copy_selected_items_to_clipboard()
Definition: kitlistgui.cpp:878
Gtk::ImageMenuItem * m_paste_menu_item
The menu paste button.
Definition: kitlistgui.hpp:148
void save()
Definition: service.cpp:98
virtual void on_menu_file_open()
Allows the user to open an existing XML document.
Definition: kitlistgui.cpp:432
bool is_deleted()
Definition: kitmodel.hpp:47
Represents a Category.
Definition: category.hpp:37
virtual void on_clipboard_get(Gtk::SelectionData &selection_date, guint)
virtual void on_menu_help_about()
const guint SB_ITEM_COUNT
Status bar message constant for displaying item counts.
Definition: kitlistgui.cpp:59
const string load_resource_glade_file(const Glib::ustring &filename)
Locate the Glade resource file from a list of potential locations.
Definition: kitlistgui.cpp:145
void set_page_title(Glib::ustring title)
Set the page title.
Definition: yamlconfig.hpp:109
Gtk::TreeModelColumn< int > m_col_num
Definition: kitlistgui.hpp:67
virtual void update_paste_status()
Enables or disables the paste menu option.
virtual void on_menu_add()
Represents an Item combined with GuiState attributes.
Definition: kitmodel.hpp:60
static Glib::RefPtr< KitPrintOperation > create()
Factory to create instances.
Definition: printing.cpp:51
virtual void toggle_selected_items(ModelItemContainer *items)
Toggles the checked state of all the passed items.
Definition: service.cpp:252
void copy_items(const ModelItemContainer &items, long cat_id)
Copies items to the specified category.
Definition: service.cpp:144
bool delete_item(long id)
Flags an item as deleted.
Definition: service.cpp:180
virtual void close_add_item_window()
Glib::RefPtr< Gtk::ListStore > m_ref_category_list_store
The model backing the category combo box.
Definition: kitlistgui.hpp:156
virtual void on_menu_rename_category()
Called when the user chooses to rename a category.
virtual void on_menu_delete_category()
Called when the user chooses the delete category menu option.
Gtk::ImageMenuItem * m_file_save_menu_item
The file save menu item.
Definition: kitlistgui.hpp:142
virtual bool confirm_lose_changes(const Glib::ustring &message)
Shows a confirmation message.
Definition: kitlistgui.cpp:247
const Glib::ustring DEFAULT_FILENAME
The default filename.
Definition: kitlistgui.cpp:83
virtual gint get_max_recent_files()
Definition: kitlistgui.cpp:240
virtual void toggle_selected()
Comparator used for sorting Categories by name.
Definition: category.hpp:66
long get_id()
Definition: category.hpp:45
const gint DEFAULT_MAX_RECENT_FILES
The maximum number of recent files to maintain.
Definition: yamlconfig.hpp:35
bool is_model_dirty()
Definition: service.hpp:55
const char item_target_text[]
Mime type for clipboard content.
Definition: kitlistgui.cpp:71
virtual void on_menu_select_all()
Called when the user chooses the &#39;select all&#39; menu option.
Definition: kitlistgui.cpp:960
const Glib::ustring PDF_FILENAME_EXTENSION
PDF filename extension.
Definition: kitlistgui.cpp:80
ItemContainer * get_filtered_items(long cat_id=-1)
Returns a list of items, applying the current filter.
Definition: service.cpp:331
Gtk::TreeView * m_item_tree_view
The item list view definition.
Definition: kitlistgui.hpp:160
virtual void refresh_category_list(long cat_id=-2)
Refreshes the category combo box list.
const guint SB_PRINT
Status bar message constant for printer messages.
Definition: kitlistgui.cpp:66
virtual void on_menu_print()
Prints the kit list.
Definition: kitlistgui.cpp:663
std::vector< Category * > CategoryContainer
Definition: category.hpp:84
virtual bool require_filename()
Definition: service.hpp:80
const guint SB_MSG
Status bar message constant for general messages.
Definition: kitlistgui.cpp:63
const Glib::ustring GCONF_KEY_RECENT_FILES
GConf entry for recent files.
Definition: kitlistgui.cpp:102
virtual void safe_open_file(const Glib::ustring &filename)
Opens an existing XML document, checking for unsaved changes.
Definition: kitlistgui.cpp:514
virtual void on_menu_uncheck_selected()
Marks all selected items as unchecked.
Definition: kitlistgui.hpp:227
Gtk::TreeModelColumn< Glib::ustring > m_col_text
Definition: kitlistgui.hpp:66
Glib::RefPtr< Gtk::PrintSettings > m_ref_printer_settings
Printer settings.
Definition: kitlistgui.hpp:172
void set_model_dirty(bool flag=true)
Definition: service.cpp:264
virtual void selected_row_callback(const Gtk::TreeModel::iterator &iter)
void on_row_changed(const Gtk::TreeModel::Path path, const Gtk::TreeModel::iterator iter)
Callback method called when an item has been modified in the item list.
virtual void on_cell_edit(const Glib::ustring s)
Callback method called when a cell has been edited in the item list.
const Glib::ustring DEFAULT_FILENAME_EXTENSION
Default filename extension.
Definition: kitlistgui.cpp:77
Gtk::TreeModelColumn< bool > m_col_checked
Definition: kitlistgui.hpp:87
void create_default_model()
Creates a default model.
Definition: service.cpp:83
virtual void on_menu_save_as()
Saves the current application state in a new document.
Definition: kitlistgui.cpp:579
const Glib::ustring GCONF_KEY
The application&#39;s root key in the GConf hierarchy.
Definition: kitlistgui.cpp:86
virtual void on_menu_export_to_pdf()
Definition: kitlistgui.cpp:692
std::deque< Glib::ustring > get_recent_filenames()
The history list of recent filenames.
Definition: yamlconfig.hpp:116
ModelItem * find_item(long id)
Definition: service.cpp:125
void set_description(const std::string description)
Definition: item.hpp:47
virtual void paste_from_xml(const Glib::ustring &document)
virtual void raise()
Make this application topmost.
virtual bool filter(bool checked)
Applies the current filter.
Definition: service.hpp:63
Gtk::ToolButton * m_file_save_tool_button
The file save toolbar button.
Definition: kitlistgui.hpp:144
Business/service layer implementation.
Definition: service.hpp:38
ModelCategoryColumns m_category_cols
The definition of the category combo box columns.
Definition: kitlistgui.hpp:158
virtual void refresh_item_list()
virtual void on_menu_copy()
Called when the use chooses the &#39;copy&#39; menu option.
Definition: kitlistgui.cpp:937
virtual void on_menu_file_new()
Creates a new empty model.
Definition: kitlistgui.cpp:387
const Glib::ustring GCONF_KEY_PAGE_TITLE
GConf entry for the page title.
Definition: kitlistgui.cpp:92

Copyright 2008-2021 Frank Dean