From 21b08252d3569848eab4178597585b686b0a332c Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Wed, 21 Feb 2018 15:19:18 +1100 Subject: [PATCH 1/8] Use the QListWidgetItems for building lists of filenames. Set, but avoid displaying, the QString from Qt.DisplayRole which is necessary for correct sorting in the list --- onionshare_gui/file_selection.py | 20 ++++++++++++-------- onionshare_gui/onionshare_gui.py | 9 ++++++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py index f08073db..4f4c43f2 100644 --- a/onionshare_gui/file_selection.py +++ b/onionshare_gui/file_selection.py @@ -94,7 +94,7 @@ class FileList(QtWidgets.QListWidget): Update the GUI elements based on the current state. """ # file list should have a background image if empty - if len(self.filenames) == 0: + if self.count() == 0: self.drop_here_image.show() self.drop_here_text.show() else: @@ -193,15 +193,14 @@ class FileList(QtWidgets.QListWidget): """ Add a file or directory to this widget. """ + for index in range(self.count()): + self.filenames.append(self.item(index)) + if filename not in self.filenames: if not os.access(filename, os.R_OK): Alert(strings._("not_a_readable_file", True).format(filename)) return - self.filenames.append(filename) - # Re-sort the list internally - self.filenames.sort() - fileinfo = QtCore.QFileInfo(filename) basename = os.path.basename(filename.rstrip('/')) ip = QtWidgets.QFileIconProvider() @@ -221,16 +220,22 @@ class FileList(QtWidgets.QListWidget): # Item's name and size labels item_name = QtWidgets.QLabel(basename) + item.filename = filename item_name.setWordWrap(False) item_name.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) item_name.setStyleSheet('QLabel { color: #000000; font-size: 13px; }') item_size = QtWidgets.QLabel(size_readable) item_size.setStyleSheet('QLabel { color: #666666; font-size: 11px; }') + # Use the basename as the method with which to sort the list + item.setData(QtCore.Qt.DisplayRole, basename) + # But we don't want to *display* the QString (we have our own QLabel), so paint over it. + item.brush = QtGui.QBrush(QtGui.QColor('white')) + item.setForeground(item.brush) + # Item's delete button def delete_item(): itemrow = self.row(item) - self.filenames.pop(itemrow) self.takeItem(itemrow) self.files_updated.emit() @@ -330,7 +335,6 @@ class FileSelection(QtWidgets.QVBoxLayout): selected = self.file_list.selectedItems() for item in selected: itemrow = self.file_list.row(item) - self.file_list.filenames.pop(itemrow) self.file_list.takeItem(itemrow) self.file_list.files_updated.emit() @@ -357,7 +361,7 @@ class FileSelection(QtWidgets.QVBoxLayout): """ Returns the total number of files and folders in the list. """ - return len(self.file_list.filenames) + return len(range(self.count())) def setFocus(self): """ diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py index 323adabc..61c2abc0 100644 --- a/onionshare_gui/onionshare_gui.py +++ b/onionshare_gui/onionshare_gui.py @@ -410,8 +410,11 @@ class OnionShareGui(QtWidgets.QMainWindow): # add progress bar to the status bar, indicating the crunching of files. self._zip_progress_bar = ZipProgressBar(0) - self._zip_progress_bar.total_files_size = OnionShareGui._compute_total_size( - self.file_selection.file_list.filenames) + self.filenames = [] + for index in range(self.file_selection.file_list.count()): + self.filenames.append(self.file_selection.file_list.item(index).filename) + + self._zip_progress_bar.total_files_size = OnionShareGui._compute_total_size(self.filenames) self.status_bar.insertWidget(0, self._zip_progress_bar) # prepare the files for sending in a new thread @@ -421,7 +424,7 @@ class OnionShareGui(QtWidgets.QMainWindow): if self._zip_progress_bar != None: self._zip_progress_bar.update_processed_size_signal.emit(x) try: - web.set_file_info(self.file_selection.file_list.filenames, processed_size_callback=_set_processed_size) + web.set_file_info(self.filenames, processed_size_callback=_set_processed_size) self.app.cleanup_filenames.append(web.zip_filename) self.starting_server_step3.emit() From fd4bc51ec294d4ae058cea28ade86efbdf0b2868 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Wed, 21 Feb 2018 15:29:56 +1100 Subject: [PATCH 2/8] fix appending of filenames when checking that a file hasn't already been added to the list --- onionshare_gui/file_selection.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py index 4f4c43f2..270baef7 100644 --- a/onionshare_gui/file_selection.py +++ b/onionshare_gui/file_selection.py @@ -82,8 +82,6 @@ class FileList(QtWidgets.QListWidget): self.setMinimumHeight(205) self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - self.filenames = [] - self.drop_here_image = DropHereLabel(self, True) self.drop_here_text = DropHereLabel(self, False) self.drop_count = DropCountLabel(self) @@ -194,9 +192,9 @@ class FileList(QtWidgets.QListWidget): Add a file or directory to this widget. """ for index in range(self.count()): - self.filenames.append(self.item(index)) + filenames.append(self.item(index).filename) - if filename not in self.filenames: + if filename not in filenames: if not os.access(filename, os.R_OK): Alert(strings._("not_a_readable_file", True).format(filename)) return From 6815665f1d69d83181a9774d5f94cb3ffacb9d85 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Wed, 21 Feb 2018 15:47:21 +1100 Subject: [PATCH 3/8] Instantiate empty filenames list --- onionshare_gui/file_selection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py index 270baef7..2a024620 100644 --- a/onionshare_gui/file_selection.py +++ b/onionshare_gui/file_selection.py @@ -191,6 +191,7 @@ class FileList(QtWidgets.QListWidget): """ Add a file or directory to this widget. """ + filenames = [] for index in range(self.count()): filenames.append(self.item(index).filename) From 921565158261207b4d4254cb682bea3766c6696d Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 22 Feb 2018 14:37:31 +1100 Subject: [PATCH 4/8] Remove the item_name QLabel widget and just let the QListWidgetItem text() display as title. Trim super-long filenames --- onionshare_gui/file_selection.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py index 2a024620..6d4d8b15 100644 --- a/onionshare_gui/file_selection.py +++ b/onionshare_gui/file_selection.py @@ -86,6 +86,7 @@ class FileList(QtWidgets.QListWidget): self.drop_here_text = DropHereLabel(self, False) self.drop_count = DropCountLabel(self) self.resizeEvent(None) + self.setStyleSheet('QListWidget::item { color: #000000; font-size: 13px; }') def update(self): """ @@ -202,6 +203,8 @@ class FileList(QtWidgets.QListWidget): fileinfo = QtCore.QFileInfo(filename) basename = os.path.basename(filename.rstrip('/')) + if len(basename) > 35: + basename = basename[:35] + '...' ip = QtWidgets.QFileIconProvider() icon = ip.icon(fileinfo) @@ -217,20 +220,13 @@ class FileList(QtWidgets.QListWidget): item.setIcon(icon) item.size_bytes = size_bytes - # Item's name and size labels - item_name = QtWidgets.QLabel(basename) + # Item's filename attribute and size labels item.filename = filename - item_name.setWordWrap(False) - item_name.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Fixed) - item_name.setStyleSheet('QLabel { color: #000000; font-size: 13px; }') item_size = QtWidgets.QLabel(size_readable) item_size.setStyleSheet('QLabel { color: #666666; font-size: 11px; }') # Use the basename as the method with which to sort the list item.setData(QtCore.Qt.DisplayRole, basename) - # But we don't want to *display* the QString (we have our own QLabel), so paint over it. - item.brush = QtGui.QBrush(QtGui.QColor('white')) - item.setForeground(item.brush) # Item's delete button def delete_item(): @@ -246,11 +242,9 @@ class FileList(QtWidgets.QListWidget): item.item_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) # Create the item's widget and layouts - item_vlayout = QtWidgets.QVBoxLayout() - item_vlayout.addWidget(item_name) - item_vlayout.addWidget(item_size) item_hlayout = QtWidgets.QHBoxLayout() - item_hlayout.addLayout(item_vlayout) + item_hlayout.addStretch() + item_hlayout.addWidget(item_size) item_hlayout.addWidget(item.item_button) widget = QtWidgets.QWidget() widget.setLayout(item_hlayout) From 6998aec50a288e23ecf8233c5ef6c58226055d5a Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Thu, 22 Feb 2018 14:44:00 +1100 Subject: [PATCH 5/8] Force a scrollbar on the file list widget. Not pretty but avoids weird text disappearance on resize when scrollbar otherwise activates --- onionshare_gui/file_selection.py | 1 + 1 file changed, 1 insertion(+) diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py index 6d4d8b15..d39f9ac4 100644 --- a/onionshare_gui/file_selection.py +++ b/onionshare_gui/file_selection.py @@ -86,6 +86,7 @@ class FileList(QtWidgets.QListWidget): self.drop_here_text = DropHereLabel(self, False) self.drop_count = DropCountLabel(self) self.resizeEvent(None) + self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.setStyleSheet('QListWidget::item { color: #000000; font-size: 13px; }') def update(self): From 22c301fd9c4a8a5e3759f98c64934eacbec5bb29 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Thu, 22 Feb 2018 09:55:04 -0800 Subject: [PATCH 6/8] Stop trimming filenames, and instead create item info with a white background --- onionshare_gui/file_selection.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py index d39f9ac4..5b621478 100644 --- a/onionshare_gui/file_selection.py +++ b/onionshare_gui/file_selection.py @@ -81,13 +81,18 @@ class FileList(QtWidgets.QListWidget): self.setSortingEnabled(True) self.setMinimumHeight(205) self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - self.drop_here_image = DropHereLabel(self, True) self.drop_here_text = DropHereLabel(self, False) self.drop_count = DropCountLabel(self) self.resizeEvent(None) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) - self.setStyleSheet('QListWidget::item { color: #000000; font-size: 13px; }') + self.setStyleSheet( + """ + QListWidget::item { background-color: #ffffff; color: #000000; font-size: 13px; } + QListWidget::item:selected { background-color: #ddddff; } + QWidget#item-info { background-color: #ffffff; } + """ + ) def update(self): """ @@ -204,8 +209,6 @@ class FileList(QtWidgets.QListWidget): fileinfo = QtCore.QFileInfo(filename) basename = os.path.basename(filename.rstrip('/')) - if len(basename) > 35: - basename = basename[:35] + '...' ip = QtWidgets.QFileIconProvider() icon = ip.icon(fileinfo) @@ -242,11 +245,18 @@ class FileList(QtWidgets.QListWidget): item.item_button.clicked.connect(delete_item) item.item_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + # Item info widget, with a white background + item_info_layout = QtWidgets.QHBoxLayout() + item_info_layout.addWidget(item_size) + item_info_layout.addWidget(item.item_button) + item_info = QtWidgets.QWidget() + item_info.setObjectName('item-info') + item_info.setLayout(item_info_layout) + # Create the item's widget and layouts item_hlayout = QtWidgets.QHBoxLayout() item_hlayout.addStretch() - item_hlayout.addWidget(item_size) - item_hlayout.addWidget(item.item_button) + item_hlayout.addWidget(item_info) widget = QtWidgets.QWidget() widget.setLayout(item_hlayout) From 1967d50707215a4208e8c8cf640073bde06cd829 Mon Sep 17 00:00:00 2001 From: Micah Lee Date: Thu, 22 Feb 2018 10:02:52 -0800 Subject: [PATCH 7/8] Make the item-info boxes have an obvious style --- onionshare_gui/file_selection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py index 5b621478..34771689 100644 --- a/onionshare_gui/file_selection.py +++ b/onionshare_gui/file_selection.py @@ -90,7 +90,7 @@ class FileList(QtWidgets.QListWidget): """ QListWidget::item { background-color: #ffffff; color: #000000; font-size: 13px; } QListWidget::item:selected { background-color: #ddddff; } - QWidget#item-info { background-color: #ffffff; } + QWidget#item-info { background-color: #fbfbfb; border: 1px solid #f0f0f0; border-radius: 5px; } """ ) From ade9a452a3ce005ed5baf18913e4a529144371f7 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Fri, 23 Feb 2018 10:49:43 +1100 Subject: [PATCH 8/8] Remove our custom stylesheeting, and just trim long names, allowing them to untrim as the window resizes --- onionshare_gui/file_selection.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py index 34771689..6fee2c77 100644 --- a/onionshare_gui/file_selection.py +++ b/onionshare_gui/file_selection.py @@ -86,13 +86,6 @@ class FileList(QtWidgets.QListWidget): self.drop_count = DropCountLabel(self) self.resizeEvent(None) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) - self.setStyleSheet( - """ - QListWidget::item { background-color: #ffffff; color: #000000; font-size: 13px; } - QListWidget::item:selected { background-color: #ddddff; } - QWidget#item-info { background-color: #fbfbfb; border: 1px solid #f0f0f0; border-radius: 5px; } - """ - ) def update(self): """ @@ -141,6 +134,15 @@ class FileList(QtWidgets.QListWidget): self.takeItem(self.row(item)) self.update() + # Extend any filenames that were truncated to fit the window + # We use 200 as a rough guess at how wide the 'file size + delete button' widget is + # and extend based on the overall width minus that amount. + for index in range(self.count()): + metrics = QtGui.QFontMetrics(self.item(index).font()) + elided = metrics.elidedText(self.item(index).basename, QtCore.Qt.ElideRight, self.width() - 200) + self.item(index).setText(elided) + + def dragEnterEvent(self, event): """ dragEnterEvent for dragging files and directories into the widget. @@ -208,7 +210,6 @@ class FileList(QtWidgets.QListWidget): return fileinfo = QtCore.QFileInfo(filename) - basename = os.path.basename(filename.rstrip('/')) ip = QtWidgets.QFileIconProvider() icon = ip.icon(fileinfo) @@ -229,8 +230,11 @@ class FileList(QtWidgets.QListWidget): item_size = QtWidgets.QLabel(size_readable) item_size.setStyleSheet('QLabel { color: #666666; font-size: 11px; }') + item.basename = os.path.basename(filename.rstrip('/')) # Use the basename as the method with which to sort the list - item.setData(QtCore.Qt.DisplayRole, basename) + metrics = QtGui.QFontMetrics(item.font()) + elided = metrics.elidedText(item.basename, QtCore.Qt.ElideRight, self.sizeHint().width()) + item.setData(QtCore.Qt.DisplayRole, elided) # Item's delete button def delete_item():