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

TagSelector.cc

/*
 * Tag list and selector widget
 *
 * Copyright (C) 2003  Enrico Zini <enrico@debian.org>
 *
 * 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 "TagSelector.h"
#include "TagMenu.h"

#include "Environment.h"

#include <gtkmm/eventbox.h>

using namespace std;
using namespace Tagcoll;

void TagSelector::do_changed()
{
      _signal_changed.emit();
}

void TagSelector::do_add_tag(Tag tag)
{
      _signal_add_tag.emit(tag);
}

void TagSelector::do_remove_tag(Tag tag)
{
      _signal_remove_tag.emit(tag);
}

bool TagSelector::on_titleAdd_event(GdkEvent* e)
{
      if (e->type == GDK_BUTTON_PRESS)
      {
            TagMenu<TagcollDocument<std::string> >* addMenu = manage(new TagMenu<TagcollDocument<std::string> >());
            addMenu->populateAvailable(doc, _selected);
            addMenu->signal_selected().connect(
                              sigc::mem_fun(*this, &TagSelector::on_add_to_selection));
            addMenu->popup(e->button.button, e->button.time);
            return true;
      }
      return false;
}

bool TagSelector::on_facetAdd_event(GdkEvent* e, Facet facet)
{
      if (e->type == GDK_BUTTON_PRESS)
      {
            TagMenu<TagcollDocument<std::string> >* addMenu = manage(new TagMenu<TagcollDocument<std::string> >());
            addMenu->populateAvailable(doc, _selected, facet);
            addMenu->signal_selected().connect(
                              sigc::mem_fun(*this, &TagSelector::on_add_to_selection));
            addMenu->popup(e->button.button, e->button.time);
            return true;
      }
      return false;
}

bool TagSelector::on_tag_popup_event(GdkEvent* e, Tag tag)
{
      if (e->type == GDK_BUTTON_PRESS && e->button.button == 3)
      {
            Gtk::Menu* itemPopup = manage(new Gtk::Menu());

            itemPopup->items().push_back(Gtk::Menu_Helpers::MenuElem(
                              "Add to all/selected items",
                              sigc::bind<Tag>(
                                    sigc::mem_fun(*this, &TagSelector::do_add_tag), tag)));
            itemPopup->items().push_back(Gtk::Menu_Helpers::MenuElem(
                              "Remove from all/selected items",
                              sigc::bind<Tag>(
                                    sigc::mem_fun(*this, &TagSelector::do_remove_tag), tag)));
                                          
            itemPopup->popup(e->button.button, e->button.time);
            return true;
      }
      return false;
}

void TagSelector::on_add_to_selection(Tag tag)
{
      //printf("Add to sel: %.*s\n", PFSTR(tag));
      unsigned int count_pre = _selected.size();
      _selected += tag;
      if (count_pre != _selected.size())
      {
            updateView();
            do_changed();
      }
}

void TagSelector::on_del_from_selection(Tag tag)
{
      //printf("Del from sel: %.*s\n", PFSTR(tag));
      unsigned int count_pre = _selected.size();
      _selected -= tag;
      if (count_pre != _selected.size())
      {
            updateView();
            do_changed();
      }
}

void TagSelector::on_document_changed()
{
      time_t start = time(NULL);
      TagSet allTags = doc.collection().getAllTags();
      _selected = _selected ^ allTags;
      updateView();
      time_t end = time(NULL);
      if (end != start)
            fprintf(stderr, "TagSelector::on_document_changed: %ld seconds\n", (end-start));
}

TagSelector::TagSelector(TagcollDocument<std::string>& doc)
      : doc(doc), table(0)
{
      //set_shadow_type(Gtk::SHADOW_NONE);

      updateView();

      pack_start(tableBox, false, true);
      pack_start(*manage(new Gtk::Label("")), true, true);
      /*
      Gtk::VBox* vbox = manage(new Gtk::VBox());
      vbox->pack_start(tableBox, false, true);
      vbox->pack_start(*manage(new Gtk::Label("CIPS")), true, true);
      add(*vbox);
      */

      //add(table);

      //Only show the scrollbars when they are necessary
      //set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

      /*
      // Create the Tree models
      selectedTagListModel = Gtk::ListStore::create(tagListModelColumns);
      availableTagListModel = Gtk::ListStore::create(tagListModelColumns);
      unavailableTagListModel = Gtk::ListStore::create(tagListModelColumns);

      selectedTagList.set_model(selectedTagListModel);
      availableTagList.set_model(availableTagListModel);
      unavailableTagList.set_model(unavailableTagListModel);
      */

      // Initially fill the available list with all tags
      /*
      Gtk::TreeModel::Row row;
      
      allTags = doc.collection().getAllTags();

      for (OpSet<string>::const_iterator i = allTags.begin(); i != allTags.end(); i++)
      {
            row = *(availableTagListModel->append());
            row[tagListModelColumns.tag] = *i;
      }

      // Add the view columns
      selectedTagList.append_column("Selected", tagListModelColumns.tag);
      availableTagList.append_column("Available", tagListModelColumns.tag);
      unavailableTagList.append_column("Unavailable", tagListModelColumns.tag);

      // Setup the lists as drag sources
      std::list<Gtk::TargetEntry> listTargets;
      listTargets.push_back(Gtk::TargetEntry("TAG"));
      listTargets.push_back(Gtk::TargetEntry("text/plain"));

      selectedTagList.drag_source_set(listTargets, Gdk::ModifierType(GDK_BUTTON1_MASK), Gdk::ACTION_COPY);
      availableTagList.drag_source_set(listTargets, Gdk::ModifierType(GDK_BUTTON1_MASK), Gdk::ACTION_COPY);
      unavailableTagList.drag_source_set(listTargets, Gdk::ModifierType(GDK_BUTTON1_MASK), Gdk::ACTION_COPY);
      */

      doc.signal_changed().connect(sigc::mem_fun(*this, &TagSelector::on_document_changed));
}

void TagSelector::on_selectedTagList_drag_data_get(
            const Glib::RefPtr<Gdk::DragContext>&, Gtk::SelectionData& selection_data, guint, guint, Tag tag)
{
      string stag = tag.fullname();
      selection_data.set(selection_data.get_target(), 8, (const guchar*)stag.data(), stag.size());
}

void TagSelector::updateView()
{
      time_t start = time(NULL);

      if (table)
      {
            tableBox.remove(*table);
            delete table;
      }
      //table.children().clear();

      // Create the facet/tag hierarchy
      int facets = 0, tags = 0;
      std::map<Facet, std::vector<Tag> > contents;
    for (TagSet::const_iterator i = _selected.begin(); i != _selected.end(); i++)
      {
            std::map<Facet, vector<Tag> >::iterator j = contents.find(i->facet());
            if (j != contents.end())
            {
                  j->second.push_back(*i);
                  tags++;
            }
            else
            {
                  std::vector<Tag> v;
                  v.push_back(*i);
                  contents.insert(pair<Facet, vector<Tag> >(i->facet(), v));
                  facets++;
                  tags++;
            }
      }

      // Resize the table to fit everything
      //printf("Resized: %dx%d\n", facets+tags+1, 4);
      //table.resize(facets + tags + 1, 4);
      table = new Gtk::Table(facets + tags + 1, 3);
      tableBox.pack_start(*table);

      // Setup the lists as drag sources
      std::list<Gtk::TargetEntry> listTargets;
      listTargets.push_back(Gtk::TargetEntry("TAG"));
      listTargets.push_back(Gtk::TargetEntry("text/plain"));

      // Add facets and tags
      int row = 0;
      for (std::map<Facet, std::vector<Tag> >::const_iterator i = contents.begin(); i != contents.end(); i++)
      {
            //printf("Add facet: %.*s\n", PFSTR(i->first));

            Gtk::Button* delFacet = manage(new Gtk::Button("-"));
            table->attach(*delFacet, 0, 1, row, row + 1, Gtk::SHRINK);

            Gtk::Label* facet = manage(new Gtk::Label(i->first.name().size() ? i->first.name() : "(legacy)", Gtk::ALIGN_LEFT));
            table->attach(*facet, 1, 2, row, row + 1);
            int px, py;
            facet->get_padding(px, py);
            facet->set_padding(4, py);

            Gtk::Button* addTag = manage(new Gtk::Button("+"));
            table->attach(*addTag, 2, 3, row, row + 1, Gtk::SHRINK);
            addTag->add_events(Gdk::BUTTON_PRESS_MASK);
            addTag->signal_event().connect(sigc::bind<Facet>(
                        sigc::mem_fun(*this, &TagSelector::on_facetAdd_event),
                        i->first));

            ++row;
            
            for (vector<Tag>::const_iterator j = i->second.begin(); j != i->second.end(); j++)
            {
                  //printf("Add tag: %.*s\n", PFSTR(*j));
                  //table->attach(*manage(new Gtk::Label("")), 0, 1, row, row+1, Gtk::SHRINK);

                  Gtk::Button* delTag = manage(new Gtk::Button("-"));
                  table->attach(*delTag, 0, 1, row, row + 1, Gtk::SHRINK);
                  delTag->signal_clicked().connect(sigc::bind<Tag>(
                                    sigc::mem_fun(*this, &TagSelector::on_del_from_selection),
                                    *j));

                  Gtk::Label* tag = manage(new Gtk::Label(j->name(), Gtk::ALIGN_LEFT));
                  int px, py;
                  tag->get_padding(px, py);
                  tag->set_padding(14, py);
                  Gtk::EventBox* ebox = manage(new Gtk::EventBox());
                  ebox->add(*tag);
                  ebox->add_events(Gdk::BUTTON_PRESS_MASK);
                  ebox->signal_event().connect(sigc::bind<Tag>(
                              sigc::mem_fun(*this, &TagSelector::on_tag_popup_event),
                              *j));
                  //ebox->drag_source_set(listTargets, Gdk::ModifierType(GDK_BUTTON1_MASK), Gdk::ACTION_COPY);
                  ebox->drag_source_set(listTargets);
                  ebox->signal_drag_data_get().connect(sigc::bind<Tag>(
                                    sigc::mem_fun(*this, &TagSelector::on_selectedTagList_drag_data_get),
                                    *j));

                  table->attach(*ebox, 1, 3, row, row + 1);
                  
                  ++row;
            }
      }

      // Create the title
      //Gtk::Label* title = manage(new Gtk::Label("Selected"));
      ////table->attach(*title, 0, 2, 0, 1);
      
      //Gtk::Button* titleAdd = manage(new Gtk::Button("+"));
      //table->attach(*titleAdd, 2, 3, 0, 1, Gtk::SHRINK);
      //titleAdd->add_events(Gdk::BUTTON_PRESS_MASK);
      //titleAdd->signal_event().connect(SigC::slot(*this, &TagSelector::on_titleAdd_event));
      //titleAdd->signal_clicked().connect(
                  //SigC::slot(*this, &TagcollEditor::on_titleAdd_clicked));

      Gtk::Button* titleAdd = manage(new Gtk::Button("Add"));
      table->attach(*titleAdd, 0, 3, row, row+1, Gtk::SHRINK);
      titleAdd->add_events(Gdk::BUTTON_PRESS_MASK);
      titleAdd->signal_event().connect(sigc::mem_fun(*this, &TagSelector::on_titleAdd_event));

      table->show();
      table->show_all_children(true);

/*
      

      
      OpSet<string> companions = doc.collection().getCompanionTags(_selected);
      OpSet<string> unavl = allTags - _selected - companions;

      Gtk::TreeModel::Row row;

      selectedTagListModel->clear();
      for (OpSet<string>::const_iterator i = _selected.begin(); i != _selected.end(); i++)
      {
            // Selected tags remain unfiltered, to avoid loosing the operating context
            //if (filter.empty() || i->find(filter) != string::npos)
            //{
                  row = *(selectedTagListModel->append());
                  row[tagListModelColumns.tag] = *i;
            //}
      }

      availableTagListModel->clear();
      for (OpSet<string>::const_iterator i = companions.begin(); i != companions.end(); i++)
      {
            if (filter.empty() || i->find(filter) != string::npos)
            {
                  row = *(availableTagListModel->append());
                  row[tagListModelColumns.tag] = *i;
            }
      }

      unavailableTagListModel->clear();
      for (OpSet<string>::const_iterator i = unavl.begin(); i != unavl.end(); i++)
      {
            if (filter.empty() || i->find(filter) != string::npos)
            {
                  row = *(unavailableTagListModel->append());
                  row[tagListModelColumns.tag] = *i;
            }
      }
*/

      time_t end = time(NULL);
      if (end != start)
            fprintf(stderr, "TagSelector::updateList: %ld seconds\n", (end-start));
}

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

Generated by  Doxygen 1.6.0   Back to index