# This Python file uses the following encoding: utf-8
#
#  Author: Roman 'gryf' Dobosz  gryf@elysium.pl
#
#  Copyright (C) 2007 by Roman 'gryf' Dobosz
#
#  This file is part of pyGTKtalog.
#
#  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

#  -------------------------------------------------------------------------

LICENCE = open('LICENCE').read()

import os.path
from os import popen
import gtk
import pango

from gtkmvc import Controller

from lib import device_helper
from lib.globs import APPL_VERSION
from c_config import ConfigController
from views.v_config import ConfigView
from c_search import SearchController
from views.v_search import SearchView
import views.v_dialogs as Dialogs
from views.v_image import ImageView



class MainController(Controller):
    """Controller for main application window"""
    scan_cd = False
    widgets_all = ('tag_path_box', 'hpaned1',
                       'file1', 'edit1', 'view1', 'help1',
                           'add_cd', 'add_directory1', 'del_all_images',
                           'del_all_thumb', 'stat1',
                       'tb_new','tb_open', 'tb_save', 'tb_addcd', 'tb_adddir',
                       'tb_find', 'tb_quit')
    widgets_cancel = ('cancel','cancel1')

    def __init__(self, model):
        """Initialize controller"""
        self.DND_TARGETS = [('files_tags', 0, 69)]
        Controller.__init__(self, model)
        self.hovering = False
        self.first = True
        return

    def register_view(self, view):
        Controller.register_view(self, view)

        # Make not active "Cancel" button and menu_item
        for widget in self.widgets_cancel:
            self.view[widget].set_sensitive(False)

        # hide "debug" button, if production
        # (i.e. python OT running with -OO option)
        if __debug__:
            self.view['debugbtn'].show()
        else:
            self.view['debugbtn'].hide()

        # load configuration/defaults and set it to properties
        bo = self.model.config.confd['showtoolbar']
        self.view['toolbar1'].set_active(bo)
        if bo:
            self.view['maintoolbar'].show()
        else:
            self.view['maintoolbar'].hide()
        statusbar_state = self.model.config.confd['showstatusbar']
        self.view['status_bar1'].set_active(statusbar_state)
        if self.model.config.confd['showstatusbar']:
            self.view['statusprogress'].show()
        else:
            self.view['statusprogress'].hide()
        self.view['hpaned1'].set_position(self.model.config.confd['h'])
        self.view['vpaned1'].set_position(self.model.config.confd['v'])
        self.view['main'].resize(self.model.config.confd['wx'],
                                 self.model.config.confd['wy'])

        # initialize statusbar
        context = self.view['mainStatus'].get_context_id('detailed res')
        self.context_id = context
        self.statusbar_id = self.view['mainStatus'].push(self.context_id,
                                                         "Idle")

        # make tag_cloud_textview recive dnd signals
        self.view['tag_cloud_textview'].drag_dest_set(gtk.DEST_DEFAULT_ALL,
                          self.DND_TARGETS,
                          gtk.gdk.ACTION_COPY)

        # initialize treeviews
        self.__setup_disc_treeview()
        self.__setup_files_treeview()
        self.__setup_exif_treeview()

        # in case passing catalog filename in command line, unlock gui
        if self.model.filename:
            self.__activate_ui(self.model.filename)

        # generate recent menu
        self.__generate_recent_menu()

        self.view['tag_cloud_textview'].connect("populate-popup",
                                           self.on_tag_cloud_textview_popup)
        # in case model has opened file, register tags
        if self.model.db_tmp_path:
            self.__tag_cloud()
        else:
            self.model.new()
            #self.__activate_ui()

        # Show main window
        self.view['main'].show();
        self.view['main'].drag_dest_set(0, [], 0)
        return

    #########################################################################
    # Connect signals from GUI, like menu objects, toolbar buttons and so on.
    def on_tag_cloud_textview_drag_drop(self, wid, context, x, y, time):
        context.finish(True, False, time)
        return True

    def on_tag_cloud_textview_drag_motion(self, filestv, context, x, y, time):
        context.drag_status(gtk.gdk.ACTION_COPY, time)
        iter = filestv.get_iter_at_location(x, y)
        buff = filestv.get_buffer()
        tag_table = buff.get_tag_table()

        # clear weight of tags
        def foreach_tag(texttag, user_data):
            """set every text tag's weight to normal"""
            texttag.set_property("underline", pango.UNDERLINE_NONE)
        tag_table.foreach(foreach_tag, None)

        try:
            tag = iter.get_tags()[0]
            tag.set_property("underline", pango.UNDERLINE_LOW)
        except:
            pass
        return True

    def on_files_drag_data_get(self, treeview, context, selection,
                               targetType, eventTime):
        """responce to "data get" DnD signal"""
        # get selection, and send it to the client
        if targetType == self.DND_TARGETS[0][2]:
            # get selection
            treesrl = treeview.get_selection()
            model, list_of_paths = treesrl.get_selected_rows()
            ids = []
            for path in list_of_paths:
                id = model.get_value(model.get_iter(path), 0)
                ids.append(id)
            string = str(tuple(ids)).replace(",)", ")")
            selection.set(selection.target, 8, string)

    def on_tag_cloud_textview_popup(self, textview, menu):
        menu = None
        return True

    def on_tag_cloud_textview_event_after(self, textview, event):
        """check, if and what tag user clicked. generate apropriate output
        in files treview"""
        if event.type != gtk.gdk.BUTTON_RELEASE:
            return False
        if event.button != 1:
            return False

        buff = textview.get_buffer()
        try:
            (start, end) = buff.get_selection_bounds()
        except ValueError:
            pass
        else:
            if start.get_offset() != end.get_offset():
                return False

        # get the iter at the mouse position
        (x, y) = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
                                              int(event.x), int(event.y))
        iterator = textview.get_iter_at_location(x, y)

        tags = iterator.get_tags()

        if len(tags) == 1:
            tag = tags[0]
            self.model.add_tag_to_path(tag.get_property('name'))
            self.view['tag_path_box'].show()

            # fill the path of tag
            self.view['tag_path'].set_text('')
            temp = self.model.selected_tags.values()
            self.model.refresh_discs_tree()
            #self.on_discs_cursor_changed(textview)

            temp.sort()
            for tag1 in temp:
                txt = self.view['tag_path'].get_text()
                if txt == '':
                    self.view['tag_path'].set_text(tag1)
                else:
                    self.view['tag_path'].set_text(txt + ", " +tag1)
            self.__tag_cloud()
        self.model.get_root_entries()
        self.__set_files_hiden_columns_visible(True)
        self.view['files'].set_model(self.model.files_list)
        self.__hide_details()

    def on_tag_cloud_textview_drag_data_received(self, widget, context, x, y,
                                                 selection, targetType, time):
        """recive data from source TreeView"""
        if targetType == self.DND_TARGETS[0][2]:
            iter = widget.get_iter_at_location(x, y)
            ids = selection.data.rstrip(")").lstrip("(").split(",")
            try:
                tag = iter.get_tags()[0]
                for id in ids:
                    it = int(tag.get_property('name'))
                    tn = self.model.get_tag_by_id(it)
                    self.model.add_tags(int(id.strip()), tn)
            except:
                if selection.data:
                    tags = Dialogs.TagsDialog().run()
                    if not tags:
                        return
                    for id in ids:
                        self.model.add_tags(int(id.strip()), tags)

        self.__tag_cloud()

    def on_edit2_activate(self, menu_item):
        try:
            selection = self.view['files'].get_selection()
            model, list_of_paths = selection.get_selected_rows()
            id = model.get_value(model.get_iter(list_of_paths[0]), 0)
        except TypeError:
            if __debug__:
                print "c_main.py: on_edit2_activate(): 0",
                print "selected rows"
            return

        val = self.model.get_file_info(id)
        ret = Dialogs.EditDialog(val).run()
        if ret:
            self.model.rename(id, ret['filename'])
            self.model.update_desc_and_note(id,
                                            ret['description'], ret['note'])
            self.__get_item_info(id)
            self.model.unsaved_project = True
            self.__set_title(filepath=self.model.filename, modified=True)

    def on_add_thumb1_activate(self, menu_item):
        image, only_thumbs = Dialogs.LoadImageFile().run()
        if not image:
            return
        selection = self.view['files'].get_selection()
        model, list_of_paths = selection.get_selected_rows()
        for path in list_of_paths:
            id = model.get_value(model.get_iter(path), 0)
            self.model.add_thumbnail(image, id)
        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        self.__get_item_info(id)
        return

    def on_remove_thumb1_activate(self, menu_item):
        if self.model.config.confd['delwarn']:
            obj = Dialogs.Qst(_("Delete thumbnails"), _("Delete thumbnails?"),
                              _("Thumbnails for selected items will be "
                                "permanently removed from catalog."))
            if not obj.run():
                return
        try:
            selection = self.view['files'].get_selection()
            model, list_of_paths = selection.get_selected_rows()
            for path in list_of_paths:
                id = model.get_value(model.get_iter(path), 0)
                self.model.del_thumbnail(id)
        except:
            if __debug__:
                print "c_main.py: on_remove_thumb1_activate(): error on",
                print "getting selected items or removing thumbnails"
            return

        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        self.__get_item_info(id)
        return

    def on_remove_image1_activate(self, menu_item):
        if self.model.config.confd['delwarn']:
            obj = Dialogs.Qst(_("Delete images"), _("Delete all images?"),
                              _("All images for selected items will be "
                                "permanently removed from catalog."))
            if not obj.run():
                return
        try:
            selection = self.view['files'].get_selection()
            model, list_of_paths = selection.get_selected_rows()
            for path in list_of_paths:
                id = model.get_value(model.get_iter(path), 0)
                self.model.del_images(id)
        except:
            if __debug__:
                print "c_main.py: on_remove_thumb1_activate(): error on",
                print "getting selected items or removing thumbnails"
            return

        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        self.__get_item_info(id)
        return

    def on_images_item_activated(self, iconview, path):
        model = iconview.get_model()
        iter = model.get_iter(path)
        id = model.get_value(iter, 0)
        img = self.model.get_image_path(id)
        if img:
            if self.model.config.confd['imgview'] and \
            len(self.model.config.confd['imgprog'])>0:
                popen("%s %s" % (self.model.config.confd['imgprog'], img))
            else:
                ImageView(img)
        else:
            Dialogs.Inf(_("Image view"), _("No Image"),
                        _("Image file does not exist."))

    def on_rename1_activate(self, widget):
        model, iter = self.view['discs'].get_selection().get_selected()
        name = model.get_value(iter, 1)
        id = model.get_value(iter, 0)
        new_name = Dialogs.InputNewName(name).run()

        if __debug__:
            print "c_main.py: on_rename1_activate(): label:", new_name

        if new_name and new_name != name:
            self.model.rename(id, new_name)
            self.model.unsaved_project = True
            self.__set_title(filepath=self.model.filename, modified=True)
        return True

    def on_rename2_activate(self, widget):
        try:
            selection = self.view['files'].get_selection()
            model, list_of_paths = selection.get_selected_rows()
        except TypeError:
            return

        if len(list_of_paths) != 1:
            return

        fid = model.get_value(model.get_iter(list_of_paths[0]), 0)
        name = model.get_value(model.get_iter(list_of_paths[0]),1)

        new_name = Dialogs.InputNewName(name).run()
        if __debug__:
            print "c_main.py: on_rename1_activate(): label:", new_name

        if new_name and new_name != name:
            self.model.rename(fid, new_name)
            self.__get_item_info(fid)
            self.__set_title(filepath=self.model.filename, modified=True)

        #try:
        #    path, column = self.view['discs'].get_cursor()
        #    iter = model.get_iter(path)
        #    self.model.get_root_entries(model.get_value(iter, 0))
        #except TypeError:
        #    self.model.get_root_entries(1)
        #    return

        return

    def on_tag_cloud_textview_motion_notify_event(self, widget):
        if __debug__:
            print "c_main.py: on_tag_cloud_textview_motion_notify_event():"
        w = self.view['tag_cloud_textview'].get_window(gtk.TEXT_WINDOW_TEXT)
        if w:
            w.set_cursor(None)

    def on_clear_clicked(self, w):
        self.view['tag_path_box'].hide()
        self.model.selected_tags = []
        self.model.refresh_discs_tree()
        self.__set_files_hiden_columns_visible(False)

        # cleanup files and detiles
        try:
            self.model.files_list.clear()
        except:
            pass
        self.__hide_details()
        self.on_discs_cursor_changed(w)
        self.__tag_cloud()

    def on_tag_cloud_textview_drag_leave(self, textview, dragcontext, time):
        """clean up tags properties"""
        buff = textview.get_buffer()
        tag_table = buff.get_tag_table()

        # clear weight of tags
        def foreach_tag(texttag, user_data):
            """set every text tag's weight to normal"""
            texttag.set_property("underline", pango.UNDERLINE_NONE)
        tag_table.foreach(foreach_tag, None)

    # NOTE: text view "links" functions
    def on_tag_cloud_textview_visibility_notify_event(self, textview, event):
        (wx, wy, mod) = textview.window.get_pointer()
        (bx, by) = textview.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET,
                                                     wx, wy)
        self.check_hovering(bx, by)
        return False

    def check_hovering(self, x, y):
        """Check if the mouse is above a tagged link and if yes show
           a hand cursor"""
        _hovering = False
        textview = self.view['tag_cloud_textview']
        # get the iter at the mouse position
        iter = textview.get_iter_at_location(x, y)

        # set _hovering if the iter has the tag "url"
        tags = iter.get_tags()
        for tag in tags:
            _hovering = True
            break

        # change the global hovering state
        if _hovering != self.hovering or self.first == True:
            self.first = False
            self.hovering = _hovering
            # Set the appropriate cursur icon
            if self.hovering:
                textview.get_window(gtk.TEXT_WINDOW_TEXT).\
                        set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
            else:
                textview.get_window(gtk.TEXT_WINDOW_TEXT).\
                        set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))

    def on_tag_cloud_click(self, tag, textview, event, b_iter, data):
        """react on click on connected tag items"""
        tag_cloud = self.view['tag_cloud_textview']
        if event.type == gtk.gdk.BUTTON_RELEASE:
            self.model.add_tag_to_path(tag.get_property('name'))
            self.view['tag_path_box'].show()

            # fill the path of tag
            self.view['tag_path'].set_text('')
            temp = self.model.selected_tags.values()
            self.model.refresh_discs_tree()
            #self.on_discs_cursor_changed(textview)

            temp.sort()
            for tag1 in temp:
                txt = self.view['tag_path'].get_text()
                if txt == '':
                    self.view['tag_path'].set_text(tag1)
                else:
                    self.view['tag_path'].set_text(txt + ", " +tag1)
            self.__tag_cloud()

    def on_main_destroy_event(self, window, event):
        """NOTE: quit / close window signal"""
        self.on_quit_activate(window)
        return True

    def on_quit_activate(self, widget):
        """Quit and save window parameters to config file"""
        # check if any unsaved project is on go.
        if self.model.unsaved_project and \
        self.model.config.confd['confirmquit']:
            if not Dialogs.Qst(_("Quit application") + " - pyGTKtalog",
                               _("Do you really want to quit?"),
                               _("Current database is not saved, any changes "
                                 "will be lost.")).run():
                return
        self.__store_settings()
        self.model.cleanup()
        gtk.main_quit()
        return False

    def on_new_activate(self, widget):
        """Create new database file"""
        if self.model.unsaved_project:
            if not Dialogs.Qst(_("Unsaved data") + " - pyGTKtalog",
                               _("Do you want to abandon changes?"),
                               _("Current database is not saved, any changes "
                                 "will be lost.")).run():
                return
        self.model.new()

        # cleanup files and details
        try:
            self.model.files_list.clear()
        except:
            pass
        self.__hide_details()
        self.view['tag_path_box'].hide()
        self.__activate_ui()
        self.__tag_cloud()

    def on_add_cd_activate(self, widget, label=None, current_id=None):
        """Add directory structure from cd/dvd disc"""
        mount, msg = device_helper.volmount(self.model.config.confd['cd'])
        if mount:
            guessed_label = device_helper.volname(self.model.config.confd['cd'])
            if not label:
                label = Dialogs.InputDiskLabel(guessed_label).run()
            if label:
                self.scan_cd = True
                for widget in self.widgets_all:
                    self.view[widget].set_sensitive(False)
                self.model.source = self.model.CD
                self.model.scan(self.model.config.confd['cd'], label,
                                current_id)
                self.model.unsaved_project = True
                self.__set_title(filepath=self.model.filename, modified=True)
            else:
                device_helper.volumount(self.model.config.confd['cd'])
            return True
        else:
            Dialogs.Wrn(_("Error mounting device") + " - pyGTKtalog",
                        _("Cannot mount device pointed to %s") %
                        self.model.config.confd['cd'],
                        _("Last mount message:\n%s") % msg)
            return False

    def on_add_directory_activate(self, widget, path=None, label=None,
                                   current_id=None):
        """Show dialog for choose drectory to add from filesystem."""
        if not label or not path:
            res = Dialogs.PointDirectoryToAdd().run()
            if res != (None, None):
                path = res[1]
                label = res[0]
            else:
                return False

        self.scan_cd = False
        self.model.source = self.model.DR
        self.model.scan(path, label, current_id)
        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        return

    # NOTE: about
    def on_about1_activate(self, widget):
        """Show about dialog"""
        Dialogs.Abt("pyGTKtalog", "%d.%d.%d" % APPL_VERSION, "About",
                    ["Roman 'gryf' Dobosz"], LICENCE)
        return

    def on_preferences_activate(self, widget):
        c = ConfigController(self.model.config)
        v = ConfigView(c)
        return

    def on_status_bar1_activate(self, widget):
        """Toggle visibility of statusbat and progress bar."""
        activity = self.view['status_bar1'].get_active()
        self.model.config.confd['showstatusbar'] = activity
        if self.view['status_bar1'].get_active():
            self.view['statusprogress'].show()
        else:
            self.view['statusprogress'].hide()

    def on_toolbar1_activate(self, widget):
        """Toggle visibility of toolbar bar."""
        activity = self.view['toolbar1'].get_active()
        self.model.config.confd['showtoolbar'] = activity
        if self.view['toolbar1'].get_active():
            self.view['maintoolbar'].show()
        else:
            self.view['maintoolbar'].hide()

    def on_save_activate(self, widget):
        """Save catalog to file"""
        # FIXME: Traceback when recent is null
        if self.model.filename:
            self.model.save()
            self.__set_title(filepath=self.model.filename)
        else:
            self.on_save_as_activate(widget)

    def on_save_as_activate(self, widget):
        """Save database to file under different filename."""
        initial_path = None
        if self.model.config.recent[0]:
            initial_path = os.path.dirname(self.model.config.recent[0])

        path = Dialogs.ChooseDBFilename(initial_path).run()
        if path:
            ret, err = self.model.save(path)
            if ret:
                self.model.config.add_recent(path)
                self.__set_title(filepath=path)
            else:
                Dialogs.Err(_("Error writing file") + " - pyGTKtalog",
                            _("Cannot write file %s.") % path, "%s" % err)

    def on_stat1_activate(self, menu_item, selected_id=None):
        data = self.model.get_stats(selected_id)
        label = Dialogs.StatsDialog(data).run()

    def on_statistics1_activate(self, menu_item):
        model = self.view['discs'].get_model()
        try:
            path, column = self.view['discs'].get_cursor()
            selected_iter = self.model.discs_tree.get_iter(path)
        except:
            return

        selected_id = self.model.discs_tree.get_value(selected_iter, 0)
        self.on_stat1_activate(menu_item, selected_id)

    def on_open_activate(self, widget, path=None):
        """Open catalog file"""
        confirm = self.model.config.confd['confirmabandon']
        if self.model.unsaved_project and confirm:
            obj = Dialogs.Qst(_("Unsaved data") + " - pyGTKtalog",
                              _("There is not saved database"),
                              _("Pressing <b>Ok</b> will abandon catalog."))
            if not obj.run():
                return

        initial_path = None
        if self.model.config.recent and self.model.config.recent[0]:
            initial_path = os.path.dirname(self.model.config.recent[0])

        if not path:
            path = Dialogs.LoadDBFile(initial_path).run()

        # cleanup files and details
        try:
            self.model.files_list.clear()
        except:
            pass
        self.__hide_details()
        self.view['tag_path_box'].hide()
        buf = self.view['tag_cloud_textview'].get_buffer()
        buf.set_text('')
        self.view['tag_cloud_textview'].set_buffer(buf)

        if path:
            if not self.model.open(path):
                Dialogs.Err(_("Error opening file") + " - pyGTKtalog",
                            _("Cannot open file %s.") % path)
            else:
                self.__generate_recent_menu()
                self.__activate_ui(path)
                self.__tag_cloud()
        return

    def on_discs_cursor_changed(self, widget):
        """Show files on right treeview, after clicking the left disc
        treeview."""
        model = self.view['discs'].get_model()
        path, column = self.view['discs'].get_cursor()
        if path:
            iter = self.model.discs_tree.get_iter(path)
            id = self.model.discs_tree.get_value(iter, 0)
            self.__set_files_hiden_columns_visible(False)
            self.model.get_root_entries(id)
            self.__get_item_info(id)

        return

    def on_discs_row_activated(self, treeview, path, treecolumn):
        """If possible, expand or collapse branch of discs tree"""
        if treeview.row_expanded(path):
            treeview.collapse_row(path)
        else:
            treeview.expand_row(path, False)
        return

    def on_discs_key_release_event(self, treeview, event):
        if gtk.gdk.keyval_name(event.keyval) == 'Menu':
            ids = self.__get_tv_selection_ids(treeview)
            menu_items = ['update1','rename1','delete2', 'statistics1']
            for menu_item in menu_items:
                self.view[menu_item].set_sensitive(not not ids)
            self.__popup_menu(event, 'discs_popup')
            return True
        return False

    def on_images_key_release_event(self, iconview, event):
        if gtk.gdk.keyval_name(event.keyval) == 'Menu':
            self.__popup_menu(event, 'img_popup')
            return True
        return False

    def on_images_button_press_event(self, iconview, event):
        #try:
        #    path_and_cell = iconview.get_item_at_pos(int(event.x),
        #                                             int(event.y))
        #except TypeError:
        #    return False

        if event.button == 3: # Right mouse button. Show context menu.
            #try:
            #    iconview.select_path(path_and_cell[0])
            #except TypeError:
            #    return False

            self.__popup_menu(event, 'img_popup')
            return True
        return False

    def on_img_delete_activate(self, menu_item):
        """delete selected images (with thumbnails)"""
        list_of_paths = self.view['images'].get_selected_items()
        if not list_of_paths:
            Dialogs.Inf(_("Delete images"), _("No images selected"),
                        _("You have to select at least one image to delete."))
            return

        if self.model.config.confd['delwarn']:
            obj = Dialogs.Qst(_("Delete images"), _("Delete selected images?"),
                              _("Selected images will be permanently removed"
                                " from catalog."))
            if not obj.run():
                return

        model = self.view['images'].get_model()
        ids = []
        for path in list_of_paths:
            iterator = model.get_iter(path)
            ids.append(model.get_value(iterator, 0))

        for fid in ids:
            self.model.delete_image(fid)

        # refresh files tree
        try:
            path, column = self.view['files'].get_cursor()
            model = self.view['files'].get_model()
            iterator = model.get_iter(path)
            fid = model.get_value(iterator, 0)
            self.__get_item_info(fid)
        except:
            pass

        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        return

    def on_img_save_activate(self, menu_item):
        """export images (not thumbnails) into desired direcotry"""
        dialog = Dialogs.SelectDirectory(_("Choose directory to save images"))
        filepath = dialog.run()

        if not filepath:
            return

        list_of_paths = self.view['images'].get_selected_items()
        model = self.view['images'].get_model()

        count = 0

        if len(list_of_paths) == 0:
            # no picture was selected. default to save all of them
            for image in model:
                if self.model.save_image(image[0], filepath):
                    count += 1
        else:
            # some pictures was selected, save them
            for path in list_of_paths:
                icon_iter = model.get_iter(path)
                img_id = model.get_value(icon_iter, 0)
                if self.model.save_image(img_id, filepath):
                    count += 1

        if count > 0:
            Dialogs.Inf(_("Save images"),
                        _("%d images was succsefully saved.") % count,
                        _("Images are placed in directory:\n%s.") % filepath)
        else:
            description = _("Images probably don't have real images - only"
                            " thumbnails.")
            Dialogs.Inf(_("Save images"), _("No images was saved."),
                        description)
        return

    def on_img_thumbset_activate(self, menu_item):
        """set selected image as thumbnail"""
        list_of_paths = self.view['images'].get_selected_items()

        if not list_of_paths:
            Dialogs.Inf(_("Set thumbnail"), _("No image selected"),
                        _("You have to select one image to set as thumbnail."))
            return
        if len(list_of_paths) >1:
            Dialogs.Inf(_("Set thumbnail"), _("To many images selected"),
                        _("You have to select one image to set as thumbnail."))
            return

        model = self.view['images'].get_model()
        iter = model.get_iter(list_of_paths[0])
        id = model.get_value(iter, 0)
        self.model.set_image_as_thumbnail(id)

        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        return

    def on_img_add_activate(self, menu_item):
        self.on_add_image1_activate(menu_item)

    def on_thumb_box_button_press_event(self, widget, event):
        if event.button == 3:
            self.__popup_menu(event, 'th_popup')

    def on_discs_button_press_event(self, treeview, event):
        try:
            path, column, x, y = treeview.get_path_at_pos(int(event.x),
                                                          int(event.y))
        except TypeError:
            treeview.get_selection().unselect_all()
            return False

        if event.button == 3:
            """Right mouse button. Show context menu."""
            try:
                selection = treeview.get_selection()
                model, list_of_paths = selection.get_selected_rows()
            except TypeError:
                list_of_paths = []

            if path not in list_of_paths:
                treeview.get_selection().unselect_all()
                treeview.get_selection().select_path(path)
            # setup menu
            ids = self.__get_tv_selection_ids(treeview)
            menu_items = ['update1','rename1','delete2', 'statistics1']
            for menu_item in menu_items:
                self.view[menu_item].set_sensitive(not not ids)

            # checkout, if we dealing with disc or directory
            # if ancestor is 'root', then activate "update" menu item
            treeiter = self.model.discs_tree.get_iter(path)
            ancestor = self.model.discs_tree.get_value(treeiter, 3) == 1
            self.view['update1'].set_sensitive(ancestor)

            self.__popup_menu(event)

    def on_expand_all1_activate(self, menu_item):
        self.view['discs'].expand_all()
        return
        
    def on_export_activate(self, menu_item):
        """export db file and coressponding images to tar.bz2 archive"""
        dialog = Dialogs.ChooseFilename(None, _("Choose export file"))
        filepath = dialog.run()

        if not filepath:
            return

        # TODO: dokończyć ten shit

    def on_collapse_all1_activate(self, menu_item):
        self.view['discs'].collapse_all()
        return

    def on_files_button_press_event(self, tree, event):
        if event.button == 3: # Right mouse button. Show context menu.
            try:
                selection = tree.get_selection()
                model, list_of_paths = selection.get_selected_rows()
            except TypeError:
                list_of_paths = []

            if len(list_of_paths) == 0:
                # try to select item under cursor
                try:
                    path, column, x, y = tree.get_path_at_pos(int(event.x),
                                                              int(event.y))
                except TypeError:
                    # failed, do not show any popup and return
                    tree.get_selection().unselect_all()
                    return False
                selection.select_path(path[0])

            if len(list_of_paths) > 1:
                self.view['add_image1'].set_sensitive(False)
                self.view['rename2'].set_sensitive(False)
                self.view['edit2'].set_sensitive(False)
            else:
                self.view['add_image1'].set_sensitive(True)
                self.view['rename2'].set_sensitive(True)
                self.view['edit2'].set_sensitive(True)
            self.__popup_menu(event, 'files_popup')
            return True

    def on_files_cursor_changed(self, treeview):
        """Show details of selected file/directory"""
        file_id = self.__get_tv_id_under_cursor(treeview)
        self.__get_item_info(file_id)
        return

    def on_files_key_release_event(self, treeview, event):
        """do something with pressed keys"""
        if gtk.gdk.keyval_name(event.keyval) == 'Menu':
            try:
                selection = treeview.get_selection()
                model, list_of_paths = selection.get_selected_rows()
                if not list_of_paths:
                    return
            except TypeError:
                return
            self.__popup_menu(event, 'files_popup')

        if gtk.gdk.keyval_name(event.keyval) == 'BackSpace':
            d_path, d_column = self.view['discs'].get_cursor()
            if d_path and d_column:
                # easy way
                model = self.view['discs'].get_model()
                child_iter = model.get_iter(d_path)
                parent_iter = model.iter_parent(child_iter)
                if parent_iter:
                    self.view['discs'].set_cursor(model.get_path(parent_iter))
                else:
                    # hard way
                    f_model = treeview.get_model()
                    first_iter = f_model.get_iter_first()
                    first_child_value = f_model.get_value(first_iter, 0)
                    # get two steps up
                    val = self.model.get_parent_id(first_child_value)
                    parent_value = self.model.get_parent_id(val)
                    iter = self.model.discs_tree.get_iter_first()
                    while iter:
                        current_value = self.model.discs_tree.get_value(iter,
                                                                        0)
                        if current_value == parent_value:
                            path = self.model.discs_tree.get_path(iter)
                            self.view['discs'].set_cursor(path)
                            iter = None
                        else:
                            iter = self.model.discs_tree.iter_next(iter)
        #if gtk.gdk.keyval_name(event.keyval) == 'Delete':
        #    for file_id in  self.__get_tv_selection_ids(treeview):
        #        self.main.delete(file_id)

        ids = self.__get_tv_selection_ids(self.view['files'])

    def on_files_row_activated(self, files_obj, row, column):
        """On directory doubleclick in files listview dive into desired
        branch."""
        f_iter = self.model.files_list.get_iter(row)
        current_id = self.model.files_list.get_value(f_iter, 0)

        if self.model.files_list.get_value(f_iter, 6) == 1:
            # ONLY directories. files are omitted.
            self.__set_files_hiden_columns_visible(False)
            self.model.get_root_entries(current_id)

            d_path, d_column = self.view['discs'].get_cursor()
            if d_path:
                if not self.view['discs'].row_expanded(d_path):
                    self.view['discs'].expand_row(d_path, False)

                discs_model = self.model.discs_tree
                iterator = discs_model.get_iter(d_path)
                new_iter = discs_model.iter_children(iterator)
                if new_iter:
                    while new_iter:
                        current_value = discs_model.get_value(new_iter, 0)
                        if current_value == current_id:
                            path = discs_model.get_path(new_iter)
                            self.view['discs'].set_cursor(path)
                        new_iter = discs_model.iter_next(new_iter)
        return

    def on_cancel_clicked(self, widget):
        """When scanning thread is runing and user push the cancel button,
        models abort attribute trigger cancelation for scan operation"""
        self.model.abort = True
        return

    def on_find_activate(self, widget):
        """search button/menu activated. Show search window"""
        if not self.model.search_created:
            c = SearchController(self.model)
            v = SearchView(c)
        return

    # NOTE: recent signal
    def recent_item_response(self, path):
        self.on_open_activate(self, path)
        return

    # NOTE: add tags / images
    def on_delete_tag2_activate(self, menu_item):
        pass

    def on_delete_tag_activate(self, menu_item):
        ids = self.__get_tv_selection_ids(self.view['files'])
        if not ids:
            Dialogs.Inf(_("Remove tags"), _("No files selected"),
                        _("You have to select some files first."))
            return

        tags = self.model.get_tags_by_file_id(ids)
        if tags:
            d = Dialogs.TagsRemoveDialog(tags)
            retcode, retval = d.run()
            if retcode=="ok" and not retval:
                Dialogs.Inf(_("Remove tags"), _("No tags selected"),
                            _("You have to select any tag to remove from"
                              " files."))
                return
            elif retcode == "ok" and retval:
                self.model.delete_tags(ids, retval)
                self.model.get_root_entries()
                self.view['files'].set_model(self.model.files_list)
                self.__tag_cloud()
        return

    def on_add_tag1_activate(self, menu_item):
        tags = Dialogs.TagsDialog().run()
        if not tags:
            return
        ids = self.__get_tv_selection_ids(self.view['files'])
        for id in ids:
            self.model.add_tags(id, tags)

        self.__tag_cloud()
        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        self.__get_item_info(id)
        return

    def on_add_image1_activate(self, menu_item):
        dialog = Dialogs.LoadImageFile(True)
        msg = _("Don't copy images. Generate only thumbnails.")
        toggle = gtk.CheckButton(msg)
        toggle.show()
        dialog.dialog.set_extra_widget(toggle)

        images, only_thumbs = dialog.run()
        if not images:
            return

        for image in images:
            try:
                selection = self.view['files'].get_selection()
                model, list_of_paths = selection.get_selected_rows()
                id = model.get_value(model.get_iter(list_of_paths[0]), 0)
            except:
                try:
                    path, column = self.view['files'].get_cursor()
                    model = self.view['files'].get_model()
                    iter = model.get_iter(path)
                    id = model.get_value(iter, 0)
                except:
                    return
            self.model.add_image(image, id, only_thumbs)

            self.model.unsaved_project = True
            self.__set_title(filepath=self.model.filename, modified=True)

        self.__get_item_info(id)
        return

    def on_update1_activate(self, menu_item):
        """Update disc under cursor position"""
        path, column = self.view['discs'].get_cursor()
        model = self.view['discs'].get_model()

        # determine origin label and filepath
        filepath, label = self.model.get_label_and_filepath(path)

        fid = model.get_value(model.get_iter(path), 0)

        if self.model.get_source(path) == self.model.CD:
            self.on_add_cd_activate(menu_item, label, fid)
        elif self.model.get_source(path) == self.model.DR:
            self.on_add_directory_activate(menu_item, filepath, label, fid)

        return

    def on_delete1_activate(self, menu_item):
        """Main menu delete dispatcher"""
        if self.view['files'].is_focus():
            self.on_delete3_activate(menu_item)
        if self.view['discs'].is_focus():
            self.on_delete2_activate(menu_item)
        if self.view['images'].is_focus():
            self.on_img_delete_activate(menu_item)

    def on_delete2_activate(self, menu_item):
        try:
            selection = self.view['discs'].get_selection()
            model, selected_iter = selection.get_selected()
        except:
            return

        if not selected_iter:
            Dialogs.Inf(_("Delete disc"), _("No disc selected"),
                        _("You have to select disc first before you "
                          "can delete it"))
            return

        if self.model.config.confd['delwarn']:
            name = model.get_value(selected_iter, 1)
            obj = Dialogs.Qst(_("Delete %s") % name, _("Delete %s?") % name,
                              _("Object will be permanently removed."))
            if not obj.run():
                return

        # remove from model
        path = model.get_path(selected_iter)
        fid = self.model.discs_tree.get_value(selected_iter, 0)
        model.remove(selected_iter)
        selection.select_path(path)

        if not selection.path_is_selected(path):
            row = path[0]-1
            if row >= 0:
                selection.select_path((row,))
                path = (row, )

        # delete from db
        self.model.delete(fid)

        # refresh files treeview
        try:
            id = model.get_value(model.get_iter(path), 0)
        except:
            id = model.get_value(model.get_iter_first(), 0)
        self.model.get_root_entries(id)

        # refresh file info view
        self.__get_item_info(id)

        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        return

    def on_delete3_activate(self, menu_item):
        """delete files selected on files treeview"""
        dmodel = self.model.discs_tree
        try:
            selection = self.view['files'].get_selection()
            model, list_of_paths = selection.get_selected_rows()
        except TypeError:
            return

        if not list_of_paths:
            Dialogs.Inf(_("Delete files"), _("No files selected"),
                        _("You have to select at least one file to delete."))
            return

        if self.model.config.confd['delwarn']:
            obj = Dialogs.Qst(_("Delete files"), _("Delete files?"),
                              _("Selected files and directories will be "
                                "permanently\n removed from catalog."))
            if not obj.run():
                return

        def foreach_disctree(zmodel, zpath, ziter, d):
            if d[0] == zmodel.get_value(ziter, 0):
                d[1].append(zpath)
            return False

        ids = []
        for p in list_of_paths:
            val = model.get_value(model.get_iter(p), 0)
            ids.append(val)

        for fid in ids:
            # delete from db
            self.model.delete(fid)

        try:
            # try to select something
            selection = self.view['discs'].get_selection()
            model, list_of_paths = selection.get_selected_rows()
            if not list_of_paths:
                list_of_paths = [1]
            fiter = model.get_iter(list_of_paths[0])
            self.model.get_root_entries(model.get_value(fiter, 0))
        except TypeError:
            return

        buf = gtk.TextBuffer()
        self.view['description'].set_buffer(buf)
        self.view['thumb_box'].hide()
        self.view['exifinfo'].hide()
        self.view['img_container'].hide()

        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)
        return

    def on_th_delete_activate(self, menu_item):
        if self.model.config.confd['delwarn']:
            obj = Dialogs.Qst(_("Delete thumbnail"), _("Delete thumbnail?"),
                              _("Current thumbnail will be permanently removed"
                                " from catalog."))
            if not obj.run():
                return
        path, column = self.view['files'].get_cursor()
        model = self.view['files'].get_model()
        iter = model.get_iter(path)
        id = model.get_value(iter, 0)
        if id:
            self.model.del_thumbnail(id)
            self.__get_item_info(id)
            self.model.unsaved_project = True
            self.__set_title(filepath=self.model.filename, modified=True)
        return

    def on_del_all_images_activate(self, menu_item):
        if self.model.config.confd['delwarn']:
            title = 'Delete images'
            question = 'Delete all images?'
            dsc = "All images and it's thumbnails will be permanently removed"
            dsc += " from catalog."
            obj = Dialogs.Qst(title, question, dsc)
            if not obj.run():
                return

        self.model.delete_all_images()
        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)

        try:
            path, column = self.view['files'].get_cursor()
            model = self.view['files'].get_model()
            fiter = model.get_iter(path)
            fid = model.get_value(fiter, 0)
            if fid:
                self.__get_item_info(fid)
        except:
            pass
        return

    def on_del_all_thumb_activate(self, menu_item):
        if self.model.config.confd['delwarn']:
            title = 'Delete images'
            question = 'Delete all images?'
            dsc = "All images without thumbnails will be permanently removed"
            dsc += " from catalog."
            obj = Dialogs.Qst(title, question, dsc)
            if not obj.run():
                return

        self.model.del_all_thumbnail()
        self.model.unsaved_project = True
        self.__set_title(filepath=self.model.filename, modified=True)

        try:
            path, column = self.view['files'].get_cursor()
            model = self.view['files'].get_model()
            fiter = model.get_iter(path)
            fid = model.get_value(fiter, 0)
            if fid:
                self.__get_item_info(fid)
        except:
            pass
        return

    def on_edit1_activate(self, menu_item):
        """Make sufficient menu items sensitive in right cases"""
        # TODO: consolidate popup-menus with edit menu
        if  self.view['tag_cloud_textview'].is_focus():
            self.view['delete1'].set_sensitive(False)
        else:
            self.view['delete1'].set_sensitive(True)

    def on_debugbtn_clicked(self, widget):
        """Debug. To remove in stable version, including button in GUI"""
        if __debug__:
            print "\nc_main.py: on_debugbtn_clicked()"
            print "------"
            print "unsaved_project = %s" % self.model.unsaved_project
            print "filename = %s" % self.model.filename
            print "internal_filename = %s" % self.model.internal_dirname
            print "db_connection = %s" % self.model.db_connection
            print "abort = %s" % self.model.abort
            print "self.model.config.recent = %s" % self.model.config.recent
            print "source: %s" % self.model.source
            print "files have focus", self.view['files'].is_focus()
            print "discs have focus", self.view['discs'].is_focus()
            print "images have focus", self.view['images'].is_focus()
            c = self.view['files'].get_column(0)
            c.set_visible(not c.get_visible())
            c = self.view['files'].get_column(2)
            c.set_visible(not c.get_visible())

    #####################
    # observed properetis
    def property_point_value_change(self, model, old, new):
        """File was activated in search window through the observable
        property - select it on the discs and files treeview, and get
        file description"""

        if new:
            discs_tree = self.view['discs']
            discs_model = discs_tree.get_model()
            parent_id = self.model.get_parent_id(new)

            def foreach_disctree(model, path, iterator, data):
                """find path in model to desired value"""
                if model.get_value(iterator, 0) == data:
                    discs_tree.expand_to_path(path)
                    discs_tree.set_cursor(path)
                return False

            discs_model.foreach(foreach_disctree, parent_id)

            files_list = self.view['files']
            files_model = files_list.get_model()

            def foreach_fileslist(model, path, iterator, data):
                """find path in model to desired value"""
                if model.get_value(iterator, 0) == data:
                    files_list.set_cursor(path)
                    self.__get_item_info(data)
                return False

            files_model.foreach(foreach_fileslist, new)
        return

    def property_statusmsg_value_change(self, model, old, new):
        if self.statusbar_id:
            self.view['mainStatus'].remove(self.context_id, self.statusbar_id)
        self.statusbar_id = self.view['mainStatus'].push(self.context_id,
                                                         "%s" % new)
        return

    def property_busy_value_change(self, model, old, new):
        if new != old:
            for w in self.widgets_all:
                self.view[w].set_sensitive(not new)
            for widget in self.widgets_cancel:
                self.view[widget].set_sensitive(new)
            if not new and self.scan_cd:
                self.scan_cd = False
                # umount/eject cd
                ejectapp = self.model.config.confd['ejectapp']
                if self.model.config.confd['eject'] and ejectapp:
                    msg = device_helper.eject_cd(ejectapp,
                                                self.model.config.confd['cd'])
                    if msg != 'ok':
                        title = _("Error ejecting device")
                        Dialogs.Wrn(title + " - pyGTKtalog",
                                    _("Cannot eject device pointed to %s") %
                                    self.model.config.confd['cd'],
                                    _("Last eject message:\n%s") % msg)
                else:
                    msg = device_helper.volumount(self.model.config.confd['cd'])
                    if msg != 'ok':
                        title = _("Error unmounting device")
                        Dialogs.Wrn(title + " - pyGTKtalog",
                                    _("Cannot unmount device pointed to %s") %
                                    self.model.config.confd['cd'],
                                    _("Last umount message:\n%s") % msg)
        return

    def property_progress_value_change(self, model, old, new):
        self.view['progressbar1'].set_fraction(new)
        return

    #########################
    # private class functions
    def __set_files_hiden_columns_visible(self, boolean):
        """switch visibility of default hidden columns in files treeview"""
        self.view['files'].get_column(0).set_visible(boolean)
        self.view['files'].get_column(2).set_visible(boolean)

    def __get_tv_selection_ids(self, treeview):
        """get selection from treeview and return coresponding ids' from
        connected model or None"""
        ids = []
        try:
            selection = treeview.get_selection()
            model, list_of_paths = selection.get_selected_rows()
            for path in list_of_paths:
                ids.append(model.get_value(model.get_iter(path), 0))
            return ids
        except:
            # DEBUG: treeview have no selection or smth is broken
            if __debug__:
                print "c_main.py: __get_tv_selection_ids(): error on",
                print "getting selected items"
            return
        return None

    def __get_tv_id_under_cursor(self, treeview):
        """get id of item form tree view under cursor"""
        path, column = treeview.get_cursor()
        if path and column:
            model = treeview.get_model()
            tm_iter = model.get_iter(path)
            item_id = model.get_value(tm_iter, 0)
            return item_id
        return None

    def __setup_disc_treeview(self):
        """Setup TreeView discs widget as tree."""
        self.view['discs'].set_model(self.model.discs_tree)

        c = gtk.TreeViewColumn('Filename')

        # one row contains image and text
        cellpb = gtk.CellRendererPixbuf()
        cell = gtk.CellRendererText()
        c.pack_start(cellpb, False)
        c.pack_start(cell, True)
        c.set_attributes(cellpb, stock_id=2)
        c.set_attributes(cell, text=1)

        self.view['discs'].append_column(c)

        # registration of treeview signals:

        return

    def __setup_iconview(self):
        """Setup IconView images widget."""
        self.view['images'].set_model(self.model.images_store)
        self.view['images'].set_pixbuf_column(1)
        self.view['images'].set_selection_mode(gtk.SELECTION_MULTIPLE)
        return

    def __setup_files_treeview(self):
        """Setup TreeView files widget, as columned list."""
        v = self.view['files']
        v.set_model(self.model.files_list)

        v.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

        c = gtk.TreeViewColumn('Disc', gtk.CellRendererText(), text=1)
        c.set_sort_column_id(1)
        c.set_resizable(True)
        c.set_visible(False)
        self.view['files'].append_column(c)

        c = gtk.TreeViewColumn('Filename')
        cellpb = gtk.CellRendererPixbuf()
        cell = gtk.CellRendererText()
        c.pack_start(cellpb, False)
        c.pack_start(cell, True)
        c.set_attributes(cellpb, stock_id=7)
        c.set_attributes(cell, text=2)
        c.set_sort_column_id(2)
        c.set_resizable(True)
        self.view['files'].append_column(c)

        c = gtk.TreeViewColumn('Path', gtk.CellRendererText(), text=3)
        c.set_sort_column_id(3)
        c.set_resizable(True)
        c.set_visible(False)
        self.view['files'].append_column(c)

        c = gtk.TreeViewColumn('Size', gtk.CellRendererText(), text=4)
        c.set_sort_column_id(4)
        c.set_resizable(True)
        self.view['files'].append_column(c)

        c = gtk.TreeViewColumn('Date', gtk.CellRendererText(), text=5)
        c.set_sort_column_id(5)
        c.set_resizable(True)
        self.view['files'].append_column(c)
        self.view['files'].set_search_column(2)

        #v.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
        #                           self.DND_TARGETS,
        #                           gtk.gdk.ACTION_DEFAULT)
        v.drag_source_set(gtk.gdk.BUTTON1_MASK, self.DND_TARGETS,
                          gtk.gdk.ACTION_COPY)
        return

    def __setup_exif_treeview(self):
        self.view['exif_tree'].set_model(self.model.exif_list)

        c = gtk.TreeViewColumn('EXIF key', gtk.CellRendererText(), text=0)
        c.set_sort_column_id(0)
        c.set_resizable(True)
        self.view['exif_tree'].append_column(c)

        c = gtk.TreeViewColumn('EXIF value', gtk.CellRendererText(), text=1)
        c.set_sort_column_id(1)
        c.set_resizable(True)
        self.view['exif_tree'].append_column(c)
        return

    def __activate_ui(self, name=None):
        """Make UI active, and set title"""
        self.model.unsaved_project = False
        self.__set_title(filepath=name)
        return

    def __set_title(self, filepath=None, modified=False):
        """Set main window title"""
        if modified:
            mod = " *"
        else:
            mod = ""

        if filepath:
            self.view['main'].set_title("%s - pyGTKtalog%s" %
                                        (os.path.basename(filepath), mod))
        else:
            self.view['main'].set_title("untitled - pyGTKtalog%s" % mod)
        return

    def __store_settings(self):
        """Store window size and pane position in config file (using config
       object from model)"""
        if self.model.config.confd['savewin']:
            self.model.config.confd['wx'], self.model.config.confd['wy'] = \
            self.view['main'].get_size()
        if self.model.config.confd['savepan']:
            self.model.config.confd['h'] = self.view['hpaned1'].get_position()
            self.model.config.confd['v'] = self.view['vpaned1'].get_position()
        self.model.config.save()
        return

    def __popup_menu(self, event, menu='discs_popup'):
        """Popoup desired menu"""
        self.view[menu].popup(None, None, None, 0, 0)
        #self.view[menu].popup(None, None, None, event.button,
        #                               event.time)
        self.view[menu].show_all()
        return

    def __generate_recent_menu(self):
        self.recent_menu = gtk.Menu()
        for i in self.model.config.recent:
            name = os.path.basename(i)
            item = gtk.MenuItem("%s" % name.replace('_', '__'))
            item.connect_object("activate", self.recent_item_response, i)
            self.recent_menu.append(item)
            item.show()
        self.view['recent_files1'].set_submenu(self.recent_menu)
        return

    def __get_item_info(self, file_id):
        """Get item under cusor, fetch information from model and depending on
        what kind of information file has display it"""
        buf = gtk.TextBuffer()
        if not file_id:
            self.__hide_details()
            return
        #self.view['description'].show()
        set = self.model.get_file_info(file_id)

        tag = buf.create_tag()
        tag.set_property('weight', pango.WEIGHT_BOLD)

        if __debug__ and 'fileinfo' in set:
            buf.insert_with_tags(buf.get_end_iter(), "ID: ", tag)
            buf.insert(buf.get_end_iter(), str(set['fileinfo']['id']) + "\n")
            buf.insert_with_tags(buf.get_end_iter(), "Type: ", tag)
            buf.insert(buf.get_end_iter(), str(set['fileinfo']['type']) + "\n")

        if set['fileinfo']['disc']:
            buf.insert_with_tags(buf.get_end_iter(), "Disc: ", tag)
            buf.insert(buf.get_end_iter(), set['fileinfo']['disc'] + "\n")
        if set['fileinfo']['disc'] and set['fileinfo']['type'] == 1:
            buf.insert_with_tags(buf.get_end_iter(), "Directory: ", tag)
        elif not set['fileinfo']['disc'] and set['fileinfo']['type'] == 1:
            buf.insert_with_tags(buf.get_end_iter(), "Disc: ", tag)
        else:
            buf.insert_with_tags(buf.get_end_iter(), "Filename: ", tag)
        buf.insert(buf.get_end_iter(), set['filename'] + "\n")
        buf.insert_with_tags(buf.get_end_iter(), "Date: ", tag)
        buf.insert(buf.get_end_iter(), str(set['fileinfo']['date']) + "\n")
        buf.insert_with_tags(buf.get_end_iter(), "Size: ", tag)
        buf.insert(buf.get_end_iter(), str(set['fileinfo']['size']) + "\n")

        if 'gthumb' in set:
            tag = buf.create_tag()
            tag.set_property('weight', pango.WEIGHT_BOLD)
            buf.insert_with_tags(buf.get_end_iter(), "\ngThumb comment:\n", tag)
            if set['gthumb']['note']:
                buf.insert(buf.get_end_iter(), set['gthumb']['note'] + "\n")
            if set['gthumb']['place']:
                buf.insert(buf.get_end_iter(), set['gthumb']['place'] + "\n")
            if set['gthumb']['date']:
                buf.insert(buf.get_end_iter(), set['gthumb']['date'] + "\n")

        if 'description' in set:
            tag = buf.create_tag()
            tag.set_property('weight', pango.WEIGHT_BOLD)
            buf.insert_with_tags(buf.get_end_iter(), "\nDetails:\n", tag)
            buf.insert(buf.get_end_iter(), set['description'] + "\n")

        if 'note' in set:
            tag = buf.create_tag()
            tag.set_property('weight', pango.WEIGHT_BOLD)
            buf.insert_with_tags(buf.get_end_iter(), "\nNote:\n", tag)
            buf.insert(buf.get_end_iter(), set['note'] + "\n")

        tags = self.model.get_file_tags(file_id)
        if tags:
            tag = buf.create_tag()
            tag.set_property('weight', pango.WEIGHT_BOLD)
            buf.insert_with_tags(buf.get_end_iter(), "\nFile tags:\n", tag)
            tags = tags.values()
            tags.sort()
            first = True
            for tag in tags:
                if first:
                    first = False
                    buf.insert(buf.get_end_iter(), tag)
                else:
                    buf.insert(buf.get_end_iter(), ", " + tag)

        self.view['description'].set_buffer(buf)

        if 'images' in set:
            self.__setup_iconview()
            self.view['img_container'].show()
        else:
            self.view['img_container'].hide()

        if 'exif' in set:
            self.view['exif_tree'].set_model(self.model.exif_list)
            self.view['exifinfo'].show()
        else:
            self.view['exifinfo'].hide()

        if 'thumbnail' in set:
            self.view['thumb'].set_from_file(set['thumbnail'])
            self.view['thumb_box'].show()
        else:
            self.view['thumb_box'].hide()
        return

    def __tag_cloud(self):
        """generate tag cloud"""
        tag_cloud = self.view['tag_cloud_textview']
        self.model.get_tags()

        def insert_blank(buff, b_iter):
            if b_iter.is_end() and b_iter.is_start():
                return b_iter
            else:
                buff.insert(b_iter, " ")
                b_iter = buff.get_end_iter()
            return b_iter

        buff = tag_cloud.get_buffer()

        # NOTE: remove old tags
        def foreach_rem(texttag, data):
            """remove old tags"""
            tag_table.remove(texttag)

        tag_table = buff.get_tag_table()
        while tag_table.get_size() > 0:
            tag_table.foreach(foreach_rem, None)

        buff.set_text('')

        if len(self.model.tag_cloud) > 0:
            for cloud in self.model.tag_cloud:
                buff_iter = insert_blank(buff, buff.get_end_iter())
                try:
                    tag = buff.create_tag(str(cloud['id']))
                    tag.set_property('size-points', cloud['size'])
                    #tag.connect('event', self.on_tag_cloud_click, tag)
                    tag_repr = cloud['name'] + "(%d)" % cloud['count']
                    buff.insert_with_tags(buff_iter, tag_repr, tag)
                except:
                    if __debug__:
                        print "c_main.py: __tag_cloud: error on tag:", cloud

    def __hide_details(self):
        """hide details and "reset" tabs visibility"""
        buf = self.view['description'].get_buffer()
        buf.set_text('')
        self.view['img_container'].hide()
        self.view['exifinfo'].hide()
        self.view['thumb_box'].hide()
        self.view['description'].set_buffer(buf)

    pass # end of class
