Logo Search packages:      
Sourcecode: tagcolledit version File versions  Download package

TagcollEditor.cc

/*
 * Main application class
 *
 * Copyright (C) 2003  Enrico Zini
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "TagcollEditor.h"

#include <tagcoll/stringf.h>
#include "Environment.h"

#include <gtkmm/stock.h>
#include <gtkmm/fileselection.h>
#include <gtkmm/messagedialog.h>

#include <map>

using namespace std;
using namespace Tagcoll;


TagcollEditor::TagcollEditor(TagcollDocument<std::string>& doc)
      : doc(doc), addLabel("No items selected"), addButton("Add"), /*panelTable(1, 2, true),*/ changed(false), currentPanel(0)
{
      panels[0] = new TagPanel(doc, TagPanel::LEFT);
      panels[1] = new TagPanel(doc, TagPanel::RIGHT);

      set_title("Tagged Collection Editor");
      //set_border_width(5);
      set_default_size(700, 500);

      add(mainVBox);

      mainVBox.pack_start(menuBar, Gtk::PACK_SHRINK);
      mainVBox.pack_start(entryHBox, Gtk::PACK_SHRINK);
      mainVBox.pack_start(mainHPaned, Gtk::PACK_EXPAND_WIDGET);

      entryHBox.pack_start(addLabel, Gtk::PACK_SHRINK);
      entryHBox.pack_start(addCombo, Gtk::PACK_EXPAND_WIDGET);
      entryHBox.pack_start(addButton, Gtk::PACK_SHRINK);
      //currentAdd.set_text("");
      
      TagSet tags = doc.vocabulary().getTags();
      vector<string> string_tags;
      for (TagSet::const_iterator i = tags.begin(); i != tags.end(); i++)
            string_tags.push_back(i->fullname());
      addCombo.set_popdown_strings(string_tags);

      //currentAdd.get_entry()->signal_changed().connect(
      addButton.signal_clicked().connect(
                  sigc::mem_fun(*this, &TagcollEditor::on_addButton_clicked));

      mainHPaned.add1(*panels[0]);
      mainHPaned.add2(*panels[1]);
      //panelTable.attach(*panels[0], 0, 1, 0, 1, Gtk::FILL | Gtk::EXPAND | Gtk::SHRINK, Gtk::FILL | Gtk::EXPAND | Gtk::SHRINK, 1, 0);
      //panelTable.attach(*panels[1], 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND | Gtk::SHRINK, Gtk::FILL | Gtk::EXPAND | Gtk::SHRINK, 1, 0);

      doc.signal_changed().connect(sigc::mem_fun(*this, &TagcollEditor::on_doc_change));
      doc.signal_filename_changed().connect(sigc::mem_fun(*this, &TagcollEditor::on_filename_change));
      panels[0]->signal_selection_changed().connect(sigc::mem_fun(*this, &TagcollEditor::on_selection_change));
      panels[1]->signal_selection_changed().connect(sigc::mem_fun(*this, &TagcollEditor::on_selection_change));
      panels[0]->signal_focus_in().connect(sigc::mem_fun(*this, &TagcollEditor::on_leftpanel_focus));
      panels[1]->signal_focus_in().connect(sigc::mem_fun(*this, &TagcollEditor::on_rightpanel_focus));
      panels[0]->signal_request_tagcoll_change().connect(sigc::mem_fun(*this, &TagcollEditor::on_request_tagcoll_change));
      panels[1]->signal_request_tagcoll_change().connect(sigc::mem_fun(*this, &TagcollEditor::on_request_tagcoll_change));
      panels[0]->signal_request_tagset_merge().connect(sigc::mem_fun(*this, &TagcollEditor::on_merge));
      panels[1]->signal_request_tagset_merge().connect(sigc::mem_fun(*this, &TagcollEditor::on_merge));
      panels[0]->signal_request_tagset_intersect().connect(sigc::mem_fun(*this, &TagcollEditor::on_intersect));
      panels[1]->signal_request_tagset_intersect().connect(sigc::mem_fun(*this, &TagcollEditor::on_intersect));
      panels[0]->signal_request_item_copy().connect(sigc::mem_fun(*this, &TagcollEditor::on_copy_to_other));
      panels[1]->signal_request_item_copy().connect(sigc::mem_fun(*this, &TagcollEditor::on_copy_to_other));
      panels[0]->signal_request_item_move().connect(sigc::mem_fun(*this, &TagcollEditor::on_move_to_other));
      panels[1]->signal_request_item_move().connect(sigc::mem_fun(*this, &TagcollEditor::on_move_to_other));
      panels[0]->signal_select_tagset().connect(sigc::mem_fun(*this, &TagcollEditor::on_select_tagset_panel1));
      panels[1]->signal_select_tagset().connect(sigc::mem_fun(*this, &TagcollEditor::on_select_tagset_panel2));
      panels[0]->signal_select_tagset_other_panel().connect(sigc::mem_fun(*this, &TagcollEditor::on_select_tagset_panel2));
      panels[1]->signal_select_tagset_other_panel().connect(sigc::mem_fun(*this, &TagcollEditor::on_select_tagset_panel1));

      menuBar.items().push_back(Gtk::Menu_Helpers::MenuElem("_File", fileMenu));
      menuBar.items().push_back(Gtk::Menu_Helpers::MenuElem("_Edit", editMenu));

      fileMenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::OPEN,
                        sigc::mem_fun(*this, &TagcollEditor::on_open)));
      fileMenu.items().push_back(Gtk::Menu_Helpers::MenuElem("Load _Debtags",
                        sigc::mem_fun(*this, &TagcollEditor::on_open_debtags)));
      fileMenu.items().push_back(Gtk::Menu_Helpers::SeparatorElem());

      fileMenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::SAVE,
                        sigc::mem_fun(*this, &TagcollEditor::on_save)));
      saveMenuItem = &(fileMenu.items().back());
      saveMenuItem->set_sensitive(false);
      fileMenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::SAVE_AS,
                        sigc::mem_fun(*this, &TagcollEditor::on_save_as)));
      saveasMenuItem = &(fileMenu.items().back());
      fileMenu.items().push_back(Gtk::Menu_Helpers::SeparatorElem());

      fileMenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::QUIT,
                        sigc::mem_fun(*this, &TagcollEditor::on_quit)));


      editMenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::UNDO,
                        sigc::mem_fun(*this, &TagcollEditor::on_undo)));
      undoMenuItem = &(editMenu.items().back());
      editMenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::REDO,
                        sigc::mem_fun(*this, &TagcollEditor::on_redo)));
      redoMenuItem = &(editMenu.items().back());
      editMenu.items().push_back(Gtk::Menu_Helpers::SeparatorElem());

      editMenu.items().push_back(Gtk::Menu_Helpers::MenuElem("_Merge",
                        sigc::mem_fun(*this, &TagcollEditor::on_merge)));
      mergeMenuItem = &(editMenu.items().back());
      editMenu.items().push_back(Gtk::Menu_Helpers::MenuElem("_Intersect",
                        sigc::mem_fun(*this, &TagcollEditor::on_intersect)));
      intersectMenuItem = &(editMenu.items().back());
      editMenu.items().push_back(Gtk::Menu_Helpers::MenuElem("Co_py to other panel",
                        sigc::mem_fun(*this, &TagcollEditor::on_copy_to_other)));
      copyToOtherMenuItem = &(editMenu.items().back());
      editMenu.items().push_back(Gtk::Menu_Helpers::MenuElem("Mo_ve to other panel",
                        sigc::mem_fun(*this, &TagcollEditor::on_move_to_other)));
      moveToOtherMenuItem = &(editMenu.items().back());
      editMenu.items().push_back(Gtk::Menu_Helpers::MenuElem("Delete _unselected tags",
                        sigc::mem_fun(*this, &TagcollEditor::on_delete_unselected)));
      deleteUnselectedMenuItem = &(editMenu.items().back());

      //menuBar.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::HELP, helpMenu));
      checkUndo();
      setChanged(false);
      on_filename_change();
      on_selection_change();

      show_all_children();
}

void TagcollEditor::on_leftpanel_focus()
{
      debug("leftpanel_focus\n");
      currentPanel = 0;
}

void TagcollEditor::on_rightpanel_focus()
{
      debug("rightpanel_focus\n");
      currentPanel = 1;
}

void TagcollEditor::setChanged(bool val)
{
      changed = val;
      on_filename_change();
}

void TagcollEditor::on_doc_change()
{
      checkUndo();
      setChanged(true);

      TagSet tags = doc.vocabulary().getTags();
      vector<string> string_tags;
      for (TagSet::const_iterator i = tags.begin(); i != tags.end(); i++)
            string_tags.push_back(i->fullname());
      addCombo.set_popdown_strings(string_tags);

      /*
      allTags = doc.collection().getAllTags();
      addCombo.set_popdown_strings(allTags);
      */
}

void TagcollEditor::on_filename_change()
{
      if (doc.fileName().empty())
      {
            set_title(string("Tagged Collection Editor - debtags Database") + (changed ? " [*]" : ""));
            saveMenuItem->set_sensitive(false);
      }
      else
      {
            set_title("Tagged Collection Editor - " + doc.fileName() + (changed ? " [*]" : ""));
            saveMenuItem->set_sensitive(changed);
      }
}

void TagcollEditor::on_selection_change()
{
      int size = activePanel().getSelectionSize();

      /*
      if (size == 1)
      {
            std::map< string, OpSet<string> > data = activePanel().getSelection();
            OpSet<string>& tags = data.begin()->second;
            std::string val;
            for (OpSet<string>::const_iterator i = tags.begin();
                        i != tags.end(); i++)
                  if (i == tags.begin())
                        val += "Current tag set: " + *i;
                  else
                        val += ", " + *i;
            currentLabel.set_text(val + " ");
            currentAdd.set_sensitive(true);
      } else*/ if (size >= 1) {
            addLabel.hide();
            addCombo.show();
            addButton.set_sensitive(true);
      } else {
            addLabel.show();
            addCombo.hide();
            addButton.set_sensitive(false);
      }

      mergeMenuItem->set_sensitive(size >= 2);
      intersectMenuItem->set_sensitive(size >= 2);
      copyToOtherMenuItem->set_sensitive(size >= 1);
      moveToOtherMenuItem->set_sensitive(size >= 1);
      deleteUnselectedMenuItem->set_sensitive(size >= 1);
}

void TagcollEditor::checkUndo()
{
      undoMenuItem->set_sensitive(doc.canUndo());
      redoMenuItem->set_sensitive(doc.canRedo());
}

void TagcollEditor::on_open_debtags()
{
      try {
            doc.loadDebtags();
      } catch (Exception& e) {
            warning("%s: %.*s", e.type(), PFSTR(e.desc()));
      }
}

void TagcollEditor::on_open()
{
      Gtk::FileSelection dialog("Please select the name of the file to open");
      dialog.set_transient_for(*this);
      //dialog.get_file_list()->get_parent()->hide(); //Prevent the user from selecting a file.

      int result = dialog.run();

      //Handle the response:
      switch (result)
      {
            case Gtk::RESPONSE_OK:
            {
                  try {
                        doc.load(dialog.get_filename());
                  } catch (Exception& e) {
                        warning("%s: %.*s", e.type(), PFSTR(e.desc()));
                  }
                  break;
            }
            case Gtk::RESPONSE_CANCEL:
            {
                  break;
            }
            default:
            {
                  warning("Unexpected button clicked in load file selection dialog");
                  break;
            }
      }
}
      
void TagcollEditor::on_save()
{
      if (!doc.fileName().empty())
      {
            doc.save(doc.fileName());
            setChanged(false);
      }
}

void TagcollEditor::on_save_as()
{
      Gtk::FileSelection dialog("Please select the file name to save as");
      dialog.set_transient_for(*this);
      //dialog.get_file_list()->get_parent()->hide(); //Prevent the user from selecting a file.

      int result = dialog.run();

      //Handle the response:
      switch (result)
      {
            case Gtk::RESPONSE_OK:
            {
                  try {
                        doc.save(dialog.get_filename());
                  } catch (Exception& e) {
                        warning("%s: %.*s", e.type(), PFSTR(e.desc()));
                  }
                  setChanged(false);
                  break;
            }
            case Gtk::RESPONSE_CANCEL:
            {
                  break;
            }
            default:
            {
                  warning("Unexpected button clicked in save as... file selection dialog");
                  break;
            }
      }
}

void TagcollEditor::on_quit()
{
      hide();
}

void TagcollEditor::on_undo()
{
      doc.undo();
}

void TagcollEditor::on_redo()
{
      doc.redo();
}

void TagcollEditor::on_merge()
{
      // Get the contents of the selection
      std::map< string, TagSet > data = activePanel().getSelection();

      /*
      warning("LTP: %s\n", leftTagPanel.isActive() ? "Y" : "N");
      warning("RTP: %s\n", rightTagPanel.isActive() ? "Y" : "N");
      */    

      // Compute the union
      TagSet merged;
      for (std::map< string, TagSet >::const_iterator i = data.begin();
                  i != data.end(); i++)
            merged += i->second;

      // Make the changes
      PatchList<string, Tag> change;
      for (std::map< string, TagSet >::const_iterator i = data.begin();
                  i != data.end(); i++)
      {
            Patch<string, Tag> patch(i->first);
            patch.add(merged - i->second);
            change.addPatch(patch);
      }

      doc.applyChange(change);
}

void TagcollEditor::on_intersect()
{
      // Get the contents of the selection
      std::map< string, TagSet > data = activePanel().getSelection();

      if (data.empty())
            return;

      // Compute the intersection
      std::map< string, TagSet >::const_iterator i = data.begin();
      TagSet intersected = i->second;
      OpSet<string> items;
      for ( ; i != data.end(); i++)
      {
            items += i->first;
            intersected ^= i->second;
      }

      // Make the changes
      PatchList<string, Tag> change;
      for (std::map< string, TagSet >::const_iterator i = data.begin();
                  i != data.end(); i++)
      {
            Patch<string, Tag> patch(i->first);
            patch.add(intersected - i->second);
            patch.remove(i->second - intersected);
            change.addPatch(patch);
      }

      doc.applyChange(change);
}

void TagcollEditor::on_copy_to_other()
{
      std::map< string, TagSet > sourceItems = activePanel().getSelection();
      TagSet targetTags = otherPanel().selectedTags();

      PatchList<string, Tag> change;

      // Merge the source tagsets with the currently selected tagset of the target panel
      for (std::map< string, TagSet >::const_iterator i = sourceItems.begin();
                  i != sourceItems.end(); i++)
      {
            Patch<string, Tag> patch(i->first);
            patch.add(targetTags);
            change.addPatch(patch);
      }

      doc.applyChange(change);
}

void TagcollEditor::on_move_to_other()
{
      std::map< string, TagSet > sourceItems = activePanel().getSelection();
      TagSet targetTags = otherPanel().selectedTags();

      PatchList<string, Tag> change;

      // Replace the source tagsets with the currently selected tagset of the target panel
      for (std::map< string, TagSet >::const_iterator i = sourceItems.begin();
                  i != sourceItems.end(); i++)
      {
            Patch<string, Tag> patch(i->first);
            patch.add(targetTags - i->second);
            patch.remove(i->second - targetTags);
            change.addPatch(patch);
      }

      doc.applyChange(change);
}

void TagcollEditor::on_delete_unselected()
{
      // Get the contents of the selection
      std::map< string, TagSet > data = activePanel().getSelection();

      if (data.empty())
            return;

      // Prepare the change
      TagSet selected = activePanel().selectedTags();
      PatchList<string, Tag> change;
      for (std::map< string, TagSet >::const_iterator i = data.begin();
                  i != data.end(); i++)
      {
            //change.insert(make_pair(i->first, i->second ^ selected));
            Patch<string, Tag> patch(i->first);
            patch.remove(i->second - selected);
            change.addPatch(patch);
      }


      // Make the change
      doc.applyChange(change);
}

void TagcollEditor::on_request_tagcoll_change(PatchList<string, Tag> change)
{
      doc.applyChange(change);
}

void TagcollEditor::on_select_tagset_panel1(TagSet tagset)
{
      panels[0]->selectedTags(tagset);
}

void TagcollEditor::on_select_tagset_panel2(TagSet tagset)
{
      panels[1]->selectedTags(tagset);
}

void TagcollEditor::on_addButton_clicked()
{
      string tag = addCombo.get_entry()->get_text();
      if (tag == "")
            return;

      if (!doc.vocabulary().hasTag(tag))
      {
            Gtk::MessageDialog dialog(*this, "Tag " + tag + " does not exist: do you want to create it?",
                        false, Gtk::MESSAGE_QUESTION, (Gtk::ButtonsType)(Gtk::BUTTONS_YES_NO));
            int result = dialog.run();

            //Handle the response:
            switch (result)
            {
                  case Gtk::RESPONSE_CANCEL: return;
                  case Gtk::RESPONSE_OK:
                  default: break;
            }
      }

      Tag newTag = doc.vocabulary().obtainTag(tag);

      std::map< string, TagSet > sourceItems = activePanel().getSelection();
      PatchList<string, Tag> change;

      // Add `tag' to all selected items
      for (std::map< string, TagSet >::const_iterator i = sourceItems.begin();
                  i != sourceItems.end(); i++)
      {
            Patch<string, Tag> patch(i->first);
            patch.add(newTag);
            change.addPatch(patch);
      }

      doc.applyChange(change);
}

// vim:set ts=4 sw=4:

Generated by  Doxygen 1.6.0   Back to index