# -*- coding: utf-8 -*-

# Copyright (c) 2005 - 2006 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the base class of the VCS project browser helper.
"""

import os

from qt import QObject, QDialog, qApp

from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
from UI.Browser import BrowserFile
from Project.ProjectBrowser import ProjectBrowserSimpleDir
import Preferences

class VcsProjectBrowserHelper(QObject):
    """
    Class implementing the base class of the VCS project browser helper.
    """
    def __init__(self, vcsObject, browserObject, projectObject, isTranslationsBrowser,
        parent=None, name=None):
        """
        Constructor
        
        @param vcsObject reference to the vcs object
        @param browserObject reference to the project browser object
        @param projectObject reference to the project object
        @param isTranslationsBrowser flag indicating, the helper is requested for the
            translations browser (this needs some special treatment)
        @param parent parent widget (QWidget)
        @param name name of this object (string or QString)
        """
        QObject.__init__(self, parent, name)
        
        self.vcs = vcsObject
        self.browser = browserObject
        self.isTranslationsBrowser = isTranslationsBrowser
        self.project = projectObject
    
    def addVCSMenus(self, mainMenu, multiMenu, backMenu, dirMenu, dirMultiMenu):
        """
        Public method to add the VCS entries to the various project browser menus.
        
        @param mainMenu reference to the main menu (QPopupMenu)
        @param multiMenu reference to the multiple selection menu (QPopupMenu)
        @param backMenu reference to the background menu (QPopupMenu)
        @param dirMenu reference to the directory menu (QPopupMenu)
        @param dirMultiMenu reference to the multiple selection directory
            menu (QPopupMenu)
        """
        self.addVCSMenu(mainMenu)
        self.addVCSMenuMulti(multiMenu)
        self.addVCSMenuBack(backMenu)
        self.addVCSMenuDir(dirMenu)
        self.addVCSMenuDirMulti(dirMultiMenu)
    
    def handleShowPopupMenu(self, menu, standardItems):
        """
        Slot called before the context menu is shown. 
        
        It enables/disables the VCS menu entries depending on the overall 
        VCS status and the file status.
        
        @param menu reference to the menu to be shown
        @param standardItems array of standard items that need activation/deactivation
            depending on the overall VCS status
        """
        raise RuntimeError, 'Not implemented'
    
    def handleShowPopupMenuMulti(self, menu, standardItems):
        """
        Slot called before the context menu (multiple selections) is shown. 
        
        It enables/disables the VCS menu entries depending on the overall 
        VCS status and the files status.
        
        @param menu reference to the menu to be shown
        @param standardItems array of standard items that need activation/deactivation
            depending on the overall VCS status
        """
        raise RuntimeError, 'Not implemented'
    
    def handleShowPopupMenuDir(self, menu, standardItems):
        """
        Slot called before the context menu is shown. 
        
        It enables/disables the VCS menu entries depending on the overall 
        VCS status and the directory status.
        
        @param menu reference to the menu to be shown
        @param standardItems array of standard items that need activation/deactivation
            depending on the overall VCS status
        """
        raise RuntimeError, 'Not implemented'
    
    def handleShowPopupMenuDirMulti(self, menu, standardItems):
        """
        Slot called before the context menu is shown. 
        
        It enables/disables the VCS menu entries depending on the overall 
        VCS status and the directory status.
        
        @param menu reference to the menu to be shown
        @param standardItems array of standard items that need activation/deactivation
            depending on the overall VCS status
        """
        raise RuntimeError, 'Not implemented'

    ############################################################################
    ## General menu handling methods below
    ############################################################################
    
    def handleVCSUpdate(self):
        """
        Private slot called by the context menu to update a file from the VCS repository.
        """
        if self.isTranslationsBrowser:
            names = [unicode(itm.fileName()) \
                for itm in self.browser.getSelectedItems([ProjectBrowserSimpleDir])]
            if not names:
                names = [unicode(itm.fileName()) \
                    for itm in self.browser.getSelectedItems([BrowserFile])]
                names += ['%s.qm' % os.path.splitext(name)[0] for name in names]
        else:
            names = [unicode(itm.fileName()) for itm in self.browser.getSelectedItems()]
        self.vcs.vcsUpdate(names)
        
    def handleVCSCommit(self):
        """
        Private slot called by the context menu to commit the changes to the VCS repository.
        """
        if self.isTranslationsBrowser:
            names = [unicode(itm.fileName()) \
                for itm in self.browser.getSelectedItems([ProjectBrowserSimpleDir])]
            if not names:
                names = [unicode(itm.fileName()) \
                    for itm in self.browser.getSelectedItems([BrowserFile])]
                names += ['%s.qm' % os.path.splitext(name)[0] for name in names]
        else:
            names = [unicode(itm.fileName()) for itm in self.browser.getSelectedItems()]
        if Preferences.getVCS("AutoSaveFiles"):
            vm = qApp.mainWidget().getViewManager()
            for name in names:
                vm.saveEditor(name)
        self.vcs.vcsCommit(names, '')
        
    def handleVCSAdd(self):
        """
        Private slot called by the context menu to add the selected file to the VCS repository.
        """
        if self.isTranslationsBrowser:
            items = self.browser.getSelectedItems([ProjectBrowserSimpleDir])
            if items:
                names = [unicode(itm.fileName()) for itm in items]
                self.project.vcs.vcsAdd(names)
            else:
                items = self.browser.getSelectedItems([BrowserFile])
                names = [unicode(itm.fileName()) for itm in items]
                qnames = ['%s.qm' % os.path.splitext(name)[0] for name in names]
                
                # create empty files if they don't exist
                for name in names + qnames:
                    if not os.path.exists(name):
                        try:
                            f = open(name, 'w')
                            f.close()
                        except:
                            pass
        else:
            items = self.browser.getSelectedItems()
            names = [unicode(itm.fileName()) for itm in items]
            qnames = []
        
        if not names:
            return
        if len(names + qnames) == 1:
            self.vcs.vcsAdd(names[0], os.path.isdir(names[0]))
        else:
            if self.vcs.canDetectBinaries:
                self.vcs.vcsAdd(names + qnames)
            else:
                self.vcs.vcsAdd(names)
                if len(qnames):
                    self.vcs.vcsAddBinary(qnames)
        for itm, fn in zip(items, names):
            self.browser.updateVCSStatus(itm, fn)
        
    def handleVCSAddTree(self):
        """
        Private slot called by the context menu.
        
        It is used to add the selected
        directory tree to the VCS repository.
        """
        items = self.browser.getSelectedItems()
        names = [unicode(itm.fileName()) for itm in items]
        self.vcs.vcsAddTree(names)
        for itm, fn in zip(items, names):
            self.browser.updateVCSStatus(itm, fn)
            opened = itm.isOpen()
            itm.setOpen(0)
            qApp.processEvents()
            itm.setOpen(opened)
            node = self.browser.findParentNode(\
                fn.replace(self.browser.project.ppath+os.sep, ''))[0]
            while node != self.browser:
                fn = unicode(node.fileName())
                self.browser.updateVCSStatus(node, fn)
                node = self.browser.findParentNode(\
                    fn.replace(self.browser.project.ppath+os.sep, ''))[0]
        
    def handleVCSRemove(self):
        """
        Private slot called by the context menu to remove the selected file from the VCS repository.
        """
        if self.isTranslationsBrowser:
            items = self.browser.getSelectedItems([ProjectBrowserSimpleDir])
            if items:
                return      # not supported
            
            isRemoveDirs = 0
            items = self.browser.getSelectedItems([BrowserFile])
            names = [unicode(itm.fileName()) for itm in items]
            qnames = ['%s.qm' % os.path.splitext(name)[0] for name in names]
            translations = [unicode(itm.text(0)) for itm in items]
            
            dlg = DeleteFilesConfirmationDialog(self.parent(),
                self.trUtf8("Remove from repository (and disk)"),
                self.trUtf8("Do you really want to remove these translations from the repository (and disk)?"),
                self.trUtf8("&Yes"), self.trUtf8("&No"), translations)
            
            names.extend(qnames)
        else:
            items = self.browser.getSelectedItems()
            isRemoveDirs = len(items) == \
                self.browser.getSelectedItemsCount([ProjectBrowserSimpleDir])
            names = [unicode(itm.fileName()) for itm in items]
            files = [unicode(itm.fileName()).replace(self.browser.project.ppath+os.sep, '') \
                for itm in items]
            
            dlg = DeleteFilesConfirmationDialog(self.parent(),
                self.trUtf8("Remove from repository (and disk)"),
                self.trUtf8("Do you really want to remove these files from the repository (and disk)?"),
                self.trUtf8("&Yes"), self.trUtf8("&No"), files)
            
        if dlg.exec_loop() == QDialog.Accepted:
            status = self.vcs.vcsRemove(names)
            if status:
                if isRemoveDirs:
                    self.browser.handleRemoveDir() # remove directories from Project
                else:
                    self.browser.handleRemove() # remove file(s) from project
        
    def handleVCSLog(self):
        """
        Private slot called by the context menu to show the VCS log of a file.
        """
        itm = self.browser.currentItem()
        fn = unicode(itm.fileName())
        self.vcs.vcsLog(fn)
        
    def handleVCSDiff(self):
        """
        Private slot called by the context menu to show the difference of a file to the repository.
        """
        names = [unicode(itm.fileName()) for itm in self.browser.getSelectedItems()]
        self.vcs.vcsDiff(names)
        
    def handleVCSStatus(self):
        """
        Private slot called by the context menu to show the status of a file.
        """
        if self.isTranslationsBrowser:
            items = self.browser.getSelectedItems([ProjectBrowserSimpleDir])
            if items:
                names = [unicode(itm.fileName()) for itm in items]
            else:
                items = self.browser.getSelectedItems([BrowserFile])
                names = [unicode(itm.fileName()) for itm in items]
                names += ['%s.qm' % os.path.splitext(name)[0] for name in names]
        else:
            names = [unicode(itm.fileName()) for itm in self.browser.getSelectedItems()]
        self.vcs.vcsStatus(names)

    def handleVCSRevert(self):
        """
        Private slot called by the context menu to revert changes made to a file.
        """
        names = [unicode(itm.fileName()) for itm in self.browser.getSelectedItems()]
        self.vcs.vcsRevert(names)

    def handleVCSMerge(self):
        """
        Private slot called by the context menu to merge changes into to a file.
        """
        itm = self.browser.currentItem()
        fn = unicode(itm.fileName())
        self.vcs.vcsMerge(fn)
