mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-02-03 20:01:38 +00:00
cocoa: merge se/me/pe into one single app
That merge has already been done in core and qt, we're following. I broke picture scan details panel image loading. Will fix later.
This commit is contained in:
@@ -6,6 +6,7 @@ from cocoa.inter import PyBaseApp, BaseAppView
|
||||
|
||||
class DupeGuruView(BaseAppView):
|
||||
def askYesNoWithPrompt_(self, prompt: str) -> bool: pass
|
||||
def createResultsWindow(self): pass
|
||||
def showResultsWindow(self): pass
|
||||
def showProblemDialog(self): pass
|
||||
def selectDestFolderWithPrompt_(self, prompt: str) -> str: pass
|
||||
@@ -123,6 +124,9 @@ class PyDupeGuruBase(PyBaseApp):
|
||||
def showIgnoreList(self):
|
||||
self.model.ignore_list_dialog.show()
|
||||
|
||||
def clearPictureCache(self):
|
||||
self.model.clear_picture_cache()
|
||||
|
||||
#---Information
|
||||
def getScanOptions(self) -> list:
|
||||
return [o.label for o in self.model.SCANNER_CLASS.get_scan_options()]
|
||||
@@ -130,7 +134,50 @@ class PyDupeGuruBase(PyBaseApp):
|
||||
def resultsAreModified(self) -> bool:
|
||||
return self.model.results.is_modified
|
||||
|
||||
def getSelectedDupePath(self) -> str:
|
||||
return str(self.model.selected_dupe_path())
|
||||
|
||||
def getSelectedDupeRefPath(self) -> str:
|
||||
return str(self.model.selected_dupe_ref_path())
|
||||
|
||||
#---Properties
|
||||
def getAppMode(self) -> int:
|
||||
return self.model.app_mode
|
||||
|
||||
def setAppMode_(self, app_mode: int):
|
||||
self.model.app_mode = app_mode
|
||||
|
||||
def setScanType_(self, scan_type_index: int):
|
||||
scan_options = self.model.SCANNER_CLASS.get_scan_options()
|
||||
try:
|
||||
so = scan_options[scan_type_index]
|
||||
self.model.options['scan_type'] = so.scan_type
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def setMinMatchPercentage_(self, percentage: int):
|
||||
self.model.options['min_match_percentage'] = int(percentage)
|
||||
|
||||
def setWordWeighting_(self, words_are_weighted: bool):
|
||||
self.model.options['word_weighting'] = words_are_weighted
|
||||
|
||||
def setMatchSimilarWords_(self, match_similar_words: bool):
|
||||
self.model.options['match_similar_words'] = match_similar_words
|
||||
|
||||
def setSizeThreshold_(self, size_threshold: int):
|
||||
self.model.options['size_threshold'] = size_threshold
|
||||
|
||||
def enable_scanForTag_(self, enable: bool, scan_tag: str):
|
||||
if 'scanned_tags' not in self.model.options:
|
||||
self.model.options['scanned_tags'] = set()
|
||||
if enable:
|
||||
self.model.options['scanned_tags'].add(scan_tag)
|
||||
else:
|
||||
self.model.options['scanned_tags'].discard(scan_tag)
|
||||
|
||||
def setMatchScaled_(self, match_scaled: bool):
|
||||
self.model.options['match_scaled'] = match_scaled
|
||||
|
||||
def setMixFileKind_(self, mix_file_kind: bool):
|
||||
self.model.options['mix_file_kind'] = mix_file_kind
|
||||
|
||||
@@ -151,6 +198,10 @@ class PyDupeGuruBase(PyBaseApp):
|
||||
def ask_yes_no(self, prompt):
|
||||
return self.callback.askYesNoWithPrompt_(prompt)
|
||||
|
||||
@dontwrap
|
||||
def create_results_window(self):
|
||||
self.callback.createResultsWindow()
|
||||
|
||||
@dontwrap
|
||||
def show_results_window(self):
|
||||
self.callback.showResultsWindow()
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# Copyright 2016 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
from hscommon.trans import trget
|
||||
|
||||
from core.scanner import ScanType
|
||||
from core_me.app import DupeGuru as DupeGuruME
|
||||
from .app import PyDupeGuruBase
|
||||
|
||||
tr = trget('ui')
|
||||
|
||||
class PyDupeGuru(PyDupeGuruBase):
|
||||
def __init__(self):
|
||||
self._init(DupeGuruME)
|
||||
|
||||
#---Properties
|
||||
def setMinMatchPercentage_(self, percentage: int):
|
||||
self.model.options['min_match_percentage'] = percentage
|
||||
|
||||
def setScanType_(self, scan_type: int):
|
||||
try:
|
||||
self.model.options['scan_type'] = [
|
||||
ScanType.Filename,
|
||||
ScanType.Fields,
|
||||
ScanType.FieldsNoOrder,
|
||||
ScanType.Tag,
|
||||
ScanType.Contents,
|
||||
ScanType.ContentsAudio,
|
||||
][scan_type]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def setWordWeighting_(self, words_are_weighted: bool):
|
||||
self.model.options['word_weighting'] = words_are_weighted
|
||||
|
||||
def setMatchSimilarWords_(self, match_similar_words: bool):
|
||||
self.model.options['match_similar_words'] = match_similar_words
|
||||
|
||||
def enable_scanForTag_(self, enable: bool, scan_tag: str):
|
||||
if 'scanned_tags' not in self.model.options:
|
||||
self.model.options['scanned_tags'] = set()
|
||||
if enable:
|
||||
self.model.options['scanned_tags'].add(scan_tag)
|
||||
else:
|
||||
self.model.options['scanned_tags'].discard(scan_tag)
|
||||
@@ -1,90 +0,0 @@
|
||||
# Copyright 2016 Hardcoded Software (http://www.hardcoded.net)
|
||||
#
|
||||
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
||||
# which should be included with this package. The terms are also available at
|
||||
# http://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
from cocoa import proxy
|
||||
|
||||
from core.scanner import ScanType
|
||||
from core_pe import _block_osx
|
||||
from core_pe.photo import Photo as PhotoBase
|
||||
from core_pe.app import DupeGuru as DupeGuruBase
|
||||
from .app import PyDupeGuruBase
|
||||
|
||||
|
||||
class Photo(PhotoBase):
|
||||
HANDLED_EXTS = PhotoBase.HANDLED_EXTS.copy()
|
||||
HANDLED_EXTS.update({'psd', 'nef', 'cr2', 'orf'})
|
||||
|
||||
def _plat_get_dimensions(self):
|
||||
return _block_osx.get_image_size(str(self.path))
|
||||
|
||||
def _plat_get_blocks(self, block_count_per_side, orientation):
|
||||
try:
|
||||
blocks = _block_osx.getblocks(str(self.path), block_count_per_side, orientation)
|
||||
except Exception as e:
|
||||
raise IOError('The reading of "%s" failed with "%s"' % (str(self.path), str(e)))
|
||||
if not blocks:
|
||||
raise IOError('The picture %s could not be read' % str(self.path))
|
||||
return blocks
|
||||
|
||||
def _get_exif_timestamp(self):
|
||||
exifdata = proxy.readExifData_(str(self.path))
|
||||
if exifdata:
|
||||
try:
|
||||
return exifdata['{Exif}']['DateTimeOriginal']
|
||||
except KeyError:
|
||||
return ''
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class DupeGuruPE(DupeGuruBase):
|
||||
def __init__(self, view):
|
||||
DupeGuruBase.__init__(self, view)
|
||||
self.fileclasses = [Photo]
|
||||
|
||||
def selected_dupe_path(self):
|
||||
if not self.selected_dupes:
|
||||
return None
|
||||
return self.selected_dupes[0].path
|
||||
|
||||
def selected_dupe_ref_path(self):
|
||||
if not self.selected_dupes:
|
||||
return None
|
||||
ref = self.results.get_group_of_duplicate(self.selected_dupes[0]).ref
|
||||
if ref is self.selected_dupes[0]: # we don't want the same pic to be displayed on both sides
|
||||
return None
|
||||
return ref.path
|
||||
|
||||
|
||||
class PyDupeGuru(PyDupeGuruBase):
|
||||
def __init__(self):
|
||||
self._init(DupeGuruPE)
|
||||
|
||||
def clearPictureCache(self):
|
||||
self.model.clear_picture_cache()
|
||||
|
||||
#---Information
|
||||
def getSelectedDupePath(self) -> str:
|
||||
return str(self.model.selected_dupe_path())
|
||||
|
||||
def getSelectedDupeRefPath(self) -> str:
|
||||
return str(self.model.selected_dupe_ref_path())
|
||||
|
||||
#---Properties
|
||||
def setScanType_(self, scan_type: int):
|
||||
try:
|
||||
self.model.options['scan_type'] = [
|
||||
ScanType.FuzzyBlock,
|
||||
ScanType.ExifTimestamp,
|
||||
][scan_type]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def setMatchScaled_(self, match_scaled: bool):
|
||||
self.model.options['match_scaled'] = match_scaled
|
||||
|
||||
def setMinMatchPercentage_(self, percentage: int):
|
||||
self.model.options['threshold'] = percentage
|
||||
@@ -12,10 +12,12 @@ import os.path as op
|
||||
from hscommon.path import Path, pathify
|
||||
from cocoa import proxy
|
||||
|
||||
from core.scanner import ScanType
|
||||
from core.directories import Directories as DirectoriesBase, DirectoryState
|
||||
from core_se.app import DupeGuru as DupeGuruBase
|
||||
from core_se import fs
|
||||
import core.pe.photo
|
||||
from core.pe import _block_osx
|
||||
from core.pe.photo import Photo as PhotoBase
|
||||
from core.app import DupeGuru as DupeGuruBase, AppMode
|
||||
from core.se import fs
|
||||
from .app import PyDupeGuruBase
|
||||
|
||||
def is_bundle(str_path):
|
||||
@@ -31,13 +33,37 @@ class Bundle(fs.Folder):
|
||||
return not path.islink() and path.isdir() and is_bundle(str(path))
|
||||
|
||||
|
||||
class Photo(PhotoBase):
|
||||
HANDLED_EXTS = PhotoBase.HANDLED_EXTS.copy()
|
||||
HANDLED_EXTS.update({'psd', 'nef', 'cr2', 'orf'})
|
||||
|
||||
def _plat_get_dimensions(self):
|
||||
return _block_osx.get_image_size(str(self.path))
|
||||
|
||||
def _plat_get_blocks(self, block_count_per_side, orientation):
|
||||
try:
|
||||
blocks = _block_osx.getblocks(str(self.path), block_count_per_side, orientation)
|
||||
except Exception as e:
|
||||
raise IOError('The reading of "%s" failed with "%s"' % (str(self.path), str(e)))
|
||||
if not blocks:
|
||||
raise IOError('The picture %s could not be read' % str(self.path))
|
||||
return blocks
|
||||
|
||||
def _get_exif_timestamp(self):
|
||||
exifdata = proxy.readExifData_(str(self.path))
|
||||
if exifdata:
|
||||
try:
|
||||
return exifdata['{Exif}']['DateTimeOriginal']
|
||||
except KeyError:
|
||||
return ''
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
class Directories(DirectoriesBase):
|
||||
ROOT_PATH_TO_EXCLUDE = list(map(Path, ['/Library', '/Volumes', '/System', '/bin', '/sbin', '/opt', '/private', '/dev']))
|
||||
HOME_PATH_TO_EXCLUDE = [Path('Library')]
|
||||
def __init__(self):
|
||||
DirectoriesBase.__init__(self)
|
||||
self.folderclass = fs.Folder
|
||||
|
||||
|
||||
def _default_state_for_path(self, path):
|
||||
result = DirectoriesBase._default_state_for_path(self, path)
|
||||
if result is not None:
|
||||
@@ -58,8 +84,7 @@ class Directories(DirectoriesBase):
|
||||
yield from_folder
|
||||
return
|
||||
else:
|
||||
for folder in DirectoriesBase._get_folders(self, from_folder, j):
|
||||
yield folder
|
||||
yield from DirectoriesBase._get_folders(self, from_folder, j)
|
||||
|
||||
@staticmethod
|
||||
def get_subfolders(path):
|
||||
@@ -69,37 +94,31 @@ class Directories(DirectoriesBase):
|
||||
|
||||
class DupeGuru(DupeGuruBase):
|
||||
def __init__(self, view):
|
||||
# appdata = op.join(appdata, 'dupeGuru')
|
||||
# print(repr(appdata))
|
||||
DupeGuruBase.__init__(self, view)
|
||||
self.fileclasses = [Bundle, fs.File]
|
||||
self.directories = Directories()
|
||||
|
||||
def selected_dupe_path(self):
|
||||
if not self.selected_dupes:
|
||||
return None
|
||||
return self.selected_dupes[0].path
|
||||
|
||||
def selected_dupe_ref_path(self):
|
||||
if not self.selected_dupes:
|
||||
return None
|
||||
ref = self.results.get_group_of_duplicate(self.selected_dupes[0]).ref
|
||||
if ref is self.selected_dupes[0]: # we don't want the same pic to be displayed on both sides
|
||||
return None
|
||||
return ref.path
|
||||
|
||||
def _get_fileclasses(self):
|
||||
result = DupeGuruBase._get_fileclasses(self)
|
||||
if self.app_mode == AppMode.Standard:
|
||||
result = [Bundle] + result
|
||||
return result
|
||||
|
||||
class PyDupeGuru(PyDupeGuruBase):
|
||||
def __init__(self):
|
||||
core.pe.photo.PLAT_SPECIFIC_PHOTO_CLASS = Photo
|
||||
self._init(DupeGuru)
|
||||
|
||||
#---Properties
|
||||
def setMinMatchPercentage_(self, percentage: int):
|
||||
self.model.options['min_match_percentage'] = int(percentage)
|
||||
|
||||
def setScanType_(self, scan_type: int):
|
||||
try:
|
||||
self.model.options['scan_type'] = [
|
||||
ScanType.Filename,
|
||||
ScanType.Contents,
|
||||
ScanType.Folders,
|
||||
][scan_type]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def setWordWeighting_(self, words_are_weighted: bool):
|
||||
self.model.options['word_weighting'] = words_are_weighted
|
||||
|
||||
def setMatchSimilarWords_(self, match_similar_words: bool):
|
||||
self.model.options['match_similar_words'] = match_similar_words
|
||||
|
||||
def setSizeThreshold_(self, size_threshold: int):
|
||||
self.model.options['size_threshold'] = size_threshold
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user