-
Notifications
You must be signed in to change notification settings - Fork 2
/
FF_Compare.py
284 lines (228 loc) 路 10.7 KB
/
FF_Compare.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# This source file is a part of File Find made by Pixel-Master
#
# Copyright 2022-2024 Pixel-Master
#
# 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
# This file contains the code for the 'Compare Search' feature
# Imports
from json import load
import logging
import os
# PySide6 Gui Imports
from PySide6.QtGui import QFont
from PySide6.QtCore import QObject, Signal, QThreadPool, QSize
from PySide6.QtWidgets import (
QMainWindow, QFileDialog, QListWidget, QLabel, QPushButton, QWidget, QGridLayout, QHBoxLayout)
# Projects Libraries
import FF_Additional_UI
import FF_Files
import FF_Menubar
# The window
class CompareUi:
def __init__(self, path_of_first_search, parent):
# Debug
logging.info("Setting up the Compare_Window")
# Set up the Window
self.Compare_Window = QMainWindow(parent)
# Set up the window title
self.Compare_Window.setWindowTitle(
f"File Find | Comparing Searches: "
f"{FF_Files.display_path(path_of_first_search, 15)} (base) --> "
f"{FF_Files.display_path(compared_searches.path_of_second_search[0], 15)}")
# Set the start size of the Window, because it's resizable
self.BASE_WIDTH = 800
self.BASE_HEIGHT = 700
self.Compare_Window.setBaseSize(self.BASE_WIDTH, self.BASE_HEIGHT)
# Display the window
self.Compare_Window.show()
# Adding Layouts
# Main Layout
# Create a central widget
self.Central_Widget = QWidget(self.Compare_Window)
self.Compare_Window.setCentralWidget(self.Central_Widget)
# Create the main Layout
self.Compare_Layout = QGridLayout(self.Central_Widget)
self.Compare_Layout.setContentsMargins(20, 20, 20, 20)
self.Compare_Layout.setVerticalSpacing(1)
# Listbox Layout
self.Listbox_Layout = QHBoxLayout(self.Compare_Window)
self.Listbox_Layout.setContentsMargins(0, 0, 0, 0)
# Add to main Layout
self.Compare_Layout.addLayout(self.Listbox_Layout, 2, 0, 8, 2)
# Bottom Layout
self.Bottom_Layout = QHBoxLayout(self.Compare_Window)
self.Bottom_Layout.setContentsMargins(0, 20, 0, 0)
# Add to main Layout
self.Compare_Layout.addLayout(self.Bottom_Layout, 10, 0, 1, 2)
# Setting up the menu bar...
menu_bar = FF_Menubar.MenuBar(parent=self.Compare_Window, window="compare",
listbox=None, )
logging.debug("Done building MenuBar\n")
# Set up both list-boxes
# Added files / files only in first search
# Debug
logging.debug("Setting up Added files / files only in first search listbox..")
self.added_files_listbox = QListWidget(self.Compare_Window)
# Adding to grid
self.Listbox_Layout.addWidget(self.added_files_listbox)
# Show the Listbox
self.added_files_listbox.show()
# Add items
self.added_files_listbox.addItems(compared_searches.files_only_in_first_search)
# Double-Clicking Event
self.added_files_listbox.doubleClicked.connect(menu_bar.open_in_finder)
# Removed files / files only in second search
# Debug
logging.debug("Done!, Setting up Removed files / files only in second search listbox..")
self.removed_files_listbox = QListWidget(self.Compare_Window)
# Adding to grid
self.Listbox_Layout.addWidget(self.removed_files_listbox)
# Show the Listbox
self.removed_files_listbox.show()
# Add items
self.removed_files_listbox.addItems(compared_searches.files_only_in_second_search)
# Double-Clicking Event
self.removed_files_listbox.doubleClicked.connect(menu_bar.open_in_finder)
# Debug
logging.debug("Done!")
# Labels
# Added files
self.added_files_label1, self.added_files_label2 = self.generate_title_label(
text="Added Files", text2=path_of_first_search, color=FF_Files.GREEN_COLOR)
self.Compare_Layout.addWidget(self.added_files_label1, 0, 0)
self.Compare_Layout.addWidget(self.added_files_label2, 1, 0)
# Removed files
self.removed_files_label1, self.removed_files_label2 = self.generate_title_label(
text="Removed Files", text2=compared_searches.path_of_second_search[0], color=FF_Files.RED_COLOR)
self.Compare_Layout.addWidget(self.removed_files_label1, 0, 1)
self.Compare_Layout.addWidget(self.removed_files_label2, 1, 1)
# Buttons
# Button to open the File in Finder
move_file = self.generate_button("Move / Rename", menu_bar.move_file,
icon=os.path.join(FF_Files.ASSETS_FOLDER, "Move_icon_small.png"))
self.Bottom_Layout.addWidget(move_file)
# Button to move the file to trash
delete_file = self.generate_button("Move to Trash", menu_bar.delete_file,
icon=os.path.join(FF_Files.ASSETS_FOLDER, "Trash_icon_small.png"))
self.Bottom_Layout.addWidget(delete_file)
# Button to open the file
open_file = self.generate_button("Open", menu_bar.open_file,
icon=os.path.join(FF_Files.ASSETS_FOLDER, "Open_icon_small.png"))
self.Bottom_Layout.addWidget(open_file)
# Button to show info about the file
file_info_button = self.generate_button("Info", menu_bar.file_info,
icon=os.path.join(FF_Files.ASSETS_FOLDER, "Info_button_img_small.png"))
self.Bottom_Layout.addWidget(file_info_button)
# Debug
logging.info("Done building Compare-UI!\n")
# Functions to automate Button
def generate_button(self, text, command, icon=None):
# Define the Button
button = QPushButton(self.Compare_Window)
# Change the Text
button.setText(text)
# Set the command
button.clicked.connect(command)
# Set the icon
if icon is not None:
FF_Additional_UI.UIIcon(icon, button.setIcon)
button.setIconSize(QSize(23, 22))
# Return the value of the Button, to move the Button
return button
# Function for generating the added / removed files labels
def generate_title_label(self, text, text2, color) -> tuple[QLabel, QLabel]:
# Label 1
label1 = QLabel(self.Compare_Window)
# Defining the font
font1 = QFont(FF_Files.DEFAULT_FONT, FF_Files.TITLE_FONT_SIZE)
font1.setBold(True)
# Set the text, the font and the color
label1.setText(text)
label1.setFont(font1)
label1.setStyleSheet(f"color: {color};")
label1.setFixedHeight(40)
# Label 2
label2 = QLabel(self.Compare_Window)
# Set the text, the font and the color
# Shorten the text string to only include the first to the 30th
# and the last ten character if the string is longer then 43 characters
text2_shortened = f"Files only in:\n{FF_Files.display_path(text2)}"
# Set the label to the shortened string
label2.setText(text2_shortened)
# Defining the font
font2 = QFont(FF_Files.DEFAULT_FONT, FF_Files.SMALLER_FONT_SIZE)
# Configure the font
label2.setFont(font2)
return label1, label2
# The engine
class CompareSearches:
def __init__(self, files_of_first_search: list, path_of_first_search, parent):
# Debug
logging.debug("User pressed Compare Search")
try:
# Setting the thread up with the Qt6 signals to launch the ui
class SignalsClass(QObject):
finished = Signal()
self.signals = SignalsClass()
# Connecting the signal to the user-interface class
self.signals.finished.connect(lambda: CompareUi(path_of_first_search, parent))
# Thread
comparing_thread = QThreadPool(parent)
# Get the files of both searches
self.files_of_first_search = files_of_first_search
logging.debug("Asking for a second File Find Search file...")
self.files_of_second_search, self.path_of_second_search = self.load_second_search()
# Files which are only in one list
self.files_only_in_first_search = []
self.files_only_in_second_search = []
# Starting the thread
logging.debug("Starting thread...")
comparing_thread.start(self.compare)
except TypeError:
# If no file was selected
logging.info("No file was selected, when comparing files")
pass
def compare(self):
# Debug
logging.debug("Comparing searches...")
# Loop through the first list and test every file if it is in both lists
for file_in_first_list in self.files_of_first_search:
if not (file_in_first_list in self.files_of_second_search):
self.files_only_in_first_search.append(file_in_first_list)
else:
# If it is found delete file in second list
self.files_of_second_search.remove(file_in_first_list)
logging.debug("Done Looping!, Swapping...")
# In the second search are only files that don't appear in the first search
self.files_only_in_second_search = self.files_of_second_search
logging.debug("Done comparing searches!\n")
# Setting the global var compared_searches to self to include all 'self.' vars
global compared_searches
compared_searches = self
# Emitting the signal to launch the ui
logging.debug("Finished thread, Emitting finished signal!")
self.signals.finished.emit()
@staticmethod
def load_second_search():
# Get the user to select a valid search file
second_search_file = QFileDialog.getOpenFileName(
parent=None,
caption="Select Second Search",
dir=FF_Files.USER_FOLDER,
filter="*.FFSearch;")
# Debug
logging.debug(f"Second search: {second_search_file}, Reading file...")
# Load list from file and return path and files
try:
with open(second_search_file[0]) as search_file:
load_file_content = load(search_file)
# Debug
logging.info(f"Second search file has version: {load_file_content['VERSION']}")
# Return path and list of found files
return load_file_content["matched_list"], second_search_file
except FileNotFoundError:
# if the user pressed cancel
return None
compared_searches: CompareSearches