Browse Source

- COSMETIC: New deletion confirmation dialog (Merged delete/delete permanently actions)

- Delete useless properties button in top tool bar
- Set Alt+P keyboard shortcut to toggle torrent properties visibility
adaptive-webui-19844
Christophe Dumez 15 years ago
parent
commit
623933e2aa
  1. 1
      Changelog
  2. 5
      src/GUI.cpp
  3. BIN
      src/Icons/oxygen/dialog-warning.png
  4. 17
      src/MainWindow.ui
  5. 37
      src/TransferListWidget.cpp
  6. 1
      src/TransferListWidget.h
  7. 10
      src/bittorrent.cpp
  8. 2
      src/bittorrent.h
  9. 123
      src/confirmdeletiondlg.ui
  10. 60
      src/deletionconfirmationdlg.h
  11. 1
      src/icons.qrc
  12. 1
      src/propertieswidget.cpp
  13. 7
      src/src.pro

1
Changelog

@ -31,6 +31,7 @@
- COSMETIC: Made program preferences scrollable for usability on small screens (e.g. netbooks) - COSMETIC: Made program preferences scrollable for usability on small screens (e.g. netbooks)
- COSMETIC: Added a "torrent status" column to transfer list - COSMETIC: Added a "torrent status" column to transfer list
- COSMETIC: Display Seeds and Peers in two separate columns - COSMETIC: Display Seeds and Peers in two separate columns
- COSMETIC: New deletion confirmation dialog (Merged delete/delete permanently actions)
* Thu Sep 3 2009 - Christophe Dumez <chris@qbittorrent.org> - v1.5.0 * Thu Sep 3 2009 - Christophe Dumez <chris@qbittorrent.org> - v1.5.0
- FEATURE: Added Magnet URI support - FEATURE: Added Magnet URI support

5
src/GUI.cpp

@ -121,8 +121,6 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
prioSeparator2 = menu_Edit->insertSeparator(actionDecreasePriority); prioSeparator2 = menu_Edit->insertSeparator(actionDecreasePriority);
prioSeparator->setVisible(false); prioSeparator->setVisible(false);
prioSeparator2->setVisible(false); prioSeparator2->setVisible(false);
actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")));
actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png")));
actionCreate_torrent->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/new.png"))); actionCreate_torrent->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/new.png")));
// Fix Tool bar layout // Fix Tool bar layout
toolBar->layout()->setSpacing(7); toolBar->layout()->setSpacing(7);
@ -158,7 +156,6 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis
connect(actionPause, SIGNAL(triggered()), transferList, SLOT(pauseSelectedTorrents())); connect(actionPause, SIGNAL(triggered()), transferList, SLOT(pauseSelectedTorrents()));
connect(actionPause_All, SIGNAL(triggered()), transferList, SLOT(pauseAllTorrents())); connect(actionPause_All, SIGNAL(triggered()), transferList, SLOT(pauseAllTorrents()));
connect(actionDelete, SIGNAL(triggered()), transferList, SLOT(deleteSelectedTorrents())); connect(actionDelete, SIGNAL(triggered()), transferList, SLOT(deleteSelectedTorrents()));
connect(actionDelete_Permanently, SIGNAL(triggered()), transferList, SLOT(deletePermSelectedTorrents()));
connect(actionIncreasePriority, SIGNAL(triggered()), transferList, SLOT(increasePrioSelectedTorrents())); connect(actionIncreasePriority, SIGNAL(triggered()), transferList, SLOT(increasePrioSelectedTorrents()));
connect(actionDecreasePriority, SIGNAL(triggered()), transferList, SLOT(decreasePrioSelectedTorrents())); connect(actionDecreasePriority, SIGNAL(triggered()), transferList, SLOT(decreasePrioSelectedTorrents()));
@ -397,10 +394,8 @@ void GUI::createKeyboardShortcuts() {
connect(switchSearchShortcut2, SIGNAL(activated()), this, SLOT(displaySearchTab())); connect(switchSearchShortcut2, SIGNAL(activated()), this, SLOT(displaySearchTab()));
switchRSSShortcut = new QShortcut(QKeySequence(tr("Alt+4", "shortcut to switch to fourth tab")), this); switchRSSShortcut = new QShortcut(QKeySequence(tr("Alt+4", "shortcut to switch to fourth tab")), this);
connect(switchRSSShortcut, SIGNAL(activated()), this, SLOT(displayRSSTab())); connect(switchRSSShortcut, SIGNAL(activated()), this, SLOT(displayRSSTab()));
actionTorrent_Properties->setShortcut(QKeySequence(QString::fromUtf8("Alt+P")));
actionOptions->setShortcut(QKeySequence(QString::fromUtf8("Alt+O"))); actionOptions->setShortcut(QKeySequence(QString::fromUtf8("Alt+O")));
actionDelete->setShortcut(QKeySequence(QString::fromUtf8("Del"))); actionDelete->setShortcut(QKeySequence(QString::fromUtf8("Del")));
actionDelete_Permanently->setShortcut(QKeySequence(QString::fromUtf8("Shift+Del")));
actionStart->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+S"))); actionStart->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+S")));
actionStart_All->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Shift+S"))); actionStart_All->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+Shift+S")));
actionPause->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+P"))); actionPause->setShortcut(QKeySequence(QString::fromUtf8("Ctrl+P")));

BIN
src/Icons/oxygen/dialog-warning.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

17
src/MainWindow.ui

@ -25,7 +25,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>914</width> <width>914</width>
<height>23</height> <height>27</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menu_Edit"> <widget class="QMenu" name="menu_Edit">
@ -38,10 +38,8 @@
<addaction name="actionStart"/> <addaction name="actionStart"/>
<addaction name="actionPause"/> <addaction name="actionPause"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionTorrent_Properties"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionDelete"/> <addaction name="actionDelete"/>
<addaction name="actionDelete_Permanently"/>
<addaction name="actionDecreasePriority"/> <addaction name="actionDecreasePriority"/>
<addaction name="actionIncreasePriority"/> <addaction name="actionIncreasePriority"/>
</widget> </widget>
@ -107,9 +105,6 @@
<addaction name="actionDownload_from_URL"/> <addaction name="actionDownload_from_URL"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionDelete"/> <addaction name="actionDelete"/>
<addaction name="actionDelete_Permanently"/>
<addaction name="separator"/>
<addaction name="actionTorrent_Properties"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionStart"/> <addaction name="actionStart"/>
<addaction name="actionPause"/> <addaction name="actionPause"/>
@ -174,16 +169,6 @@
<string>Visit website</string> <string>Visit website</string>
</property> </property>
</action> </action>
<action name="actionDelete_Permanently">
<property name="text">
<string>Delete Permanently</string>
</property>
</action>
<action name="actionTorrent_Properties">
<property name="text">
<string>Torrent Properties</string>
</property>
</action>
<action name="actionDownload_from_URL"> <action name="actionDownload_from_URL">
<property name="text"> <property name="text">
<string>Download from URL</string> <string>Download from URL</string>

37
src/TransferListWidget.cpp

@ -35,6 +35,7 @@
#include "previewSelect.h" #include "previewSelect.h"
#include "speedlimitdlg.h" #include "speedlimitdlg.h"
#include "options_imp.h" #include "options_imp.h"
#include "deletionconfirmationdlg.h"
#include <QStandardItemModel> #include <QStandardItemModel>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QDesktopServices> #include <QDesktopServices>
@ -477,13 +478,8 @@ void TransferListWidget::pauseAllTorrents() {
void TransferListWidget::deleteSelectedTorrents() { void TransferListWidget::deleteSelectedTorrents() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows(); QModelIndexList selectedIndexes = selectionModel()->selectedRows();
if(!selectedIndexes.empty()) { if(!selectedIndexes.empty()) {
int ret = QMessageBox::question( bool delete_local_files = false;
this, if(DeletionConfirmationDlg::askForDeletionConfirmation(&delete_local_files)) {
tr("Deletion confirmation"),
tr("Are you sure you want to delete the selected torrents from transfer list?"),
tr("&Yes"), tr("&No"),
QString(), 0, 1);
if(ret) return;
QStringList hashes; QStringList hashes;
foreach(const QModelIndex &index, selectedIndexes) { foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash // Get the file hash
@ -491,33 +487,11 @@ void TransferListWidget::deleteSelectedTorrents() {
} }
foreach(const QString &hash, hashes) { foreach(const QString &hash, hashes) {
deleteTorrent(getRowFromHash(hash), false); deleteTorrent(getRowFromHash(hash), false);
BTSession->deleteTorrent(hash, false); BTSession->deleteTorrent(hash, delete_local_files);
} }
refreshList(); refreshList();
} }
} }
void TransferListWidget::deletePermSelectedTorrents() {
QModelIndexList selectedIndexes = selectionModel()->selectedRows();
if(!selectedIndexes.empty()) {
int ret = QMessageBox::question(
this,
tr("Deletion confirmation"),
tr("Are you sure you want to delete the selected torrents from transfe list and hard disk?"),
tr("&Yes"), tr("&No"),
QString(), 0, 1);
if(ret) return;
QStringList hashes;
foreach(const QModelIndex &index, selectedIndexes) {
// Get the file hash
hashes << getHashFromRow(proxyModel->mapToSource(index).row());
}
foreach(const QString &hash, hashes) {
deleteTorrent(getRowFromHash(hash), false);
BTSession->deleteTorrent(hash, true);
}
refreshList();
}
} }
// FIXME: Should work only if the tab is displayed // FIXME: Should work only if the tab is displayed
@ -765,8 +739,6 @@ void TransferListWidget::displayListMenu(const QPoint&) {
connect(&actionSet_upload_limit, SIGNAL(triggered()), this, SLOT(setUpLimitSelectedTorrents())); connect(&actionSet_upload_limit, SIGNAL(triggered()), this, SLOT(setUpLimitSelectedTorrents()));
QAction actionSet_download_limit(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")), tr("Limit download rate"), 0); QAction actionSet_download_limit(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")), tr("Limit download rate"), 0);
connect(&actionSet_download_limit, SIGNAL(triggered()), this, SLOT(setDlLimitSelectedTorrents())); connect(&actionSet_download_limit, SIGNAL(triggered()), this, SLOT(setDlLimitSelectedTorrents()));
QAction actionDelete_Permanently(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")), tr("Delete Permanently"), 0);
connect(&actionDelete_Permanently, SIGNAL(triggered()), this, SLOT(deletePermSelectedTorrents()));
QAction actionOpen_destination_folder(QIcon(QString::fromUtf8(":/Icons/oxygen/folder.png")), tr("Open destination folder"), 0); QAction actionOpen_destination_folder(QIcon(QString::fromUtf8(":/Icons/oxygen/folder.png")), tr("Open destination folder"), 0);
connect(&actionOpen_destination_folder, SIGNAL(triggered()), this, SLOT(openSelectedTorrentsFolder())); connect(&actionOpen_destination_folder, SIGNAL(triggered()), this, SLOT(openSelectedTorrentsFolder()));
QAction actionBuy_it(QIcon(QString::fromUtf8(":/Icons/oxygen/wallet.png")), tr("Buy it"), 0); QAction actionBuy_it(QIcon(QString::fromUtf8(":/Icons/oxygen/wallet.png")), tr("Buy it"), 0);
@ -833,7 +805,6 @@ void TransferListWidget::displayListMenu(const QPoint&) {
} }
listMenu.addSeparator(); listMenu.addSeparator();
listMenu.addAction(&actionDelete); listMenu.addAction(&actionDelete);
listMenu.addAction(&actionDelete_Permanently);
listMenu.addSeparator(); listMenu.addSeparator();
if(one_not_seed) if(one_not_seed)
listMenu.addAction(&actionSet_download_limit); listMenu.addAction(&actionSet_download_limit);

1
src/TransferListWidget.h

@ -92,7 +92,6 @@ public slots:
void pauseSelectedTorrents(); void pauseSelectedTorrents();
void pauseAllTorrents(); void pauseAllTorrents();
void deleteSelectedTorrents(); void deleteSelectedTorrents();
void deletePermSelectedTorrents();
void increasePrioSelectedTorrents(); void increasePrioSelectedTorrents();
void decreasePrioSelectedTorrents(); void decreasePrioSelectedTorrents();
void buySelectedTorrents() const; void buySelectedTorrents() const;

10
src/bittorrent.cpp

@ -526,7 +526,7 @@ void bittorrent::banIP(QString ip) {
// Delete a torrent from the session, given its hash // Delete a torrent from the session, given its hash
// permanent = true means that the torrent will be removed from the hard-drive too // permanent = true means that the torrent will be removed from the hard-drive too
void bittorrent::deleteTorrent(QString hash, bool permanent) { void bittorrent::deleteTorrent(QString hash, bool delete_local_files) {
qDebug("Deleting torrent with hash: %s", hash.toLocal8Bit().data()); qDebug("Deleting torrent with hash: %s", hash.toLocal8Bit().data());
QTorrentHandle h = getTorrentHandle(hash); QTorrentHandle h = getTorrentHandle(hash);
if(!h.is_valid()) { if(!h.is_valid()) {
@ -536,7 +536,7 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) {
QString savePath = h.save_path(); QString savePath = h.save_path();
QString fileName = h.name(); QString fileName = h.name();
// Remove it from session // Remove it from session
if(permanent) if(delete_local_files)
s->remove_torrent(h.get_torrent_handle(), session::delete_files); s->remove_torrent(h.get_torrent_handle(), session::delete_files);
else else
s->remove_torrent(h.get_torrent_handle()); s->remove_torrent(h.get_torrent_handle());
@ -551,10 +551,10 @@ void bittorrent::deleteTorrent(QString hash, bool permanent) {
TorrentPersistentData::deletePersistentData(hash); TorrentPersistentData::deletePersistentData(hash);
// Remove tracker errors // Remove tracker errors
trackersErrors.remove(hash); trackersErrors.remove(hash);
if(permanent) if(delete_local_files)
addConsoleMessage(tr("'%1' was removed permanently.", "'xxx.avi' was removed permanently.").arg(fileName)); addConsoleMessage(tr("'%1' was removed from transfer list and hard disk.", "'xxx.avi' was removed...").arg(fileName));
else else
addConsoleMessage(tr("'%1' was removed.", "'xxx.avi' was removed.").arg(fileName)); addConsoleMessage(tr("'%1' was removed from transfer list.", "'xxx.avi' was removed...").arg(fileName));
emit deletedTorrent(hash); emit deletedTorrent(hash);
} }

2
src/bittorrent.h

@ -119,7 +119,7 @@ class bittorrent : public QObject {
void loadSessionState(); void loadSessionState();
void saveSessionState(); void saveSessionState();
void downloadFromUrl(QString url); void downloadFromUrl(QString url);
void deleteTorrent(QString hash, bool permanent = false); void deleteTorrent(QString hash, bool delete_local_files = false);
void startUpTorrents(); void startUpTorrents();
/* Needed by Web UI */ /* Needed by Web UI */
void pauseAllTorrents(); void pauseAllTorrents();

123
src/confirmdeletiondlg.ui

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>confirmDeletionDlg</class>
<widget class="QDialog" name="confirmDeletionDlg">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>377</width>
<height>138</height>
</rect>
</property>
<property name="windowTitle">
<string>Deletion confirmation - qBittorrent</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>30</x>
<y>100</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>90</x>
<y>0</y>
<width>281</width>
<height>61</height>
</rect>
</property>
<property name="text">
<string>Are you sure you want to delete the selected torrents from the transfer list?</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
<widget class="QCheckBox" name="checkPermDelete">
<property name="geometry">
<rect>
<x>20</x>
<y>70</y>
<width>351</width>
<height>23</height>
</rect>
</property>
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Delete the files on the hard disk as well</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>61</width>
<height>61</height>
</rect>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="icons.qrc">:/Icons/oxygen/dialog-warning.png</pixmap>
</property>
</widget>
</widget>
<resources>
<include location="icons.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>confirmDeletionDlg</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>confirmDeletionDlg</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

60
src/deletionconfirmationdlg.h

@ -0,0 +1,60 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*
* Contact : chris@qbittorrent.org
*/
#ifndef DELETIONCONFIRMATIONDLG_H
#define DELETIONCONFIRMATIONDLG_H
#include <QDialog>
#include "ui_confirmdeletiondlg.h"
class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg {
Q_OBJECT
public:
DeletionConfirmationDlg(QWidget *parent=0): QDialog(parent) {
setupUi(this);
}
bool shouldDeleteLocalFiles() const {
return checkPermDelete->isChecked();
}
static bool askForDeletionConfirmation(bool *delete_local_files) {
DeletionConfirmationDlg dlg;
if(dlg.exec() == QDialog::Accepted) {
*delete_local_files = dlg.shouldDeleteLocalFiles();
return true;
}
return false;
}
};
#endif // DELETIONCONFIRMATIONDLG_H

1
src/icons.qrc

@ -120,6 +120,7 @@
<file>Icons/oxygen/gear.png</file> <file>Icons/oxygen/gear.png</file>
<file>Icons/oxygen/draw-triangle2.png</file> <file>Icons/oxygen/draw-triangle2.png</file>
<file>Icons/oxygen/remove.png</file> <file>Icons/oxygen/remove.png</file>
<file>Icons/oxygen/dialog-warning.png</file>
<file>Icons/oxygen/peer.png</file> <file>Icons/oxygen/peer.png</file>
<file>Icons/oxygen/browse.png</file> <file>Icons/oxygen/browse.png</file>
<file>Icons/oxygen/unsubscribe16.png</file> <file>Icons/oxygen/unsubscribe16.png</file>

1
src/propertieswidget.cpp

@ -67,6 +67,7 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, TransferListWidget *transfer
url_seeds_button->setStyleSheet(DEFAULT_BUTTON_CSS); url_seeds_button->setStyleSheet(DEFAULT_BUTTON_CSS);
files_button->setStyleSheet(DEFAULT_BUTTON_CSS); files_button->setStyleSheet(DEFAULT_BUTTON_CSS);
main_infos_button->setStyleSheet(DEFAULT_BUTTON_CSS); main_infos_button->setStyleSheet(DEFAULT_BUTTON_CSS);
main_infos_button->setShortcut(QKeySequence(QString::fromUtf8("Alt+P")));
// Set Properties list model // Set Properties list model
PropListModel = new TorrentFilesModel(); PropListModel = new TorrentFilesModel();

7
src/src.pro

@ -18,6 +18,7 @@ DEFINES += VERSION=\\\"v2.0.0beta2\\\"
DEFINES += VERSION_MAJOR=2 DEFINES += VERSION_MAJOR=2
DEFINES += VERSION_MINOR=0 DEFINES += VERSION_MINOR=0
DEFINES += VERSION_BUGFIX=0 DEFINES += VERSION_BUGFIX=0
# !mac:QMAKE_LFLAGS += -Wl,--as-needed # !mac:QMAKE_LFLAGS += -Wl,--as-needed
contains(DEBUG_MODE, 1) { contains(DEBUG_MODE, 1) {
CONFIG += debug CONFIG += debug
@ -192,7 +193,8 @@ HEADERS += GUI.h \
reverseresolution.h \ reverseresolution.h \
preferences.h \ preferences.h \
geoip.h \ geoip.h \
peeraddition.h peeraddition.h \
deletionconfirmationdlg.h
FORMS += MainWindow.ui \ FORMS += MainWindow.ui \
options.ui \ options.ui \
about.ui \ about.ui \
@ -210,7 +212,8 @@ FORMS += MainWindow.ui \
console.ui \ console.ui \
FeedDownloader.ui \ FeedDownloader.ui \
propertiesWidget.ui \ propertiesWidget.ui \
peer.ui peer.ui \
confirmdeletiondlg.ui
SOURCES += GUI.cpp \ SOURCES += GUI.cpp \
main.cpp \ main.cpp \
options_imp.cpp \ options_imp.cpp \

Loading…
Cancel
Save