Compare commits

..

No commits in common. "6a03e1e3998252939ab8a1056dc5a46bc5f97d45" and "6a2c1eb293553657d08dbb83bbc2938b828115c3" have entirely different histories.

9 changed files with 57 additions and 127 deletions

View File

@ -24,8 +24,8 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. Windows 10 / OSX 10.15 / Ubuntu 20.04 / Arch Linux]
- Version [e.g. 4.1.0]
- OS: [e.g. Windows 10 / OSX 10.15 / Ubuntu 20.04]
- Version [e.g. 4.0.4]
**Additional context**
Add any other context about the problem here. You may include the debug log although it is normally best to attach it as a file.

View File

@ -1,21 +1,19 @@
# dupeGuru
[dupeGuru][dupeguru] is a cross-platform (Linux, OS X, Windows) GUI tool to find duplicate files in
a system. It is written mostly in Python 3 and has the peculiarity of using
a system. It's written mostly in Python 3 and has the peculiarity of using
[multiple GUI toolkits][cross-toolkit], all using the same core Python code. On OS X, the UI layer
is written in Objective-C and uses Cocoa. On Linux, it is written in Python and uses Qt5.
is written in Objective-C and uses Cocoa. On Linux, it's written in Python and uses Qt5.
The Cocoa UI of dupeGuru is hosted in a separate repo: https://github.com/arsenetar/dupeguru-cocoa
The Cocoa UI of dupeGuru is hosted in a separate repo: https://github.com/hsoft/dupeguru-cocoa
## Current status
2020: various bug fixes and small UI improvements have been added. Packaging for MacOS is still a problem.
Development has been slow this past year, however very close to getting all the different 4.0.4 releases posted. Most of the work this past year (2019) has been towards packaging the application and issues related to that.
Still looking for additional help especially with regards to:
* OSX maintenance: reproducing bugs & cocoa version, building package with Cocoa UI.
* Linux maintenance: reproducing bugs, maintaining PPA repository, Debian package.
* Translations: updating missing strings.
* Documentation: keeping it up-to-date.
- OSX maintenance (reproducing bugs & cocoa version)
- Linux maintenance (reproducing bugs)
## Contents of this folder
@ -33,44 +31,26 @@ This folder contains the source for dupeGuru. Its documentation is in `help`, bu
## How to build dupeGuru from source
### Windows & macOS specific additional instructions
### Windows
For windows instructions see the [Windows Instructions](Windows.md).
For macos instructions (qt version) see the [macOS Instructions](macos.md).
### Prerequisites
* [Python 3.6+][python]
* [Python 3.5+][python]
* PyQt5
### Building with Make
dupeGuru comes with a makefile that can be used to build and run:
### make
$ make && make run
dupeGuru is built with "make":
### Building without Make
$ make
$ make run
$ cd <dupeGuru directory>
$ python3 -m venv --system-site-packages .\env
$ source .\env\bin\activate
$ pip install -r requirements.txt
$ python build.py
$ python run.py
### Generate Debian/Ubuntu package
### Generating Debian/Ubuntu package
To generate packages the extra requirements in requirements-extra.txt must be installed, the
steps are as follows:
$ bash -c "python3 -m venv --system-site-packages env && source env/bin/activate && pip install -r requirements.txt && python3 build.py --clean && python3 package.py"
$ cd <dupeGuru directory>
$ python3 -m venv --system-site-packages .\env
$ source .\env\bin\activate
$ pip install -r requirements.txt -r requirements-extra.txt
$ python build.py --clean
$ python package.py
This can be made a one-liner (once in the directory) as:
$ bash -c "python3 -m venv --system-site-packages env && source env/bin/activate && pip install -r requirements.txt -r requirements-extra.txt && python build.py --clean && python package.py"
## Running tests
### Running tests
The complete test suite is run with [Tox 1.7+][tox]. If you have it installed system-wide, you
don't even need to set up a virtualenv. Just `cd` into the root project folder and run `tox`.

View File

@ -1,2 +1,2 @@
__version__ = "4.1.0"
__version__ = "4.0.4"
__appname__ = "dupeGuru"

View File

@ -55,8 +55,7 @@ class ExcludeListDialogCore:
"""Sets property on row to highlight if its regex matches test_string supplied."""
matched = False
for row in self.exclude_list_table.rows:
compiled_regex = self.exclude_list.get_compiled(row.regex)
if compiled_regex and compiled_regex.match(test_string):
if self.exclude_list.get_compiled(row.regex).match(test_string):
matched = True
row.highlight = True
else:

View File

@ -1,29 +1,3 @@
=== 4.1.0 (2020-12-29)
* Use tabs instead of separate windows (#688)
* Show the shortcut for "mark selected" in results dialog (#656, #641)
* Add image comparison features to details dialog (#683)
* Add the ability to use regex based exclusion filters (#705)
* Change reference row background color, and allow user to adjust the color (#701)
* Save / Load directories as XML (#706)
* Workaround for EXIF IFD type mismatch in parsing function (#630, #698)
* Progress dialog stuck at "Verified X/X matches" (#693, #694)
* Fix word wrap in ignore list dialog (#687)
* Fix issue with result window action on creation (#685)
* Colorize details table differences, allow moving rows (#682)
* Fix loading Result of 'Scan Type: Folders' shows only '---' in every table cell (#677, #676)
* Fix issue with details and results dialog row trimming (#655, #654)
* Add option to enable/disable bold font (#646, #314)
* Use relative icon path for themes to override more easily (#746)
* Fix issues with Python 3.8 compatibility (#665)
* Fix flake8 issues (#672)
* Update to use newer pytest and expand flake8 checking, cleanup various Deprecation Warnings
* Add warnings to packaging script when files are not built (#691)
* Use relative icon path for themes to override more easily (#746)
* Update Packaging for Ubuntu (#593)
* Minor Build Updates (#627, #575, #628, #614)
* Update CI builds and add windows CI (#572, #669)
=== 4.0.4 (2019-05-13)
* Update qt/platform.py to support other Unix style OSes (#444)

View File

@ -65,25 +65,20 @@ class DupeGuru(QObject):
self.recentResults.mustOpenItem.connect(self.model.load_from)
self.resultWindow = None
if self.use_tabs:
self.main_window = (
TabBarWindow(self)
if not self.prefs.tabs_default_pos
else TabWindow(self)
)
self.main_window = TabBarWindow(self) if not self.prefs.tabs_default_pos else TabWindow(self)
parent_window = self.main_window
self.directories_dialog = self.main_window.createPage(
"DirectoriesDialog", app=self
)
self.directories_dialog = self.main_window.createPage("DirectoriesDialog", app=self)
self.main_window.addTab(
self.directories_dialog, "Directories", switch=False
)
self.directories_dialog, "Directories", switch=False)
self.actionDirectoriesWindow.setEnabled(False)
else: # floating windows only
self.main_window = None
self.directories_dialog = DirectoriesDialog(self)
parent_window = self.directories_dialog
self.progress_window = ProgressWindow(parent_window, self.model.progress_window)
self.progress_window = ProgressWindow(
parent_window, self.model.progress_window
)
self.problemDialog = ProblemDialog(
parent=parent_window, model=self.model.problem_dialog
)
@ -91,25 +86,22 @@ class DupeGuru(QObject):
self.ignoreListDialog = self.main_window.createPage(
"IgnoreListDialog",
parent=self.main_window,
model=self.model.ignore_list_dialog,
)
model=self.model.ignore_list_dialog)
self.excludeListDialog = self.main_window.createPage(
"ExcludeListDialog",
app=self,
parent=self.main_window,
model=self.model.exclude_list_dialog,
)
model=self.model.exclude_list_dialog)
else:
self.ignoreListDialog = IgnoreListDialog(
parent=parent_window, model=self.model.ignore_list_dialog
)
parent=parent_window, model=self.model.ignore_list_dialog)
self.excludeDialog = ExcludeListDialog(
app=self, parent=parent_window, model=self.model.exclude_list_dialog
)
app=self, parent=parent_window, model=self.model.exclude_list_dialog)
self.deletionOptions = DeletionOptions(
parent=parent_window, model=self.model.deletion_options
parent=parent_window,
model=self.model.deletion_options
)
self.about_box = AboutBox(parent_window, self)
@ -137,13 +129,7 @@ class DupeGuru(QObject):
self.preferencesTriggered,
),
("actionIgnoreList", "", "", tr("Ignore List"), self.ignoreListTriggered),
(
"actionDirectoriesWindow",
"",
"",
tr("Directories"),
self.showDirectoriesWindow,
),
("actionDirectoriesWindow", "", "", tr("Directories"), self.showDirectoriesWindow),
(
"actionClearPictureCache",
"Ctrl+Shift+P",
@ -151,13 +137,7 @@ class DupeGuru(QObject):
tr("Clear Picture Cache"),
self.clearPictureCacheTriggered,
),
(
"actionExcludeList",
"",
"",
tr("Exclusion Filters"),
self.excludeListTriggered,
),
("actionExcludeList", "", "", tr("Exclusion Filters"), self.excludeListTriggered),
("actionShowHelp", "F1", "", tr("dupeGuru Help"), self.showHelpTriggered),
("actionAbout", "", "", tr("About dupeGuru"), self.showAboutBoxTriggered),
(
@ -252,7 +232,8 @@ class DupeGuru(QObject):
if self.resultWindow is not None:
if self.use_tabs:
if self.main_window.indexOfWidget(self.resultWindow) < 0:
self.main_window.addTab(self.resultWindow, "Results", switch=True)
self.main_window.addTab(
self.resultWindow, "Results", switch=True)
return
self.main_window.showTab(self.resultWindow)
else:
@ -284,11 +265,9 @@ class DupeGuru(QObject):
"scanning have accented letters, you'll probably get a crash. It is advised that "
"you set your system locale properly."
)
QMessageBox.warning(
self.main_window if self.main_window else self.directories_dialog,
"Wrong Locale",
msg,
)
QMessageBox.warning(self.main_window if self.main_window
else self.directories_dialog,
"Wrong Locale", msg)
def clearPictureCacheTriggered(self):
title = tr("Clear Picture Cache")
@ -314,9 +293,7 @@ class DupeGuru(QObject):
"""Add tab for dialog, name the tab with desc_string, then show it."""
index = self.main_window.indexOfWidget(dialog)
# Create the tab if it doesn't exist already
if (
index < 0
): # or (not dialog.isVisible() and not self.main_window.isTabVisible(index)):
if index < 0: # or (not dialog.isVisible() and not self.main_window.isTabVisible(index)):
index = self.main_window.addTab(dialog, desc_string, switch=True)
# Show the tab for that widget
self.main_window.setCurrentIndex(index)
@ -327,7 +304,8 @@ class DupeGuru(QObject):
def preferencesTriggered(self):
preferences_dialog = self._get_preferences_dialog_class()(
self.main_window if self.main_window else self.directories_dialog, self
self.main_window if self.main_window else self.directories_dialog,
self
)
preferences_dialog.load()
result = preferences_dialog.exec()
@ -355,7 +333,7 @@ class DupeGuru(QObject):
if op.exists(help_path):
url = QUrl.fromLocalFile(help_path)
else:
url = QUrl("https://dupeguru.voltaicideas.net/help/en/")
url = QUrl("https://www.hardcoded.net/dupeguru/help/en/")
QDesktopServices.openUrl(url)
def handleSIGTERM(self):
@ -376,7 +354,8 @@ class DupeGuru(QObject):
return self.confirm("", prompt)
def create_results_window(self):
"""Creates resultWindow and details_dialog depending on the selected ``app_mode``."""
"""Creates resultWindow and details_dialog depending on the selected ``app_mode``.
"""
if self.details_dialog is not None:
# The object is not deleted entirely, avoid saving its geometry in the future
# self.willSavePrefs.disconnect(self.details_dialog.appWillSavePrefs)
@ -388,13 +367,10 @@ class DupeGuru(QObject):
if self.resultWindow is not None:
self.resultWindow.close()
# This is better for tabs, as it takes care of duplicate items in menu bar
self.resultWindow.deleteLater() if self.use_tabs else self.resultWindow.setParent(
None
)
self.resultWindow.deleteLater() if self.use_tabs else self.resultWindow.setParent(None)
if self.use_tabs:
self.resultWindow = self.main_window.createPage(
"ResultWindow", parent=self.main_window, app=self
)
"ResultWindow", parent=self.main_window, app=self)
else: # We don't use a tab widget, regular floating QMainWindow
self.resultWindow = ResultWindow(self.directories_dialog, self)
self.directories_dialog._updateActionsState()

View File

@ -118,7 +118,9 @@ class ExcludeListDialog(QDialog):
return
# if at least one row matched, we know whether table is highlighted or not
self._row_matched = self.model.test_string(input_text)
self.table.refresh()
# FIXME There is a bug on Windows (7) where the table rows don't get
# repainted until the table receives a mouse click event.
self.tableView.update()
input_regex = self.inputLine.text()
if not input_regex:
@ -146,7 +148,7 @@ class ExcludeListDialog(QDialog):
if self._row_matched:
self._row_matched = False
self.model.reset_rows_highlight()
self.table.refresh()
self.tableView.update()
def display_help_message(self):
self.app.show_message(tr("""\

View File

@ -58,10 +58,9 @@ class ErrorReportDialog(QDialog):
self.verticalLayout.addWidget(self.errorTextEdit)
msg = tr(
"Error reports should be reported as Github issues. You can copy the error traceback "
"above and paste it in a new issue.\n\nPlease make sure to run a search for any already "
"existing issues beforehand. Also make sure to test the very latest version available from the repository, "
"since the bug you are experiencing might have already been patched.\n\n"
"What usually really helps is if you add a description of how you got the error. Thanks!"
"above and paste it in a new issue (bonus point if you run a search to make sure the "
"issue doesn't already exist). What usually really helps is if you add a description "
"of how you got the error. Thanks!"
"\n\n"
"Although the application should continue to run after this error, it may be in an "
"unstable state, so it is recommended that you restart the application."

View File

@ -48,9 +48,9 @@ SetCompressor /SOLID lzma
!define APPLICENSE "LICENSE" ; License is not in build directory
!define APPICON "images\dgse_logo.ico" ; nor is the icon
!define DISTDIR "dist"
!define HELPURL "https://github.com/arsenetar/dupeguru/issues"
!define UPDATEURL "https://dupeguru.voltaicideas.net/"
!define ABOUTURL "https://dupeguru.voltaicideas.net/"
!define HELPURL "http://www.hardcoded.net/support/"
!define UPDATEURL "http://www.hardcoded.net/dupeguru/"
!define ABOUTURL "http://www.hardcoded.net/dupeguru/"
; Static Defines
!define UNINSTALLREGBASE "Software\Microsoft\Windows\CurrentVersion\Uninstall"