1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2026-01-22 14:41:39 +00:00

[#32] Internationalized the qt layer and localized it to French.

In the process of doing so, I also added a new preferences_dialog base class to reduce code duplication in the three pref dialogs (I didn't want to copy/paste the language combobox addition three times).
This commit is contained in:
Virgil Dupras
2011-01-21 13:57:54 +01:00
parent 7f8a357019
commit 2c127adf59
28 changed files with 1023 additions and 544 deletions

View File

@@ -15,9 +15,10 @@ from PyQt4.QtGui import QDesktopServices, QFileDialog, QDialog, QMessageBox, QAp
from jobprogress import job
from jobprogress.qt import Progress
from hscommon.trans import tr, trmsg
from core.app import DupeGuru as DupeGuruBase, JOB_SCAN, JOB_LOAD, JOB_MOVE, JOB_COPY, JOB_DELETE
from qtlib.about_box import AboutBox
from qtlib.recent import Recent
from qtlib.reg import Registration
@@ -29,11 +30,11 @@ from .problem_dialog import ProblemDialog
from .util import createActions
JOBID2TITLE = {
JOB_SCAN: "Scanning for duplicates",
JOB_LOAD: "Loading",
JOB_MOVE: "Moving",
JOB_COPY: "Copying",
JOB_DELETE: "Sending files to the recycle bin",
JOB_SCAN: tr("Scanning for duplicates"),
JOB_LOAD: tr("Loading"),
JOB_MOVE: tr("Moving"),
JOB_COPY: tr("Copying"),
JOB_DELETE: tr("Sending files to the recycle bin"),
}
class DupeGuru(DupeGuruBase, QObject):
@@ -86,13 +87,13 @@ class DupeGuru(DupeGuruBase, QObject):
# Setup actions that are common to both the directory dialog and the results window.
# (name, shortcut, icon, desc, func)
ACTIONS = [
('actionQuit', 'Ctrl+Q', '', "Quit", self.quitTriggered),
('actionPreferences', 'Ctrl+P', '', "Preferences", self.preferencesTriggered),
('actionShowHelp', 'F1', '', "dupeGuru Help", self.showHelpTriggered),
('actionAbout', '', '', "About dupeGuru", self.showAboutBoxTriggered),
('actionRegister', '', '', "Register dupeGuru", self.registerTriggered),
('actionCheckForUpdate', '', '', "Check for Update", self.checkForUpdateTriggered),
('actionOpenDebugLog', '', '', "Open Debug Log", self.openDebugLogTriggered),
('actionQuit', 'Ctrl+Q', '', tr("Quit"), self.quitTriggered),
('actionPreferences', 'Ctrl+P', '', tr("Preferences"), self.preferencesTriggered),
('actionShowHelp', 'F1', '', tr("dupeGuru Help"), self.showHelpTriggered),
('actionAbout', '', '', tr("About dupeGuru"), self.showAboutBoxTriggered),
('actionRegister', '', '', tr("Register dupeGuru"), self.registerTriggered),
('actionCheckForUpdate', '', '', tr("Check for Update"), self.checkForUpdateTriggered),
('actionOpenDebugLog', '', '', tr("Open Debug Log"), self.openDebugLogTriggered),
]
createActions(ACTIONS, self)
@@ -139,21 +140,21 @@ class DupeGuru(DupeGuruBase, QObject):
args = tuple([j] + list(args))
self._progress.run(jobid, title, func, args=args)
except job.JobInProgressError:
msg = "A previous action is still hanging in there. You can't start a new one yet. Wait a few seconds, then try again."
msg = trmsg("TaskHangingMsg")
QMessageBox.information(self.resultWindow, 'Action in progress', msg)
def add_selected_to_ignore_list(self):
dupes = self.without_ref(self.selected_dupes)
if not dupes:
return
title = "Add to Ignore List"
msg = "All selected {0} matches are going to be ignored in all subsequent scans. Continue?".format(len(dupes))
title = tr("Add to Ignore List")
msg = trmsg("IgnoreConfirmMsg").format(len(dupes))
if self.confirm(title, msg):
DupeGuruBase.add_selected_to_ignore_list(self)
def copy_or_move_marked(self, copy):
opname = 'copy' if copy else 'move'
title = "Select a directory to {0} marked files to".format(opname)
opname = tr("copy") if copy else tr("move")
title = trmsg("SelectCopyOrMoveDestinationMsg").format(opname)
flags = QFileDialog.ShowDirsOnly
destination = str(QFileDialog.getExistingDirectory(self.resultWindow, title, '', flags))
if not destination:
@@ -165,8 +166,8 @@ class DupeGuru(DupeGuruBase, QObject):
dupes = self.without_ref(self.selected_dupes)
if not dupes:
return
title = "Remove duplicates"
msg = "You are about to remove {0} files from results. Continue?".format(len(dupes))
title = tr("Remove duplicates")
msg = trmsg("FileRemovalConfirmMsg").format(len(dupes))
if self.confirm(title, msg):
DupeGuruBase.remove_selected(self)
@@ -185,8 +186,8 @@ class DupeGuru(DupeGuruBase, QObject):
if cmd:
self.invoke_command(cmd)
else:
msg = "You have no custom command set up. Please, set it up in your preferences."
QMessageBox.warning(self.resultWindow, 'Custom Command', msg)
msg = trmsg("NoCustomCommandMsg")
QMessageBox.warning(self.resultWindow, tr("Custom Command"), msg)
def show_details(self):
self.details_dialog.show()
@@ -212,12 +213,12 @@ class DupeGuru(DupeGuruBase, QObject):
if self.results.problems:
self.problemDialog.show()
else:
msg = "All files were processed successfully."
QMessageBox.information(self.resultWindow, 'Operation Complete', msg)
msg = trmsg("OperationSuccessMsg")
QMessageBox.information(self.resultWindow, tr("Operation Complete"), msg)
elif jobid == JOB_SCAN:
if not self.results.groups:
title = "Scan complete"
msg = "No duplicates found."
title = tr("Scan complete")
msg = trmsg("NoDuplicateFoundMsg")
QMessageBox.information(self.resultWindow, title, msg)
else:
self.showResultsWindow()

View File

@@ -9,7 +9,9 @@
from PyQt4.QtCore import Qt, SIGNAL, QAbstractTableModel
from PyQt4.QtGui import QHeaderView, QTableView
HEADER = ['Attribute', 'Selected', 'Reference']
from hscommon.trans import tr
HEADER = [tr("Attribute"), tr("Selected"), tr("Reference")]
class DetailsModel(QAbstractTableModel):
def __init__(self, model):

View File

@@ -1,5 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="en.qm">../lang/en.qm</file>
<file alias="fr.qm">../lang/fr.qm</file>
<file alias="qt_fr.qm">../lang/qt_fr.qm</file>
<file alias="logo_pe">../../images/dgpe_logo_32.png</file>

View File

@@ -11,6 +11,7 @@ from PyQt4.QtGui import (QWidget, QFileDialog, QHeaderView, QVBoxLayout, QHBoxLa
QAbstractItemView, QSpacerItem, QSizePolicy, QPushButton, QApplication, QMessageBox, QMainWindow,
QMenuBar, QMenu, QIcon, QPixmap)
from hscommon.trans import tr, trmsg
from qtlib.recent import Recent
from core.app import NoScannableFileError
@@ -49,9 +50,9 @@ class DirectoriesDialog(QMainWindow):
def _setupActions(self):
# (name, shortcut, icon, desc, func)
ACTIONS = [
('actionLoadResults', 'Ctrl+L', '', "Load Results...", self.loadResultsTriggered),
('actionShowResultsWindow', '', '', "Results Window", self.app.showResultsWindow),
('actionAddFolder', '', '', "Add Folder...", self.addFolderTriggered),
('actionLoadResults', 'Ctrl+L', '', tr("Load Results..."), self.loadResultsTriggered),
('actionShowResultsWindow', '', '', tr("Results Window"), self.app.showResultsWindow),
('actionAddFolder', '', '', tr("Add Folder..."), self.addFolderTriggered),
]
createActions(ACTIONS, self)
@@ -59,13 +60,13 @@ class DirectoriesDialog(QMainWindow):
self.menubar = QMenuBar(self)
self.menubar.setGeometry(QRect(0, 0, 42, 22))
self.menuFile = QMenu(self.menubar)
self.menuFile.setTitle("File")
self.menuFile.setTitle(tr("File"))
self.menuView = QMenu(self.menubar)
self.menuView.setTitle("View")
self.menuView.setTitle(tr("View"))
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle("Help")
self.menuHelp.setTitle(tr("Help"))
self.menuLoadRecent = QMenu(self.menuFile)
self.menuLoadRecent.setTitle("Load Recent Results")
self.menuLoadRecent.setTitle(tr("Load Recent Results"))
self.setMenuBar(self.menubar)
self.menuFile.addAction(self.actionLoadResults)
@@ -126,10 +127,10 @@ class DirectoriesDialog(QMainWindow):
spacerItem1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.loadResultsButton = QPushButton(self.centralwidget)
self.loadResultsButton.setText("Load Results")
self.loadResultsButton.setText(tr("Load Results"))
self.horizontalLayout.addWidget(self.loadResultsButton)
self.scanButton = QPushButton(self.centralwidget)
self.scanButton.setText("Scan")
self.scanButton.setText(tr("Scan"))
self.scanButton.setDefault(True)
self.horizontalLayout.addWidget(self.scanButton)
self.verticalLayout.addLayout(self.horizontalLayout)
@@ -167,8 +168,8 @@ class DirectoriesDialog(QMainWindow):
def closeEvent(self, event):
event.accept()
if self.app.results.is_modified:
title = "Unsaved results"
msg = "You have unsaved results, do you really want to quit?"
title = tr("Unsaved results")
msg = trmsg("ReallyWantToQuitMsg")
if not self.app.confirm(title, msg):
event.ignore()
if event.isAccepted():
@@ -176,7 +177,7 @@ class DirectoriesDialog(QMainWindow):
#--- Events
def addFolderTriggered(self):
title = "Select a directory to add to the scanning list"
title = trmsg("SelectFolderToAddMsg")
flags = QFileDialog.ShowDirsOnly
dirpath = str(QFileDialog.getExistingDirectory(self, title, self.lastAddedFolder, flags))
if not dirpath:
@@ -189,8 +190,8 @@ class DirectoriesDialog(QMainWindow):
self.app.prefs.directoriesWindowRect = self.geometry()
def loadResultsTriggered(self):
title = "Select a results file to load"
files = "dupeGuru Results (*.dupeguru)"
title = trmsg("SelectResultToLoadMsg")
files = tr("dupeGuru Results (*.dupeguru)")
destination = QFileDialog.getOpenFileName(self, title, '', files)
if destination:
self.app.load_from(destination)
@@ -207,15 +208,16 @@ class DirectoriesDialog(QMainWindow):
self.app.remove_directory(row)
def scanButtonClicked(self):
title = "Start a new scan"
title = tr("Start a new scan")
# XXX must be triggered on unsaved results
if len(self.app.results.groups) > 0:
msg = "Are you sure you want to start a new duplicate scan?"
msg = trmsg("ReallyWantToContinueMsg")
if not self.app.confirm(title, msg):
return
try:
self.app.start_scanning()
except NoScannableFileError:
msg = "The selected directories contain no scannable file."
msg = trmsg("NoScannableFileMsg")
QMessageBox.warning(self, title, msg)
def selectionChanged(self, selected, deselected):

View File

@@ -12,12 +12,13 @@ from PyQt4.QtCore import QModelIndex, Qt, QRect, QEvent, QPoint, QUrl
from PyQt4.QtGui import (QComboBox, QStyledItemDelegate, QMouseEvent, QApplication, QBrush, QStyle,
QStyleOptionComboBox, QStyleOptionViewItemV4)
from hscommon.trans import tr
from qtlib.tree_model import RefNode, TreeModel
from core.gui.directory_tree import DirectoryTree
HEADERS = ['Name', 'State']
STATES = ['Normal', 'Reference', 'Excluded']
HEADERS = [tr("Name"), tr("State")]
STATES = [tr("Normal"), tr("Reference"), tr("Excluded")]
class DirectoriesDelegate(QStyledItemDelegate):
def createEditor(self, parent, option, index):

View File

@@ -29,6 +29,8 @@ class Preferences(PreferencesBase):
self.remove_empty_folders = get('RemoveEmptyFolders', self.remove_empty_folders)
self.destination_type = get('DestinationType', self.destination_type)
self.custom_command = get('CustomCommand', self.custom_command)
self.language = get('Language', self.language)
widths = get('ColumnsWidth', self.columns_width)
# only set nonzero values
for index, width in enumerate(widths[:len(self.columns_width)]):
@@ -59,6 +61,7 @@ class Preferences(PreferencesBase):
self.remove_empty_folders = False
self.destination_type = 1
self.custom_command = ''
self.language = ''
self.resultWindowIsMaximized = False
self.resultWindowRect = None
@@ -90,6 +93,7 @@ class Preferences(PreferencesBase):
set_('CustomCommand', self.custom_command)
set_('ColumnsWidth', self.columns_width)
set_('ColumnsVisible', self.columns_visible)
set_('Language', self.language)
set_('ResultWindowIsMaximized', self.resultWindowIsMaximized)
self.set_rect('ResultWindowRect', self.resultWindowRect)

View File

@@ -0,0 +1,164 @@
# Created By: Virgil Dupras
# Created On: 2011-01-21
# Copyright 2011 Hardcoded Software (http://www.hardcoded.net)
#
# This software is licensed under the "BSD" License as described in the "LICENSE" file,
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license
import sys
from PyQt4.QtCore import SIGNAL, Qt, QSize
from PyQt4.QtGui import (QDialog, QDialogButtonBox, QVBoxLayout, QHBoxLayout, QLabel, QComboBox,
QSlider, QSizePolicy, QSpacerItem, QCheckBox, QLineEdit, QMessageBox)
from hscommon.trans import tr, trmsg
class PreferencesDialogBase(QDialog):
def __init__(self, parent, app):
flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint
QDialog.__init__(self, parent, flags)
self.app = app
self._setupUi()
self.connect(self.filterHardnessSlider, SIGNAL("valueChanged(int)"), self.filterHardnessLabel.setNum)
self.connect(self.buttonBox, SIGNAL('clicked(QAbstractButton*)'), self.buttonClicked)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
def _setupFilterHardnessBox(self):
self.filterHardnessHLayout = QHBoxLayout()
self.filterHardnessLabel = QLabel(self)
self.filterHardnessLabel.setText(tr("Filter Hardness:"))
self.filterHardnessLabel.setMinimumSize(QSize(0, 0))
self.filterHardnessHLayout.addWidget(self.filterHardnessLabel)
self.filterHardnessVLayout = QVBoxLayout()
self.filterHardnessVLayout.setSpacing(0)
self.filterHardnessHLayoutSub1 = QHBoxLayout()
self.filterHardnessHLayoutSub1.setSpacing(12)
self.filterHardnessSlider = QSlider(self)
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.filterHardnessSlider.sizePolicy().hasHeightForWidth())
self.filterHardnessSlider.setSizePolicy(sizePolicy)
self.filterHardnessSlider.setMinimum(1)
self.filterHardnessSlider.setMaximum(100)
self.filterHardnessSlider.setTracking(True)
self.filterHardnessSlider.setOrientation(Qt.Horizontal)
self.filterHardnessHLayoutSub1.addWidget(self.filterHardnessSlider)
self.filterHardnessLabel = QLabel(self)
self.filterHardnessLabel.setText("100")
self.filterHardnessLabel.setMinimumSize(QSize(21, 0))
self.filterHardnessHLayoutSub1.addWidget(self.filterHardnessLabel)
self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub1)
self.filterHardnessHLayoutSub2 = QHBoxLayout()
self.filterHardnessHLayoutSub2.setContentsMargins(-1, 0, -1, -1)
self.moreResultsLabel = QLabel(self)
self.moreResultsLabel.setText(tr("More Results"))
self.filterHardnessHLayoutSub2.addWidget(self.moreResultsLabel)
spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.filterHardnessHLayoutSub2.addItem(spacerItem)
self.fewerResultsLabel = QLabel(self)
self.fewerResultsLabel.setText(tr("Fewer Results"))
self.filterHardnessHLayoutSub2.addWidget(self.fewerResultsLabel)
self.filterHardnessVLayout.addLayout(self.filterHardnessHLayoutSub2)
self.filterHardnessHLayout.addLayout(self.filterHardnessVLayout)
def _setupBottomPart(self):
# The bottom part of the pref panel is always the same in all editions.
self.languageLabel = QLabel(tr("Language:"), self)
self.widgetsVLayout.addWidget(self.languageLabel)
self.languageComboBox = QComboBox(self)
self.languageComboBox.addItem(tr("English"))
self.languageComboBox.addItem(tr("French"))
self.widgetsVLayout.addWidget(self.languageComboBox)
self.copyMoveLabel = QLabel(self)
self.copyMoveLabel.setText(tr("Copy and Move:"))
self.widgetsVLayout.addWidget(self.copyMoveLabel)
self.copyMoveDestinationComboBox = QComboBox(self)
self.copyMoveDestinationComboBox.addItem(tr("Right in destination"))
self.copyMoveDestinationComboBox.addItem(tr("Recreate relative path"))
self.copyMoveDestinationComboBox.addItem(tr("Recreate absolute path"))
self.widgetsVLayout.addWidget(self.copyMoveDestinationComboBox)
self.customCommandLabel = QLabel(self)
self.customCommandLabel.setText(tr("Custom Command (arguments: %d for dupe, %r for ref):"))
self.widgetsVLayout.addWidget(self.customCommandLabel)
self.customCommandEdit = QLineEdit(self)
self.widgetsVLayout.addWidget(self.customCommandEdit)
def _setupAddCheckbox(self, name, label, parent=None):
if parent is None:
parent = self
cb = QCheckBox(parent)
cb.setText(label)
setattr(self, name, cb)
def _setupPreferenceWidgets(self):
# Edition-specific
pass
def _setupUi(self):
self.setWindowTitle(tr("Preferences"))
self.resize(304, 263)
self.setSizeGripEnabled(False)
self.setModal(True)
self.mainVLayout = QVBoxLayout(self)
self.widgetsVLayout = QVBoxLayout()
self._setupPreferenceWidgets()
self.mainVLayout.addLayout(self.widgetsVLayout)
self.buttonBox = QDialogButtonBox(self)
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok|QDialogButtonBox.RestoreDefaults)
self.mainVLayout.addWidget(self.buttonBox)
if sys.platform not in {'darwin', 'linux2'}:
self.verticalLayout.removeWidget(self.ignoreHardlinkMatches)
self.ignoreHardlinkMatches.setHidden(True)
def _load(self, prefs, setchecked):
# Edition-specific
pass
def _save(self, prefs, ischecked):
# Edition-specific
pass
def load(self, prefs=None):
if prefs is None:
prefs = self.app.prefs
self.filterHardnessSlider.setValue(prefs.filter_hardness)
self.filterHardnessLabel.setNum(prefs.filter_hardness)
setchecked = lambda cb, b: cb.setCheckState(Qt.Checked if b else Qt.Unchecked)
setchecked(self.mixFileKindBox, prefs.mix_file_kind)
setchecked(self.useRegexpBox, prefs.use_regexp)
setchecked(self.removeEmptyFoldersBox, prefs.remove_empty_folders)
setchecked(self.ignoreHardlinkMatches, prefs.ignore_hardlink_matches)
self.copyMoveDestinationComboBox.setCurrentIndex(prefs.destination_type)
self.customCommandEdit.setText(prefs.custom_command)
langindex = {'fr': 1}.get(self.app.prefs.language, 0)
self.languageComboBox.setCurrentIndex(langindex)
self._load(prefs, setchecked)
def save(self):
prefs = self.app.prefs
prefs.filter_hardness = self.filterHardnessSlider.value()
ischecked = lambda cb: cb.checkState() == Qt.Checked
prefs.mix_file_kind = ischecked(self.mixFileKindBox)
prefs.use_regexp = ischecked(self.useRegexpBox)
prefs.remove_empty_folders = ischecked(self.removeEmptyFoldersBox)
prefs.ignore_hardlink_matches = ischecked(self.ignoreHardlinkMatches)
prefs.destination_type = self.copyMoveDestinationComboBox.currentIndex()
prefs.custom_command = str(self.customCommandEdit.text())
langs = ['en', 'fr']
lang = langs[self.languageComboBox.currentIndex()]
oldlang = self.app.prefs.language
if oldlang not in langs:
oldlang = 'en'
if lang != oldlang:
QMessageBox.information(self, "", trmsg("NeedsToRestartToApplyLangMsg"))
self.app.prefs.language = lang
self._save(prefs, ischecked)
#--- Events
def buttonClicked(self, button):
role = self.buttonBox.buttonRole(button)
if role == QDialogButtonBox.ResetRole:
self.resetToDefaults()

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Created By: Virgil Dupras
# Created On: 2010-04-12
# Copyright 2010 Hardcoded Software (http://www.hardcoded.net)
@@ -11,6 +10,7 @@ from PyQt4.QtCore import Qt
from PyQt4.QtGui import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QSpacerItem, QSizePolicy,
QLabel, QTableView, QAbstractItemView, QApplication)
from hscommon.trans import tr, trmsg
from core.gui.problem_dialog import ProblemDialog as ProblemDialogModel
from .problem_table import ProblemTable
@@ -29,11 +29,11 @@ class ProblemDialog(QDialog):
self.closeButton.clicked.connect(self.accept)
def _setupUi(self):
self.setWindowTitle("Problems!")
self.setWindowTitle(tr("Problems!"))
self.resize(413, 323)
self.verticalLayout = QVBoxLayout(self)
self.label = QLabel(self)
self.label.setText("There were problems processing some (or all) of the files. The cause of these problems are described in the table below. Those files were not removed from your results.")
self.label.setText(trmsg("ProblemsDuringProcessingMsg"))
self.label.setWordWrap(True)
self.verticalLayout.addWidget(self.label)
self.tableView = QTableView(self)
@@ -47,12 +47,12 @@ class ProblemDialog(QDialog):
self.verticalLayout.addWidget(self.tableView)
self.horizontalLayout = QHBoxLayout()
self.revealButton = QPushButton(self)
self.revealButton.setText("Reveal Selected")
self.revealButton.setText(tr("Reveal Selected"))
self.horizontalLayout.addWidget(self.revealButton)
spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.closeButton = QPushButton(self)
self.closeButton.setText("Close")
self.closeButton.setText(tr("Close"))
self.closeButton.setDefault(True)
self.horizontalLayout.addWidget(self.closeButton)
self.verticalLayout.addLayout(self.horizontalLayout)

View File

@@ -7,14 +7,15 @@
# which should be included with this package. The terms are also available at
# http://www.hardcoded.net/licenses/bsd_license
from hscommon.trans import tr
from qtlib.column import Column
from qtlib.table import Table
from core.gui.problem_table import ProblemTable as ProblemTableModel
class ProblemTable(Table):
COLUMNS = [
Column('path', 'File Path', 150),
Column('msg', 'Error Message', 150),
Column('path', tr("File Path"), 150),
Column('msg', tr("Error Message"), 150),
]
def __init__(self, problem_dialog, view):

View File

@@ -9,10 +9,11 @@
import sys
from PyQt4.QtCore import Qt, SIGNAL, QUrl, QRect
from PyQt4.QtGui import (QMainWindow, QMenu, QPixmap, QIcon, QLabel, QHeaderView, QMessageBox,
QInputDialog, QLineEdit, QDesktopServices, QFileDialog, QMenuBar, QWidget, QVBoxLayout,
QAbstractItemView, QStatusBar)
from PyQt4.QtGui import (QMainWindow, QMenu, QLabel, QHeaderView, QMessageBox, QInputDialog,
QLineEdit, QDesktopServices, QFileDialog, QMenuBar, QWidget, QVBoxLayout, QAbstractItemView,
QStatusBar)
from hscommon.trans import tr, trmsg
from hscommon.util import nonone
from .results_model import ResultsModel, ResultsView
@@ -38,31 +39,31 @@ class ResultWindow(QMainWindow):
def _setupActions(self):
# (name, shortcut, icon, desc, func)
ACTIONS = [
('actionDetails', 'Ctrl+I', '', "Details", self.detailsTriggered),
('actionActions', '', '', "Actions", self.actionsTriggered),
('actionPowerMarker', 'Ctrl+1', '', "Show Dupes Only", self.powerMarkerTriggered),
('actionDelta', 'Ctrl+2', '', "Show Delta Values", self.deltaTriggered),
('actionDeleteMarked', 'Ctrl+D', '', "Send Marked to Recycle Bin", self.deleteTriggered),
('actionHardlinkMarked', 'Ctrl+Shift+D', '', "Delete Marked and Replace with Hardlinks", self.hardlinkTriggered),
('actionMoveMarked', 'Ctrl+M', '', "Move Marked to...", self.moveTriggered),
('actionCopyMarked', 'Ctrl+Shift+M', '', "Copy Marked to...", self.copyTriggered),
('actionRemoveMarked', 'Ctrl+R', '', "Remove Marked from Results", self.removeMarkedTriggered),
('actionRemoveSelected', 'Ctrl+Del', '', "Remove Selected from Results", self.removeSelectedTriggered),
('actionIgnoreSelected', 'Ctrl+Shift+Del', '', "Add Selected to Ignore List", self.addToIgnoreListTriggered),
('actionMakeSelectedReference', 'Ctrl+Space', '', "Make Selected Reference", self.makeReferenceTriggered),
('actionOpenSelected', 'Ctrl+O', '', "Open Selected with Default Application", self.openTriggered),
('actionRevealSelected', 'Ctrl+Shift+O', '', "Open Containing Folder of Selected", self.revealTriggered),
('actionRenameSelected', 'F2', '', "Rename Selected", self.renameTriggered),
('actionMarkAll', 'Ctrl+A', '', "Mark All", self.markAllTriggered),
('actionMarkNone', 'Ctrl+Shift+A', '', "Mark None", self.markNoneTriggered),
('actionInvertMarking', 'Ctrl+Alt+A', '', "Invert Marking", self.markInvertTriggered),
('actionMarkSelected', '', '', "Mark Selected", self.markSelectedTriggered),
('actionClearIgnoreList', '', '', "Clear Ignore List", self.clearIgnoreListTriggered),
('actionApplyFilter', 'Ctrl+F', '', "Apply Filter", self.applyFilterTriggered),
('actionCancelFilter', 'Ctrl+Shift+F', '', "Cancel Filter", self.cancelFilterTriggered),
('actionExport', '', '', "Export To HTML", self.exportTriggered),
('actionSaveResults', 'Ctrl+S', '', "Save Results...", self.saveResultsTriggered),
('actionInvokeCustomCommand', 'Ctrl+Alt+I', '', "Invoke Custom Command", self.app.invokeCustomCommand),
('actionDetails', 'Ctrl+I', '', tr("Details"), self.detailsTriggered),
('actionActions', '', '', tr("Actions"), self.actionsTriggered),
('actionPowerMarker', 'Ctrl+1', '', tr("Show Dupes Only"), self.powerMarkerTriggered),
('actionDelta', 'Ctrl+2', '', tr("Show Delta Values"), self.deltaTriggered),
('actionDeleteMarked', 'Ctrl+D', '', tr("Send Marked to Recycle Bin"), self.deleteTriggered),
('actionHardlinkMarked', 'Ctrl+Shift+D', '', tr("Delete Marked and Replace with Hardlinks"), self.hardlinkTriggered),
('actionMoveMarked', 'Ctrl+M', '', tr("Move Marked to..."), self.moveTriggered),
('actionCopyMarked', 'Ctrl+Shift+M', '', tr("Copy Marked to..."), self.copyTriggered),
('actionRemoveMarked', 'Ctrl+R', '', tr("Remove Marked from Results"), self.removeMarkedTriggered),
('actionRemoveSelected', 'Ctrl+Del', '', tr("Remove Selected from Results"), self.removeSelectedTriggered),
('actionIgnoreSelected', 'Ctrl+Shift+Del', '', tr("Add Selected to Ignore List"), self.addToIgnoreListTriggered),
('actionMakeSelectedReference', 'Ctrl+Space', '', tr("Make Selected Reference"), self.makeReferenceTriggered),
('actionOpenSelected', 'Ctrl+O', '', tr("Open Selected with Default Application"), self.openTriggered),
('actionRevealSelected', 'Ctrl+Shift+O', '', tr("Open Containing Folder of Selected"), self.revealTriggered),
('actionRenameSelected', 'F2', '', tr("Rename Selected"), self.renameTriggered),
('actionMarkAll', 'Ctrl+A', '', tr("Mark All"), self.markAllTriggered),
('actionMarkNone', 'Ctrl+Shift+A', '', tr("Mark None"), self.markNoneTriggered),
('actionInvertMarking', 'Ctrl+Alt+A', '', tr("Invert Marking"), self.markInvertTriggered),
('actionMarkSelected', '', '', tr("Mark Selected"), self.markSelectedTriggered),
('actionClearIgnoreList', '', '', tr("Clear Ignore List"), self.clearIgnoreListTriggered),
('actionApplyFilter', 'Ctrl+F', '', tr("Apply Filter"), self.applyFilterTriggered),
('actionCancelFilter', 'Ctrl+Shift+F', '', tr("Cancel Filter"), self.cancelFilterTriggered),
('actionExport', '', '', tr("Export To HTML"), self.exportTriggered),
('actionSaveResults', 'Ctrl+S', '', tr("Save Results..."), self.saveResultsTriggered),
('actionInvokeCustomCommand', 'Ctrl+Alt+I', '', tr("Invoke Custom Command"), self.app.invokeCustomCommand),
]
createActions(ACTIONS, self)
self.actionDelta.setCheckable(True)
@@ -72,17 +73,17 @@ class ResultWindow(QMainWindow):
self.menubar = QMenuBar(self)
self.menubar.setGeometry(QRect(0, 0, 630, 22))
self.menuFile = QMenu(self.menubar)
self.menuFile.setTitle("File")
self.menuFile.setTitle(tr("File"))
self.menuMark = QMenu(self.menubar)
self.menuMark.setTitle("Mark")
self.menuMark.setTitle(tr("Mark"))
self.menuActions = QMenu(self.menubar)
self.menuActions.setTitle("Actions")
self.menuActions.setTitle(tr("Actions"))
self.menuColumns = QMenu(self.menubar)
self.menuColumns.setTitle("Columns")
self.menuColumns.setTitle(tr("Columns"))
self.menuView = QMenu(self.menubar)
self.menuView.setTitle("View")
self.menuView.setTitle(tr("View"))
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle("Help")
self.menuHelp.setTitle(tr("Help"))
self.setMenuBar(self.menubar)
self.menuActions.addAction(self.actionDeleteMarked)
@@ -138,11 +139,11 @@ class ResultWindow(QMainWindow):
action.column_index = index
self._column_actions.append(action)
menu.addSeparator()
action = menu.addAction("Reset to Defaults")
action = menu.addAction(tr("Reset to Defaults"))
action.column_index = -1
# Action menu
actionMenu = QMenu('Actions', self.menubar)
actionMenu = QMenu(tr("Actions"), self.menubar)
actionMenu.addAction(self.actionDeleteMarked)
actionMenu.addAction(self.actionHardlinkMarked)
actionMenu.addAction(self.actionMoveMarked)
@@ -160,7 +161,7 @@ class ResultWindow(QMainWindow):
self.actionActions.setMenu(actionMenu)
def _setupUi(self):
self.setWindowTitle("dupeGuru Results")
self.setWindowTitle(tr("dupeGuru Results"))
self.resize(630, 514)
self.centralwidget = QWidget(self)
self.verticalLayout_2 = QVBoxLayout(self.centralwidget)
@@ -222,8 +223,8 @@ class ResultWindow(QMainWindow):
self.app.add_selected_to_ignore_list()
def applyFilterTriggered(self):
title = "Apply Filter"
msg = "Type the filter you want to apply on your results. See help for details."
title = tr("Apply Filter")
msg = trmsg("TypeFilterMsg")
text = nonone(self._last_filter, '[*]')
answer, ok = QInputDialog.getText(self, title, msg, QLineEdit.Normal, text)
if not ok:
@@ -236,15 +237,15 @@ class ResultWindow(QMainWindow):
self.app.apply_filter('')
def clearIgnoreListTriggered(self):
title = "Clear Ignore List"
title = tr("Clear Ignore List")
count = len(self.app.scanner.ignore_list)
if not count:
QMessageBox.information(self, title, "Nothing to clear.")
QMessageBox.information(self, title, trmsg("NothingToClearMsg"))
return
msg = "Do you really want to remove all {0} items from the ignore list?".format(count)
msg = trmsg("ClearIgnoreListConfirmMsg").format(count)
if self.app.confirm(title, msg, QMessageBox.No):
self.app.scanner.ignore_list.Clear()
QMessageBox.information(self, title, "Ignore list cleared.")
QMessageBox.information(self, title, trmsg("IgnoreListClearedMsg"))
def copyTriggered(self):
self.app.copy_or_move_marked(True)
@@ -253,8 +254,8 @@ class ResultWindow(QMainWindow):
count = self.app.results.mark_count
if not count:
return
title = "Delete duplicates"
msg = "You are about to send {0} files to the recycle bin. Continue?".format(count)
title = tr("Delete duplicates")
msg = trmsg("SendToTrashConfirmMsg").format(count)
if self.app.confirm(title, msg):
self.app.delete_marked()
@@ -278,8 +279,8 @@ class ResultWindow(QMainWindow):
count = self.app.results.mark_count
if not count:
return
title = "Delete and hardlink duplicates"
msg = "You are about to send {0} files to the trash and hardlink them afterwards. Continue?".format(count)
title = tr("Delete and hardlink duplicates")
msg = trmsg("HardlinkConfirmMsg").format(count)
if self.app.confirm(title, msg):
self.app.delete_marked(replace_with_hardlinks=True)
@@ -314,8 +315,8 @@ class ResultWindow(QMainWindow):
count = self.app.results.mark_count
if not count:
return
title = "Remove duplicates"
msg = "You are about to remove {0} files from results. Continue?".format(count)
title = tr("Remove duplicates")
msg = trmsg("FileRemovalConfirmMsg").format(count)
if self.app.confirm(title, msg):
self.app.remove_marked()
@@ -329,8 +330,8 @@ class ResultWindow(QMainWindow):
self.app.reveal_selected()
def saveResultsTriggered(self):
title = "Select a file to save your results to"
files = "dupeGuru Results (*.dupeguru)"
title = trmsg("SelectResultToSaveMsg")
files = tr("dupeGuru Results (*.dupeguru)")
destination = QFileDialog.getSaveFileName(self, title, '', files)
if destination:
self.app.save_as(destination)