mirror of
https://invent.kde.org/system/dolphin
synced 2024-10-05 16:19:10 +00:00
Allow renaming of items (note that currently the "rename multiple files" dialog is temporary used for this until KFileItemDelegate offers editing functionality).
svn path=/trunk/KDE/kdebase/apps/; revision=642219
This commit is contained in:
parent
75da26f8b0
commit
d9ac44e08f
|
@ -22,8 +22,6 @@
|
|||
#include <config-kmetadata.h>
|
||||
#include "dolphinmainwindow.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "bookmarkssidebarpage.h"
|
||||
#include "dolphinapplication.h"
|
||||
#include "dolphinnewmenu.h"
|
||||
|
@ -58,6 +56,7 @@
|
|||
#include <kmenu.h>
|
||||
#include <kmessagebox.h>
|
||||
#include <konqmimedata.h>
|
||||
#include <konq_operations.h>
|
||||
#include <kpropertiesdialog.h>
|
||||
#include <kprotocolinfo.h>
|
||||
#include <ktoggleaction.h>
|
||||
|
@ -106,7 +105,7 @@ DolphinMainWindow::~DolphinMainWindow()
|
|||
|
||||
void DolphinMainWindow::setActiveView(DolphinView* view)
|
||||
{
|
||||
assert((view == m_view[PrimaryIdx]) || (view == m_view[SecondaryIdx]));
|
||||
Q_ASSERT((view == m_view[PrimaryIdx]) || (view == m_view[SecondaryIdx]));
|
||||
if (m_activeView == view) {
|
||||
return;
|
||||
}
|
||||
|
@ -203,6 +202,12 @@ void DolphinMainWindow::dropUrls(const KUrl::List& urls,
|
|||
}
|
||||
}
|
||||
|
||||
void DolphinMainWindow::rename(const KUrl& oldUrl, const KUrl& newUrl)
|
||||
{
|
||||
KonqOperations::rename(this, oldUrl, newUrl);
|
||||
m_undoCommandTypes.append(KonqUndoManager::RENAME);
|
||||
}
|
||||
|
||||
void DolphinMainWindow::refreshViews()
|
||||
{
|
||||
const bool split = DolphinSettings::instance().generalSettings()->splitView();
|
||||
|
@ -232,7 +237,7 @@ void DolphinMainWindow::refreshViews()
|
|||
}
|
||||
|
||||
m_activeView = isPrimaryViewActive ? m_view[PrimaryIdx] : m_view[SecondaryIdx];
|
||||
assert(m_activeView != 0);
|
||||
Q_ASSERT(m_activeView != 0);
|
||||
|
||||
updateViewActions();
|
||||
emit activeViewChanged();
|
||||
|
@ -336,7 +341,7 @@ void DolphinMainWindow::slotSelectionChanged()
|
|||
{
|
||||
updateEditActions();
|
||||
|
||||
assert(m_view[PrimaryIdx] != 0);
|
||||
Q_ASSERT(m_view[PrimaryIdx] != 0);
|
||||
int selectedUrlsCount = m_view[PrimaryIdx]->selectedUrls().count();
|
||||
if (m_view[SecondaryIdx] != 0) {
|
||||
selectedUrlsCount += m_view[SecondaryIdx]->selectedUrls().count();
|
||||
|
@ -444,7 +449,7 @@ void DolphinMainWindow::moveToTrash()
|
|||
clearStatusBar();
|
||||
const KUrl::List selectedUrls = m_activeView->selectedUrls();
|
||||
KonqOperations::del(this, KonqOperations::TRASH, selectedUrls);
|
||||
m_undoOperations.append(KonqOperations::TRASH);
|
||||
m_undoCommandTypes.append(KonqUndoManager::TRASH);
|
||||
}
|
||||
|
||||
void DolphinMainWindow::deleteItems()
|
||||
|
@ -453,7 +458,7 @@ void DolphinMainWindow::deleteItems()
|
|||
|
||||
KUrl::List list = m_activeView->selectedUrls();
|
||||
const uint itemCount = list.count();
|
||||
assert(itemCount >= 1);
|
||||
Q_ASSERT(itemCount >= 1);
|
||||
|
||||
QString text;
|
||||
if (itemCount > 1) {
|
||||
|
@ -514,26 +519,36 @@ void DolphinMainWindow::slotUndoAvailable(bool available)
|
|||
undoAction->setEnabled(available);
|
||||
}
|
||||
|
||||
if (available && (m_undoOperations.count() > 0)) {
|
||||
const KonqOperations::Operation op = m_undoOperations.takeFirst();
|
||||
if (available && (m_undoCommandTypes.count() > 0)) {
|
||||
const KonqUndoManager::CommandType command = m_undoCommandTypes.takeFirst();
|
||||
DolphinStatusBar* statusBar = m_activeView->statusBar();
|
||||
switch (op) {
|
||||
case KonqOperations::COPY:
|
||||
switch (command) {
|
||||
case KonqUndoManager::COPY:
|
||||
statusBar->setMessage(i18n("Copy operation completed."),
|
||||
DolphinStatusBar::OperationCompleted);
|
||||
break;
|
||||
case KonqOperations::MOVE:
|
||||
case KonqUndoManager::MOVE:
|
||||
statusBar->setMessage(i18n("Move operation completed."),
|
||||
DolphinStatusBar::OperationCompleted);
|
||||
break;
|
||||
case KonqOperations::LINK:
|
||||
case KonqUndoManager::LINK:
|
||||
statusBar->setMessage(i18n("Link operation completed."),
|
||||
DolphinStatusBar::OperationCompleted);
|
||||
break;
|
||||
case KonqOperations::TRASH:
|
||||
case KonqUndoManager::TRASH:
|
||||
statusBar->setMessage(i18n("Move to trash operation completed."),
|
||||
DolphinStatusBar::OperationCompleted);
|
||||
break;
|
||||
case KonqUndoManager::RENAME:
|
||||
statusBar->setMessage(i18n("Renaming operation completed."),
|
||||
DolphinStatusBar::OperationCompleted);
|
||||
break;
|
||||
|
||||
case KonqUndoManager::MKDIR:
|
||||
statusBar->setMessage(i18n("Created directory."),
|
||||
DolphinStatusBar::OperationCompleted);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -912,7 +927,7 @@ void DolphinMainWindow::compareFiles()
|
|||
// - both in the secondary view
|
||||
// - one in the primary view and the other in the secondary
|
||||
// view
|
||||
assert(m_view[PrimaryIdx] != 0);
|
||||
Q_ASSERT(m_view[PrimaryIdx] != 0);
|
||||
|
||||
KUrl urlA;
|
||||
KUrl urlB;
|
||||
|
@ -920,9 +935,9 @@ void DolphinMainWindow::compareFiles()
|
|||
|
||||
switch (urls.count()) {
|
||||
case 0: {
|
||||
assert(m_view[SecondaryIdx] != 0);
|
||||
Q_ASSERT(m_view[SecondaryIdx] != 0);
|
||||
urls = m_view[SecondaryIdx]->selectedUrls();
|
||||
assert(urls.count() == 2);
|
||||
Q_ASSERT(urls.count() == 2);
|
||||
urlA = urls[0];
|
||||
urlB = urls[1];
|
||||
break;
|
||||
|
@ -930,9 +945,9 @@ void DolphinMainWindow::compareFiles()
|
|||
|
||||
case 1: {
|
||||
urlA = urls[0];
|
||||
assert(m_view[SecondaryIdx] != 0);
|
||||
Q_ASSERT(m_view[SecondaryIdx] != 0);
|
||||
urls = m_view[SecondaryIdx]->selectedUrls();
|
||||
assert(urls.count() == 1);
|
||||
Q_ASSERT(urls.count() == 1);
|
||||
urlB = urls[0];
|
||||
break;
|
||||
}
|
||||
|
@ -946,7 +961,7 @@ void DolphinMainWindow::compareFiles()
|
|||
default: {
|
||||
// may not happen: compareFiles may only get invoked if 2
|
||||
// files are selected
|
||||
assert(false);
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -983,7 +998,7 @@ void DolphinMainWindow::init()
|
|||
DolphinSettings& settings = DolphinSettings::instance();
|
||||
|
||||
KBookmarkManager* manager = settings.bookmarkManager();
|
||||
assert(manager != 0);
|
||||
Q_ASSERT(manager != 0);
|
||||
KBookmarkGroup root = manager->root();
|
||||
if (root.first().isNull()) {
|
||||
root.addBookmark(manager, i18n("Home"), settings.generalSettings()->homeUrl(), "folder-home");
|
||||
|
@ -1437,19 +1452,19 @@ void DolphinMainWindow::updateGoActions()
|
|||
void DolphinMainWindow::copyUrls(const KUrl::List& source, const KUrl& dest)
|
||||
{
|
||||
KonqOperations::copy(this, KonqOperations::COPY, source, dest);
|
||||
m_undoOperations.append(KonqOperations::COPY);
|
||||
m_undoCommandTypes.append(KonqUndoManager::COPY);
|
||||
}
|
||||
|
||||
void DolphinMainWindow::moveUrls(const KUrl::List& source, const KUrl& dest)
|
||||
{
|
||||
KonqOperations::copy(this, KonqOperations::MOVE, source, dest);
|
||||
m_undoOperations.append(KonqOperations::MOVE);
|
||||
m_undoCommandTypes.append(KonqUndoManager::MOVE);
|
||||
}
|
||||
|
||||
void DolphinMainWindow::linkUrls(const KUrl::List& source, const KUrl& dest)
|
||||
{
|
||||
KonqOperations::copy(this, KonqOperations::LINK, source, dest);
|
||||
m_undoOperations.append(KonqOperations::LINK);
|
||||
m_undoCommandTypes.append(KonqUndoManager::LINK);
|
||||
}
|
||||
|
||||
void DolphinMainWindow::clearStatusBar()
|
||||
|
@ -1489,7 +1504,7 @@ DolphinMainWindow::UndoUiInterface::UndoUiInterface(DolphinMainWindow* mainWin)
|
|||
KonqUndoManager::UiInterface(mainWin),
|
||||
m_mainWin(mainWin)
|
||||
{
|
||||
assert(m_mainWin != 0);
|
||||
Q_ASSERT(m_mainWin != 0);
|
||||
}
|
||||
|
||||
DolphinMainWindow::UndoUiInterface::~UndoUiInterface()
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#include <kmainwindow.h>
|
||||
#include <ksortablelist.h>
|
||||
#include <konq_operations.h>
|
||||
#include <konq_undo.h>
|
||||
|
||||
#include <QList>
|
||||
|
@ -73,19 +72,22 @@ public:
|
|||
DolphinView* activeView() const { return m_activeView; }
|
||||
|
||||
/**
|
||||
* Handles the dropping of Urls to the given
|
||||
* Handles the dropping of URLs to the given
|
||||
* destination. A context menu with the options
|
||||
* 'Move Here', 'Copy Here', 'Link Here' and
|
||||
* 'Cancel' is offered to the user.
|
||||
* @param urls List of Urls which have been
|
||||
* @param urls List of URLs which have been
|
||||
* dropped.
|
||||
* @param destination Destination Url, where the
|
||||
* list or Urls should be moved,
|
||||
* @param destination Destination URL, where the
|
||||
* list or URLs should be moved,
|
||||
* copied or linked to.
|
||||
*/
|
||||
void dropUrls(const KUrl::List& urls,
|
||||
const KUrl& destination);
|
||||
|
||||
/** Renames the item represented by \a oldUrl to \a newUrl. */
|
||||
void rename(const KUrl& oldUrl, const KUrl& newUrl);
|
||||
|
||||
/**
|
||||
* Refreshs the views of the main window by recreating them dependent from
|
||||
* the given Dolphin settings.
|
||||
|
@ -146,7 +148,10 @@ private slots:
|
|||
/** Updates the 'Create New...' sub menu. */
|
||||
void updateNewMenu();
|
||||
|
||||
/** Renames the selected item of the active view. */
|
||||
/**
|
||||
* Let the user input a name for the selected item(s) and trigger
|
||||
* a renaming afterwards.
|
||||
*/
|
||||
void rename();
|
||||
|
||||
/** Moves the selected items of the active view to the trash. */
|
||||
|
@ -307,16 +312,16 @@ private slots:
|
|||
*/
|
||||
void adjustViewProperties();
|
||||
|
||||
/** Goes back on step of the Url history. */
|
||||
/** Goes back on step of the URL history. */
|
||||
void goBack();
|
||||
|
||||
/** Goes forward one step of the Url history. */
|
||||
/** Goes forward one step of the URL history. */
|
||||
void goForward();
|
||||
|
||||
/** Goes up one hierarchy of the current Url. */
|
||||
/** Goes up one hierarchy of the current URL. */
|
||||
void goUp();
|
||||
|
||||
/** Goes to the home Url. */
|
||||
/** Goes to the home URL. */
|
||||
void goHome();
|
||||
|
||||
/** Opens a terminal for the current shown directory. */
|
||||
|
@ -360,7 +365,7 @@ private slots:
|
|||
|
||||
/**
|
||||
* Updates the caption of the main window and the state
|
||||
* of all menu actions which depend from a changed Url.
|
||||
* of all menu actions which depend from a changed URL.
|
||||
*/
|
||||
void slotUrlChanged(const KUrl& url);
|
||||
|
||||
|
@ -430,7 +435,7 @@ private:
|
|||
DolphinView* m_view[SecondaryIdx + 1];
|
||||
|
||||
/// remember pending undo operations until they are finished
|
||||
QList<KonqOperations::Operation> m_undoOperations;
|
||||
QList<KonqUndoManager::CommandType> m_undoCommandTypes;
|
||||
};
|
||||
|
||||
#endif // _DOLPHIN_H_
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
#include "dolphinview.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QDropEvent>
|
||||
|
@ -250,6 +248,7 @@ bool DolphinView::showHiddenFiles() const
|
|||
|
||||
void DolphinView::renameSelectedItems()
|
||||
{
|
||||
DolphinView* view = mainWindow()->activeView();
|
||||
const KUrl::List urls = selectedUrls();
|
||||
if (urls.count() > 1) {
|
||||
// More than one item has been selected for renaming. Open
|
||||
|
@ -259,10 +258,9 @@ void DolphinView::renameSelectedItems()
|
|||
return;
|
||||
}
|
||||
|
||||
DolphinView* view = mainWindow()->activeView();
|
||||
const QString& newName = dialog.newName();
|
||||
if (newName.isEmpty()) {
|
||||
view->statusBar()->setMessage(i18n("The new item name is invalid."),
|
||||
view->statusBar()->setMessage(dialog.errorString(),
|
||||
DolphinStatusBar::Error);
|
||||
}
|
||||
else {
|
||||
|
@ -271,13 +269,13 @@ void DolphinView::renameSelectedItems()
|
|||
//UndoManager& undoMan = UndoManager::instance();
|
||||
//undoMan.beginMacro();
|
||||
|
||||
assert(newName.contains('#'));
|
||||
Q_ASSERT(newName.contains('#'));
|
||||
|
||||
const int urlsCount = urls.count();
|
||||
|
||||
// iterate through all selected items and rename them...
|
||||
const int replaceIndex = newName.indexOf('#');
|
||||
assert(replaceIndex >= 0);
|
||||
Q_ASSERT(replaceIndex >= 0);
|
||||
for (int i = 0; i < urlsCount; ++i) {
|
||||
const KUrl& source = urls[i];
|
||||
QString number;
|
||||
|
@ -311,28 +309,26 @@ void DolphinView::renameSelectedItems()
|
|||
else {
|
||||
// Only one item has been selected for renaming. Use the custom
|
||||
// renaming mechanism from the views.
|
||||
assert(urls.count() == 1);
|
||||
// TODO:
|
||||
/*if (m_mode == DetailsView) {
|
||||
Q3ListViewItem* item = m_iconsView->firstChild();
|
||||
while (item != 0) {
|
||||
if (item->isSelected()) {
|
||||
m_iconsView->rename(item, DolphinDetailsView::NameColumn);
|
||||
break;
|
||||
}
|
||||
item = item->nextSibling();
|
||||
}
|
||||
Q_ASSERT(urls.count() == 1);
|
||||
|
||||
// TODO: until KFileItemDelegate supports editing, use the the Dolphin
|
||||
// rename dialog as temporary workaround:
|
||||
RenameDialog dialog(urls);
|
||||
if (dialog.exec() == QDialog::Rejected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString& newName = dialog.newName();
|
||||
if (newName.isEmpty()) {
|
||||
view->statusBar()->setMessage(dialog.errorString(),
|
||||
DolphinStatusBar::Error);
|
||||
}
|
||||
else {
|
||||
KFileIconViewItem* item = static_cast<KFileIconViewItem*>(m_iconsView->firstItem());
|
||||
while (item != 0) {
|
||||
if (item->isSelected()) {
|
||||
item->rename();
|
||||
break;
|
||||
}
|
||||
item = static_cast<KFileIconViewItem*>(item->nextItem());
|
||||
}
|
||||
}*/
|
||||
const KUrl& oldUrl = urls.first();
|
||||
KUrl newUrl = oldUrl.upUrl();
|
||||
newUrl.addPath(newName);
|
||||
m_mainWindow->rename(oldUrl, newUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -894,7 +890,7 @@ QString DolphinView::selectionStatusBarText() const
|
|||
|
||||
void DolphinView::showFilterBar(bool show)
|
||||
{
|
||||
assert(m_filterBar != 0);
|
||||
Q_ASSERT(m_filterBar != 0);
|
||||
if (show) {
|
||||
m_filterBar->show();
|
||||
}
|
||||
|
@ -1001,7 +997,7 @@ void DolphinView::dropUrls(const KUrl::List& urls,
|
|||
KFileItem* directory = 0;
|
||||
if (isValidNameIndex(index)) {
|
||||
KFileItem* item = fileItem(index);
|
||||
assert(item != 0);
|
||||
Q_ASSERT(item != 0);
|
||||
if (item->isDir()) {
|
||||
// the URLs are dropped above a directory
|
||||
directory = item;
|
||||
|
@ -1073,8 +1069,8 @@ void DolphinView::createView()
|
|||
m_fileItemDelegate = 0;
|
||||
}
|
||||
|
||||
assert(m_iconsView == 0);
|
||||
assert(m_detailsView == 0);
|
||||
Q_ASSERT(m_iconsView == 0);
|
||||
Q_ASSERT(m_detailsView == 0);
|
||||
|
||||
// ... and recreate it representing the current mode
|
||||
switch (m_mode) {
|
||||
|
@ -1089,7 +1085,7 @@ void DolphinView::createView()
|
|||
break;
|
||||
}
|
||||
|
||||
assert(view != 0);
|
||||
Q_ASSERT(view != 0);
|
||||
|
||||
m_fileItemDelegate = new KFileItemDelegate(view);
|
||||
view->setItemDelegate(m_fileItemDelegate);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Peter Penz *
|
||||
* peter.penz@gmx.at *
|
||||
* Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -19,14 +18,12 @@
|
|||
***************************************************************************/
|
||||
|
||||
#include "renamedialog.h"
|
||||
#include <klocale.h>
|
||||
#include <qlabel.h>
|
||||
#include <qlayout.h>
|
||||
#include <q3vbox.h>
|
||||
//Added by qt3to4:
|
||||
#include <Q3VBoxLayout>
|
||||
#include <assert.h>
|
||||
|
||||
#include <klineedit.h>
|
||||
#include <klocale.h>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
RenameDialog::RenameDialog(const KUrl::List& items) :
|
||||
KDialog()
|
||||
|
@ -37,19 +34,23 @@ RenameDialog::RenameDialog(const KUrl::List& items) :
|
|||
|
||||
setButtonGuiItem(Ok, KGuiItem(i18n("Rename"), "dialog-apply"));
|
||||
|
||||
QWidget *page = new QWidget(this);
|
||||
QWidget* page = new QWidget(this);
|
||||
setMainWidget(page);
|
||||
|
||||
Q3VBoxLayout* topLayout = new Q3VBoxLayout(page, 0, spacingHint());
|
||||
QVBoxLayout* topLayout = new QVBoxLayout(page);
|
||||
topLayout->setMargin(KDialog::marginHint());
|
||||
|
||||
const int itemCount = items.count();
|
||||
QLabel* editLabel = new QLabel(i18n("Rename the %1 selected items to:",itemCount),
|
||||
QLabel* editLabel = new QLabel(i18n("Rename the %1 selected items to:", itemCount),
|
||||
page);
|
||||
|
||||
m_lineEdit = new KLineEdit(page);
|
||||
m_newName = i18n("New name #");
|
||||
assert(itemCount > 1);
|
||||
|
||||
// TODO: reactivate assertion as soon as KFileItemDelegate supports renaming of
|
||||
// single items
|
||||
//Q_ASSERT(itemCount > 1);
|
||||
|
||||
QString postfix(items[0].prettyUrl().section('.',1));
|
||||
if (postfix.length() > 0) {
|
||||
// The first item seems to have a postfix (e. g. 'jpg' or 'txt'). Now
|
||||
|
@ -88,8 +89,12 @@ void RenameDialog::slotButtonClicked(int button)
|
|||
{
|
||||
if (button==Ok) {
|
||||
m_newName = m_lineEdit->text();
|
||||
if (m_newName.contains('#') != 1) {
|
||||
if (m_newName.isEmpty()) {
|
||||
m_errorString = i18n("The new name is empty. A name with at least one character must be entered.");
|
||||
}
|
||||
else if (m_newName.contains('#') != 1) {
|
||||
m_newName.truncate(0);
|
||||
m_errorString = i18n("The name must contain exactly one # character.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2006 by Peter Penz *
|
||||
* peter.penz@gmx.at *
|
||||
* Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -22,7 +21,8 @@
|
|||
|
||||
#include <kdialog.h>
|
||||
#include <kurl.h>
|
||||
#include <qstring.h>
|
||||
|
||||
#include <QString>
|
||||
|
||||
class KLineEdit;
|
||||
|
||||
|
@ -35,10 +35,15 @@ class KLineEdit;
|
|||
* RenameDialog dialog(...);
|
||||
* if (dialog.exec() == QDialog::Accepted) {
|
||||
* const QString& newName = dialog.newName();
|
||||
* // ... rename items corresponding to the new name
|
||||
* if (newName.isEmpty()) {
|
||||
* // an invalid name has been chosen, use
|
||||
* // dialog.errorString() to tell the user about this
|
||||
* }
|
||||
* else {
|
||||
* // rename items corresponding to the new name
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
* @author Peter Penz
|
||||
*/
|
||||
class RenameDialog : public KDialog
|
||||
{
|
||||
|
@ -56,12 +61,18 @@ public:
|
|||
*/
|
||||
const QString& newName() const { return m_newName; }
|
||||
|
||||
/**
|
||||
* Returns the error string, if Dialog::newName() returned an empty string.
|
||||
*/
|
||||
const QString& errorString() const { return m_errorString; }
|
||||
|
||||
protected slots:
|
||||
virtual void slotButtonClicked(int button);
|
||||
|
||||
private:
|
||||
KLineEdit* m_lineEdit;
|
||||
QString m_newName;
|
||||
QString m_errorString;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue