1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2026-03-12 03:31:37 +00:00

Compare commits

...

34 Commits

Author SHA1 Message Date
421a58a61c Merge pull request #758 from serg-z/serg-z/prioritize-dialog-multi-selections
Prioritize dialog: adding/removing multiple items, adding/removing on double clicking an item, drag-n-drop fix
2021-01-11 18:50:15 -06:00
Sergey Zhuravlevich
b5a3313f80 Prioritize dialog: fix drag-n-drop putting items before the last item
When the items in the prioritizations list were drag-n-dropped to the
empty space, the row was equal to -1 and the dropped items ended up
being moved to the position before the last item. Fixing the row value
helps to avoid that behavior.

Signed-off-by: Sergey Zhuravlevich <sergey@zhur.xyz>
2021-01-07 17:42:43 +01:00
Sergey Zhuravlevich
116ac18e13 Prioritize dialog: add/remove criteria on double clicking an item
Signed-off-by: Sergey Zhuravlevich <sergey@zhur.xyz>
2021-01-07 17:42:43 +01:00
Sergey Zhuravlevich
32dcd90b50 Prioritize dialog: allow removing multiple prioritizations at once
Removing prioritizations one-by-one can be tedious. This commit enables
extended selection in the prioritizations list. Multiple items can be
selected with conventional methods, such as holding down Ctrl or Shift
key and clicking the items or holding down the left mouse button and
hovering the cursor over the list. All items also can be selected with
Ctrl+A.

Multiple items drag-n-drop is also possible.

To avoid confusion, the selection in the prioritizations list is cleared
after the items are removed or drag-n-dropped.

Signed-off-by: Sergey Zhuravlevich <sergey@zhur.xyz>
2021-01-07 17:42:30 +01:00
Sergey Zhuravlevich
c2fef8d624 Prioritize dialog: allow adding multiple criteria at once
Adding criteria to the prioritizations list one-by-one can be tedious.
This commit enables extended selection in the criteria list and
implements adding multiple items. Multiple criteria can be selected with
conventional methods, such as holding down Ctrl or Shift keys and
clicking the items or holding down the left mouse button and hovering
the cursor over the list. All items also can be selected with Ctrl+A.

Signed-off-by: Sergey Zhuravlevich <sergey@zhur.xyz>
2021-01-07 17:42:07 +01:00
fd0adc77b3 Update Readme notes for system setup 2021-01-06 12:22:15 -06:00
6a03e1e399 Update URLs 2021-01-05 23:21:44 -06:00
ae51842007 Update README.md 2021-01-05 23:04:42 -06:00
ab6acd9e88 Merge pull request #733 from glubsy/dev
Increment version to 4.1.0
2021-01-05 22:48:21 -06:00
6a2c1eb293 Fix flake8 issues introduced in package.py 2020-12-30 20:04:14 -06:00
7b4c31d262 Update for macos Qt version
- Update package.py to include a pyinstaller based packaging
- Update requirements and requirements-extra
- Add icon for macos
- Add macos.md for instructions
2020-12-30 16:44:27 -06:00
glubsy
5553414205 Fix updating QTableView on input
* When clicking on the test regex button or editing the test input field, the tableView doesn't update its data properly.
* Somehow QTableView.update() doesn't request the data from the model.
* The workaround is to call refresh on the model directly, which will in turn update its view.
2020-12-30 23:18:42 +01:00
glubsy
b138dfad33 Fix exception when testing invalid regex
* If a regex in the table is invalid and failed to compile, its "compiled" property is None.
* Only test against the regex if its compilation worked.
2020-12-30 22:50:42 +01:00
701e6d4bb2 Merge pull request #755 from glubsy/packaging
Fix Debian packaging issues
2020-12-30 14:41:34 -06:00
b44d1652b6 Change windows to use ini in AppData 2020-12-30 12:43:10 -06:00
glubsy
990eaaa797 Update requirements.txt
* Recently, the "hsaudiotag3k" on pypi has changed name slightly
* The actual version is now "1.1.3.post1"
* This avoids errors when invoking `pip -r requirements.txt`
2020-12-30 18:52:37 +01:00
glubsy
348ce95f83 Remove comment
* There is a bug with pyqt5<=5.14 where the table does not update after a call to update() and needs to receive a mouse click event in order to repaint as expected.
* This does not affect Windows only as this is a Qt5 bug.
* This seems to be fixed with pyqt5>=5.15.1.
2020-12-30 18:44:38 +01:00
glubsy
3255bdf0a2 Fix incorrect path 2020-12-30 17:55:53 +01:00
glubsy
1058247b44 Fix missing application icon
Should be placed in /usr/share/pixmaps for .dekstop file to point to it.
2020-12-30 00:24:15 +01:00
glubsy
7414f82e28 Fix missing directory for pixmap symlink in Debian 2020-12-29 23:57:10 +01:00
glubsy
8105bb709f Fix debian src package build
Workaround "dpkg-source: error: can't build with source format '3.0 (native)': native package version may not have a revision" error as mentioned in #753
2020-12-29 23:45:15 +01:00
ec628751af Minor cleanup to Windows.md 2020-12-29 14:56:37 -06:00
glubsy
288023d03e Update changelog 2020-12-29 21:51:16 +01:00
glubsy
7740dfca0e Update Readme 2020-12-29 21:31:36 +01:00
1e12ad8d4c Clean up Makefile & unused files
- Remove requirements-windows.txt as no longer used
- Remove srcpkg.sh as not up to date and not used
- Minor cleanup in makefile
- Update minimum python version to 3.6 in makefile
2020-12-29 14:08:37 -06:00
glubsy
c1d94d6771 Merge branch 'master' into dev 2020-12-29 20:10:42 +01:00
glubsy
6bc619055e Change version to 4.1.0 2020-12-06 20:13:03 +01:00
glubsy
32d66cd19b Move up to 4.0.5
* Initial push to 4.0.5 milestone
* Update changelog
2020-10-27 19:38:51 +01:00
glubsy
735ba2fd0e Update error dialog traceback message for users
* Incite users to look for already existing issues
* Also invite them to test the very latest version available first
2020-10-27 18:23:14 +01:00
glubsy
b16b6ecf4d Fix error after merging branches 2020-10-27 18:15:15 +01:00
glubsy
2875448c71 Merge branch 'save_directories' into dev 2020-10-27 16:23:49 +01:00
glubsy
51b76385c0 Merge branch 'exclude_list' into dev 2020-10-27 16:23:43 +01:00
glubsy
b9f8dd6ea0 Merge branch 'PR_ref_row_background_color' into dev 2020-10-27 16:23:35 +01:00
glubsy
6623b04403 Merge branch 'details_dialog_improvements' into dev 2020-10-27 16:23:23 +01:00
23 changed files with 293 additions and 138 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]
- Version [e.g. 4.0.4]
- OS: [e.g. Windows 10 / OSX 10.15 / Ubuntu 20.04 / Arch Linux]
- Version [e.g. 4.1.0]
**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,7 +1,7 @@
PYTHON ?= python3
PYTHON_VERSION_MINOR := $(shell ${PYTHON} -c "import sys; print(sys.version_info.minor)")
PYRCC5 ?= pyrcc5
REQ_MINOR_VERSION = 4
REQ_MINOR_VERSION = 6
PREFIX ?= /usr/local
# Window compatability via Msys2
@@ -15,7 +15,7 @@ ifeq ($(shell ${PYTHON} -c "import platform; print(platform.system())"), Windows
VENV_OPTIONS =
else
BIN = bin
SO = cpython-3$(PYTHON_VERSION_MINOR)*.so
SO = *.so
VENV_OPTIONS = --system-site-packages
endif
@@ -43,16 +43,16 @@ mofiles = $(patsubst %.po,%.mo,$(pofiles))
vpath %.po $(localedirs)
vpath %.mo $(localedirs)
all : | env i18n modules qt/dg_rc.py
all: | env i18n modules qt/dg_rc.py
@echo "Build complete! You can run dupeGuru with 'make run'"
run:
$(VENV_PYTHON) run.py
pyc:
${PYTHON} -m compileall ${packages}
pyc: | env
${VENV_PYTHON} -m compileall ${packages}
reqs :
reqs:
ifneq ($(shell test $(PYTHON_VERSION_MINOR) -gt $(REQ_MINOR_VERSION); echo $$?),0)
$(error "Python 3.${REQ_MINOR_VERSION}+ required. Aborting.")
endif
@@ -63,7 +63,7 @@ endif
@${PYTHON} -c 'import PyQt5' >/dev/null 2>&1 || \
{ echo "PyQt 5.4+ required. Install it and try again. Aborting"; exit 1; }
env : | reqs
env: | reqs
ifndef NO_VENV
@echo "Creating our virtualenv"
${PYTHON} -m venv env
@@ -73,40 +73,26 @@ ifndef NO_VENV
${PYTHON} -m venv --upgrade ${VENV_OPTIONS} env
endif
build/help : | env
build/help: | env
$(VENV_PYTHON) build.py --doc
qt/dg_rc.py : qt/dg.qrc
qt/dg_rc.py: qt/dg.qrc
$(PYRCC5) qt/dg.qrc > qt/dg_rc.py
i18n: $(mofiles)
%.mo : %.po
%.mo: %.po
msgfmt -o $@ $<
core/pe/_block.$(SO) : core/pe/modules/block.c core/pe/modules/common.c
$(PYTHON) hscommon/build_ext.py $^ _block
mv _block.$(SO) core/pe
modules: | env
$(VENV_PYTHON) build.py --modules
core/pe/_cache.$(SO) : core/pe/modules/cache.c core/pe/modules/common.c
$(PYTHON) hscommon/build_ext.py $^ _cache
mv _cache.$(SO) core/pe
qt/pe/_block_qt.$(SO) : qt/pe/modules/block.c
$(PYTHON) hscommon/build_ext.py $^ _block_qt
mv _block_qt.$(SO) qt/pe
modules : core/pe/_block.$(SO) core/pe/_cache.$(SO) qt/pe/_block_qt.$(SO)
mergepot :
mergepot: | env
$(VENV_PYTHON) build.py --mergepot
normpo :
normpo: | env
$(VENV_PYTHON) build.py --normpo
srcpkg :
./scripts/srcpkg.sh
install: all pyc
mkdir -p ${DESTDIR}${PREFIX}/share/dupeguru
cp -rf ${packages} locale ${DESTDIR}${PREFIX}/share/dupeguru
@@ -123,7 +109,7 @@ installdocs: build/help
mkdir -p ${DESTDIR}${PREFIX}/share/dupeguru
cp -rf build/help ${DESTDIR}${PREFIX}/share/dupeguru
uninstall :
uninstall:
rm -rf "${DESTDIR}${PREFIX}/share/dupeguru"
rm -f "${DESTDIR}${PREFIX}/bin/dupeguru"
rm -f "${DESTDIR}${PREFIX}/share/applications/dupeguru.desktop"
@@ -134,4 +120,4 @@ clean:
-rm locale/*/LC_MESSAGES/*.mo
-rm core/pe/*.$(SO) qt/pe/*.$(SO)
.PHONY : clean srcpkg normpo mergepot modules i18n reqs run pyc install uninstall all
.PHONY: clean normpo mergepot modules i18n reqs run pyc install uninstall all

View File

@@ -1,19 +1,21 @@
# dupeGuru
[dupeGuru][dupeguru] is a cross-platform (Linux, OS X, Windows) GUI tool to find duplicate files in
a system. It's written mostly in Python 3 and has the peculiarity of using
a system. It is 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's written in Python and uses Qt5.
is written in Objective-C and uses Cocoa. On Linux, it is written in Python and uses Qt5.
The Cocoa UI of dupeGuru is hosted in a separate repo: https://github.com/hsoft/dupeguru-cocoa
The Cocoa UI of dupeGuru is hosted in a separate repo: https://github.com/arsenetar/dupeguru-cocoa
## Current status
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.
2020: various bug fixes and small UI improvements have been added. Packaging for MacOS is still a problem.
Still looking for additional help especially with regards to:
- OSX maintenance (reproducing bugs & cocoa version)
- Linux maintenance (reproducing bugs)
* 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.
## Contents of this folder
@@ -31,26 +33,57 @@ This folder contains the source for dupeGuru. Its documentation is in `help`, bu
## How to build dupeGuru from source
### Windows
### Windows & macOS specific additional instructions
For windows instructions see the [Windows Instructions](Windows.md).
### Prerequisites
For macos instructions (qt version) see the [macOS Instructions](macos.md).
* [Python 3.5+][python]
### Prerequisites
* [Python 3.6+][python]
* PyQt5
### make
### System Setup
When running in a linux based environment the following system packages or equivalents are needed to build:
* python3-pyqt5
* python3-wheel (for hsaudiotag3k)
* python3-venv (only if using a virtual environment)
* python3-dev
* build-essential
dupeGuru is built with "make":
To create packages the following are also needed:
* python3-setuptools
* debhelper
$ make
$ make run
### Building with Make
dupeGuru comes with a makefile that can be used to build and run:
### Generate Debian/Ubuntu package
$ make && make run
$ 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"
### Building without Make
### Running tests
$ 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
### Generating Debian/Ubuntu package
To generate packages the extra requirements in requirements-extra.txt must be installed, the
steps are as follows:
$ 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
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

@@ -2,24 +2,24 @@
### Prerequisites
- [Python 3.5+][python]
- [Visual Studio 2017][vs] or [Visual Studio Build Tools 2017][vsBuildTools] with the Windows 10 SDK
- [Python 3.6+][python]
- [Visual Studio 2019][vs] or [Visual Studio Build Tools 2019][vsBuildTools] with the Windows 10 SDK
- [nsis][nsis] (for installer creation)
- [msys2][msys2] (for using makefile method)
When installing Visual Studio or the Visual Studio Build Tools with the Windows 10 SDK on versions of Windows below 10 be sure to make sure that the Universal CRT is installed before installing Visual studio as noted in the [Windows 10 SDK Notes][win10sdk] and found at [KB2999226][KB2999226].
NOTE: When installing Visual Studio or the Visual Studio Build Tools with the Windows 10 SDK on versions of Windows below 10 be sure to make sure that the Universal CRT is installed before installing Visual studio as noted in the [Windows 10 SDK Notes][win10sdk] and found at [KB2999226][KB2999226].
After installing python it is recommended to update setuptools before compiling packages. To update run (example is for python launcher and 3.7):
After installing python it is recommended to update setuptools before compiling packages. To update run (example is for python launcher and 3.8):
$ py -3.7 -m pip install --upgrade setuptools
$ py -3.8 -m pip install --upgrade setuptools
More details on setting up python for compiling packages on windows can be found on the [python wiki][pythonWindowsCompilers]
More details on setting up python for compiling packages on windows can be found on the [python wiki][pythonWindowsCompilers] Take note of the required vc++ versions.
### With build.py (preferred)
To build with a different python version 3.5 vs 3.7 or 32 bit vs 64 bit specify that version instead of -3.7 to the `py` command below. If you want to build additional versions while keeping all virtual environments setup use a different location for each vritual environment.
To build with a different python version 3.6 vs 3.8 or 32 bit vs 64 bit specify that version instead of -3.8 to the `py` command below. If you want to build additional versions while keeping all virtual environments setup use a different location for each virtual environment.
$ cd <dupeGuru directory>
$ py -3.7 -m venv .\env
$ py -3.8 -m venv .\env
$ .\env\Scripts\activate
$ pip install -r requirements.txt
$ python build.py
@@ -34,21 +34,21 @@ It is possible to build dupeGuru with the makefile on windows using a compatable
Then the following execution of the makefile should work. Pass the correct value for PYTHON to the makefile if not on the path as python3.
$ cd <dupeGuru directory>
$ make PYTHON='py -3.7'
$ make PYTHON='py -3.8'
$ make run
### Generate Windows Installer Packages
You need to use the respective x86 or x64 version of python to build the 32 bit and 64 bit versions. The build scripts will automatically detect the python architecture for you. When using build.py make sure the resulting python works before continuing to package.py. NOTE: package.py looks for the 'makensis' executable in the default location for a 64 bit windows system. Run the following in the respective virtual environment.
You need to use the respective x86 or x64 version of python to build the 32 bit and 64 bit versions. The build scripts will automatically detect the python architecture for you. When using build.py make sure the resulting python works before continuing to package.py. NOTE: package.py looks for the 'makensis' executable in the default location for a 64 bit windows system. The extra requirements need to be installed to run packaging: `pip install -r requirements-extra.txt`. Run the following in the respective virtual environment.
$ python package.py
### Running tests
The complete test suite can be run with tox just like on linux.
The complete test suite can be run with tox just like on linux. NOTE: The extra requirements need to be installed to run unit tests: `pip install -r requirements-extra.txt`.
[python]: http://www.python.org/
[nsis]: http://nsis.sourceforge.net/Main_Page
[vs]: https://www.visualstudio.com/downloads/#visual-studio-community-2017
[vsBuildTools]: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017
[vs]: https://www.visualstudio.com/downloads/#visual-studio-community-2019
[vsBuildTools]: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2019
[win10sdk]: https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk
[KB2999226]: https://support.microsoft.com/en-us/help/2999226/update-for-universal-c-runtime-in-windows
[pythonWindowsCompilers]: https://wiki.python.org/moin/WindowsCompilers

View File

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

View File

@@ -55,7 +55,8 @@ 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:
if self.exclude_list.get_compiled(row.regex).match(test_string):
compiled_regex = self.exclude_list.get_compiled(row.regex)
if compiled_regex and compiled_regex.match(test_string):
matched = True
row.highlight = True
else:

View File

@@ -72,13 +72,15 @@ class PrioritizeDialog(GUIObject):
# Add selected criteria in criteria_list to prioritization_list.
if self.criteria_list.selected_index is None:
return
crit = self.criteria[self.criteria_list.selected_index]
self.prioritizations.append(crit)
del crit
for i in self.criteria_list.selected_indexes:
crit = self.criteria[i]
self.prioritizations.append(crit)
del crit
self.prioritization_list[:] = [crit.display for crit in self.prioritizations]
def remove_selected(self):
self.prioritization_list.remove_selected()
self.prioritization_list.select([])
def perform_reprioritization(self):
self.app.reprioritize_groups(self._sort_key)

View File

@@ -1,3 +1,29 @@
=== 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

@@ -295,7 +295,7 @@ def build_debian_changelog(
return [s.strip() for s in result if s.strip()]
ENTRY_MODEL = (
"{pkg} ({version}-1) {distribution}; urgency=low\n\n{changes}\n "
"{pkg} ({version}) {distribution}; urgency=low\n\n{changes}\n "
"-- Virgil Dupras <hsoft@hardcoded.net> {date}\n\n"
)
CHANGE_MODEL = " * {description}\n"

BIN
images/dupeguru.icns Executable file

Binary file not shown.

53
macos.md Normal file
View File

@@ -0,0 +1,53 @@
## How to build dupeGuru for macos
### Prerequisites
- [Python 3.6+][python]
- [Xcode 12.3][xcode] or just Xcode command line tools (older versions can be used if not interested in arm macs)
- [Homebrew][homebrew]
- [qt5](https://www.qt.io/)
#### Prerequisite setup
1. Install Xcode if desired
2. Install [Homebrew][homebrew], if not on the path after install (arm based Macs) create `~/.zshrc`
with `export PATH="/opt/homebrew/bin:$PATH"`. Will need to reload terminal or source the file to take
affect.
3. Install qt5 with `brew`. If you are using a version of macos without system python 3.6+ then you will
also need to install that via brew or with pyenv.
$ brew install qt5
NOTE: Using `brew` to install qt5 is to allow pyqt5 to build without a native wheel
available. If you are using an intel based mac you can probably skip this step.
4. May need to launch a new terminal to have everything working.
### With build.py
OSX comes with a version of python 3 by default in newer versions of OSX. To produce universal
builds either the 3.8 version shipped in macos or 3.9.1 or newer needs to be used. If needing to
build pyqt5 from source then the first line below is needed, else it may be omitted. (Path shown is
for an arm mac.)
$ export PATH="/opt/homebrew/opt/qt/bin:$PATH"
$ cd <dupeGuru directory>
$ python3 -m venv ./env
$ source ./env/bin/activate
$ pip install -r requirements.txt
$ python build.py
$ python run.py
### Generate OSX Packages
The extra requirements need to be installed to run packaging: `pip install -r requirements-extra.txt`.
Run the following in the respective virtual environment.
$ python package.py
This will produce a dupeGuru.app in the dist folder.
### Running tests
The complete test suite can be run with tox just like on linux. NOTE: The extra requirements need to
be installed to run unit tests: `pip install -r requirements-extra.txt`.
[python]: http://www.python.org/
[homebrew]: https://brew.sh/
[xcode]: https://developer.apple.com/xcode/

View File

@@ -46,11 +46,11 @@ def copy_files_to_package(destpath, packages, with_so):
# include locale files if they are built otherwise exit as it will break
# the localization
if not op.exists("build/locale"):
print("Locale files are missing. Have you run \"build.py --loc\"? Exiting...")
print('Locale files are missing. Have you run "build.py --loc"? Exiting...')
return
# include help files if they are built otherwise exit as they should be included?
if not op.exists("build/help"):
print("Help files are missing. Have you run \"build.py --doc\"? Exiting...")
print('Help files are missing. Have you run "build.py --doc"? Exiting...')
return
shutil.copytree(op.join("build", "help"), op.join(destpath, "help"))
shutil.copytree(op.join("build", "locale"), op.join(destpath, "locale"))
@@ -161,11 +161,11 @@ def package_windows():
# include locale files if they are built otherwise exit as it will break
# the localization
if not op.exists("build/locale"):
print("Locale files are missing. Have you run \"build.py --loc\"? Exiting...")
print('Locale files are missing. Have you run "build.py --loc"? Exiting...')
return
# include help files if they are built otherwise exit as they should be included?
if not op.exists("build/help"):
print("Help files are missing. Have you run \"build.py --doc\"? Exiting...")
print('Help files are missing. Have you run "build.py --doc"? Exiting...')
return
# create version information file from template
try:
@@ -211,6 +211,33 @@ def package_windows():
print_and_do(cmd.format(version_array[0], version_array[1], version_array[2], bits))
def package_macos():
# include locale files if they are built otherwise exit as it will break
# the localization
if not op.exists("build/locale"):
print('Locale files are missing. Have you run "build.py --loc"? Exiting...')
return
# include help files if they are built otherwise exit as they should be included?
if not op.exists("build/help"):
print('Help files are missing. Have you run "build.py --doc"? Exiting...')
return
# run pyinstaller from here:
import PyInstaller.__main__
PyInstaller.__main__.run(
[
"--name=dupeguru",
"--windowed",
"--noconfirm",
"--icon=images/dupeguru.icns",
"--osx-bundle-identifier=com.hardcoded-software.dupeguru",
"--add-data=build/locale:locale",
"--add-data=build/help:help",
"run.py",
]
)
def main():
args = parse_args()
if args.src_pkg:
@@ -220,6 +247,8 @@ def main():
print("Packaging dupeGuru with UI qt")
if sys.platform == "win32":
package_windows()
elif sys.platform == "darwin":
package_macos()
else:
if not args.arch_pkg:
distname = distro.id()

View File

@@ -8,5 +8,6 @@ all:
chmod +x src/run.py
cp -R src/ "$(CURDIR)/debian/{pkgname}/usr/share/{execname}"
cp "$(CURDIR)/debian/{execname}.desktop" "$(CURDIR)/debian/{pkgname}/usr/share/applications"
ln -s "/usr/share/{execname}/dgse_logo_128.png" "$(CURDIR)/debian/{pkgname}/usr/pixmaps/{execname}.png"
mkdir -p "$(CURDIR)/debian/{pkgname}/usr/share/pixmaps"
ln -s "/usr/share/{execname}/dgse_logo_128.png" "$(CURDIR)/debian/{pkgname}/usr/share/pixmaps/{execname}.png"
ln -s "/usr/share/{execname}/run.py" "$(CURDIR)/debian/{pkgname}/usr/bin/{execname}"

View File

@@ -65,20 +65,25 @@ 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
)
@@ -86,22 +91,25 @@ 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)
@@ -129,7 +137,13 @@ 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",
@@ -137,7 +151,13 @@ 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),
(
@@ -232,8 +252,7 @@ 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:
@@ -265,9 +284,11 @@ 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")
@@ -293,7 +314,9 @@ 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)
@@ -304,8 +327,7 @@ 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()
@@ -333,7 +355,7 @@ class DupeGuru(QObject):
if op.exists(help_path):
url = QUrl.fromLocalFile(help_path)
else:
url = QUrl("https://www.hardcoded.net/dupeguru/help/en/")
url = QUrl("https://dupeguru.voltaicideas.net/help/en/")
QDesktopServices.openUrl(url)
def handleSIGTERM(self):
@@ -354,8 +376,7 @@ 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)
@@ -367,10 +388,13 @@ 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,9 +118,7 @@ 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)
# 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()
self.table.refresh()
input_regex = self.inputLine.text()
if not input_regex:
@@ -148,7 +146,7 @@ class ExcludeListDialog(QDialog):
if self._row_matched:
self._row_matched = False
self.model.reset_rows_highlight()
self.tableView.update()
self.table.refresh()
def display_help_message(self):
self.app.show_message(tr("""\

View File

@@ -47,9 +47,16 @@ class PrioritizationList(ListviewModel):
# to know where the drop took place.
if parentIndex.isValid():
return False
# "When row and column are -1 it means that the dropped data should be considered as
# dropped directly on parent."
# Moving items to row -1 would put them before the last item. Fix the row to drop the
# dragged items after the last item.
if row < 0:
row = len(self.model) - 1
strMimeData = bytes(mimeData.data(MIME_INDEXES)).decode()
indexes = list(map(int, strMimeData.split(",")))
self.model.move_indexes(indexes, row)
self.view.selectionModel().clearSelection()
return True
def mimeData(self, indexes):
@@ -84,7 +91,9 @@ class PrioritizeDialog(QDialog):
self.model.view = self
self.addCriteriaButton.clicked.connect(self.model.add_selected)
self.criteriaListView.doubleClicked.connect(self.model.add_selected)
self.removeCriteriaButton.clicked.connect(self.model.remove_selected)
self.prioritizationListView.doubleClicked.connect(self.model.remove_selected)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
@@ -102,6 +111,7 @@ class PrioritizeDialog(QDialog):
self.promptLabel.setWordWrap(True)
self.categoryCombobox = QComboBox()
self.criteriaListView = QListView()
self.criteriaListView.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.addCriteriaButton = QPushButton(
self.style().standardIcon(QStyle.SP_ArrowRight), ""
)
@@ -113,6 +123,7 @@ class PrioritizeDialog(QDialog):
self.prioritizationListView.setDragEnabled(True)
self.prioritizationListView.setDragDropMode(QAbstractItemView.InternalMove)
self.prioritizationListView.setSelectionBehavior(QAbstractItemView.SelectRows)
self.prioritizationListView.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.buttonBox = QDialogButtonBox()
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)

View File

@@ -58,9 +58,10 @@ 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 (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!"
"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!"
"\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

@@ -6,11 +6,14 @@
# which should be included with this package. The terms are also available at
# http://www.gnu.org/licenses/gpl-3.0.html
from PyQt5.QtCore import Qt, QSettings, QRect, QObject, pyqtSignal
from PyQt5.QtCore import Qt, QSettings, QRect, QObject, pyqtSignal, QStandardPaths
from PyQt5.QtWidgets import QDockWidget
from hscommon.trans import trget
from hscommon.util import tryint
from hscommon.plat import ISWINDOWS
from os import path as op
tr = trget("qtlib")
@@ -74,7 +77,18 @@ class Preferences(QObject):
def __init__(self):
QObject.__init__(self)
self.reset()
self._settings = QSettings()
# On windows use an ini file in the AppDataLocation instead of registry if possible as it
# makes it easier for a user to clear it out when there are issues.
if ISWINDOWS:
Locations = QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)
if Locations:
self._settings = QSettings(
op.join(Locations[0], "settings.ini"), QSettings.IniFormat
)
else:
self._settings = QSettings()
else:
self._settings = QSettings()
def _load_values(self, settings, get):
pass

View File

@@ -2,4 +2,4 @@ pytest>=5,<6
flake8
tox-travis
black
pyinstaller>=4.0,<5.0; sys_platform == 'win32'
pyinstaller>=4.0,<5.0; sys_platform != 'linux'

View File

@@ -1,3 +0,0 @@
PyQt5 >=5.4,<6.0
pywin32>=200
pyinstaller>=3.4,<4.0

View File

@@ -1,7 +1,7 @@
Send2Trash>=1.3.0
sphinx>=1.2.2
polib>=1.0.4
hsaudiotag3k>=1.1.3
hsaudiotag3k>=1.1.3*
distro>=1.5.0
PyQt5 >=5.4,<6.0; sys_platform == 'win32'
PyQt5 >=5.4,<6.0; sys_platform != 'linux'
pywin32>=200; sys_platform == 'win32'

View File

@@ -1,21 +0,0 @@
#!/bin/bash
echo "Creating git archive"
version=`python -c "from hscommon.build import get_module_version; print(get_module_version('core'))"`
dest="dupeguru-src-${version}.tar"
git archive -o ${dest} HEAD
# Now, we need to include submodules
submodules="cocoalib"
for submodule in $submodules; do
echo "Adding submodule ${submodule} to archive"
archive_name="${submodule}.tar"
git -C ${submodule} archive -o ../${archive_name} --prefix ${submodule}/ HEAD
tar -A ${archive_name} -f ${dest}
rm ${archive_name}
done
xz ${dest}
echo "Built source package ${dest}.xz"

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 "http://www.hardcoded.net/support/"
!define UPDATEURL "http://www.hardcoded.net/dupeguru/"
!define ABOUTURL "http://www.hardcoded.net/dupeguru/"
!define HELPURL "https://github.com/arsenetar/dupeguru/issues"
!define UPDATEURL "https://dupeguru.voltaicideas.net/"
!define ABOUTURL "https://dupeguru.voltaicideas.net/"
; Static Defines
!define UNINSTALLREGBASE "Software\Microsoft\Windows\CurrentVersion\Uninstall"