File indexing completed on 2024-04-21 04:58:21

0001 /* This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2007 David Faure <faure@kde.org>
0003     SPDX-FileCopyrightText: 2007 Eduardo Robles Elvira <edulix@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "konqundomanager.h"
0009 #include "konqsettingsxt.h"
0010 #include "konqcloseditem.h"
0011 #include "konqclosedwindowsmanager.h"
0012 #include <QAction>
0013 #include <kio/fileundomanager.h>
0014 #include "konqdebug.h"
0015 #include <KLocalizedString>
0016 #include <QWidget>
0017 
0018 KonqUndoManager::KonqUndoManager(KonqClosedWindowsManager *cwManager, QWidget *parent)
0019     : QObject(parent), m_cwManager(cwManager)
0020 {
0021     connect(KIO::FileUndoManager::self(), SIGNAL(undoAvailable(bool)),
0022             this, SLOT(slotFileUndoAvailable(bool)));
0023     connect(KIO::FileUndoManager::self(), SIGNAL(undoTextChanged(QString)),
0024             this, SLOT(slotFileUndoTextChanged(QString)));
0025 
0026     connect(m_cwManager, SIGNAL(addWindowInOtherInstances(KonqUndoManager*,KonqClosedWindowItem*)),
0027             this, SLOT(slotAddClosedWindowItem(KonqUndoManager*,KonqClosedWindowItem*)));
0028     connect(m_cwManager, SIGNAL(removeWindowInOtherInstances(KonqUndoManager*,const KonqClosedWindowItem*)),
0029             this, SLOT(slotRemoveClosedWindowItem(KonqUndoManager*,const KonqClosedWindowItem*)));
0030 }
0031 
0032 KonqUndoManager::~KonqUndoManager()
0033 {
0034     disconnect(KIO::FileUndoManager::self(), SIGNAL(undoAvailable(bool)),
0035                this, SLOT(slotFileUndoAvailable(bool)));
0036     disconnect(KIO::FileUndoManager::self(), SIGNAL(undoTextChanged(QString)),
0037                this, SLOT(slotFileUndoTextChanged(QString)));
0038 
0039     disconnect(m_cwManager, SIGNAL(addWindowInOtherInstances(KonqUndoManager*,KonqClosedWindowItem*)),
0040                this, SLOT(slotAddClosedWindowItem(KonqUndoManager*,KonqClosedWindowItem*)));
0041     disconnect(m_cwManager, SIGNAL(removeWindowInOtherInstances(KonqUndoManager*,const KonqClosedWindowItem*)),
0042                this, SLOT(slotRemoveClosedWindowItem(KonqUndoManager*,const KonqClosedWindowItem*)));
0043 
0044     // Clear the closed item lists but only remove closed windows items
0045     // in this window
0046     clearClosedItemsList(true);
0047 }
0048 
0049 void KonqUndoManager::populate()
0050 {
0051     if (m_populated) {
0052         return;
0053     }
0054     m_populated = true;
0055 
0056     const QList<KonqClosedWindowItem *> closedWindowItemList =
0057         m_cwManager->closedWindowItemList();
0058 
0059     QListIterator<KonqClosedWindowItem *> i(closedWindowItemList);
0060 
0061     // This loop is done backwards because slotAddClosedWindowItem prepends the
0062     // elements to the list, so if we do it forwards the we would get an inverse
0063     // order of closed windows
0064     for (i.toBack(); i.hasPrevious();) {
0065         slotAddClosedWindowItem(nullptr, i.previous());
0066     }
0067 }
0068 
0069 void KonqUndoManager::slotFileUndoAvailable(bool)
0070 {
0071     emit undoAvailable(this->undoAvailable());
0072 }
0073 
0074 bool KonqUndoManager::undoAvailable() const
0075 {
0076     if (!m_closedItemList.isEmpty() || m_cwManager->undoAvailable()) {
0077         return true;
0078     } else {
0079         return (m_supportsFileUndo && KIO::FileUndoManager::self()->isUndoAvailable());
0080     }
0081 }
0082 
0083 QString KonqUndoManager::undoText() const
0084 {
0085     if (!m_closedItemList.isEmpty()) {
0086         const KonqClosedItem *closedItem = m_closedItemList.first();
0087         if (!m_supportsFileUndo || !KIO::FileUndoManager::self()->isUndoAvailable() || closedItem->serialNumber() > KIO::FileUndoManager::self()->currentCommandSerialNumber()) {
0088             const KonqClosedTabItem *closedTabItem =
0089                 dynamic_cast<const KonqClosedTabItem *>(closedItem);
0090             if (closedTabItem) {
0091                 return i18n("Und&o: Closed Tab");
0092             } else {
0093                 return i18n("Und&o: Closed Window");
0094             }
0095         } else {
0096             return KIO::FileUndoManager::self()->undoText();
0097         }
0098 
0099     } else if (m_supportsFileUndo && KIO::FileUndoManager::self()->isUndoAvailable()) {
0100         return KIO::FileUndoManager::self()->undoText();
0101     }
0102 
0103     else if (m_cwManager->undoAvailable()) {
0104         return i18n("Und&o: Closed Window");
0105     } else {
0106         return i18n("Und&o");
0107     }
0108 }
0109 
0110 void KonqUndoManager::undo()
0111 {
0112     populate();
0113     KIO::FileUndoManager *fileUndoManager = KIO::FileUndoManager::self();
0114     if (!m_closedItemList.isEmpty()) {
0115         KonqClosedItem *closedItem = m_closedItemList.first();
0116 
0117         // Check what to undo
0118         if (!m_supportsFileUndo || !fileUndoManager->isUndoAvailable() || closedItem->serialNumber() > fileUndoManager->currentCommandSerialNumber()) {
0119             undoClosedItem(0);
0120             return;
0121         }
0122     }
0123     fileUndoManager->uiInterface()->setParentWidget(qobject_cast<QWidget *>(parent()));
0124     fileUndoManager->undo();
0125 }
0126 
0127 void KonqUndoManager::slotAddClosedWindowItem(KonqUndoManager *real_sender, KonqClosedWindowItem *closedWindowItem)
0128 {
0129     if (real_sender == this) {
0130         return;
0131     }
0132 
0133     populate();
0134 
0135     if (m_closedItemList.size() >= KonqSettings::maxNumClosedItems()) {
0136         const KonqClosedItem *last = m_closedItemList.last();
0137         const KonqClosedTabItem *lastTab =
0138             dynamic_cast<const KonqClosedTabItem *>(last);
0139         m_closedItemList.removeLast();
0140 
0141         // Delete only if it's a tab
0142         if (lastTab) {
0143             delete lastTab;
0144         }
0145     }
0146 
0147     m_closedItemList.prepend(closedWindowItem);
0148     emit undoTextChanged(i18n("Und&o: Closed Window"));
0149     emit undoAvailable(true);
0150     emit closedItemsListChanged();
0151 }
0152 
0153 void KonqUndoManager::addClosedWindowItem(KonqClosedWindowItem *closedWindowItem)
0154 {
0155     populate();
0156     m_cwManager->addClosedWindowItem(this, closedWindowItem);
0157 }
0158 
0159 void KonqUndoManager::slotRemoveClosedWindowItem(KonqUndoManager *real_sender, const KonqClosedWindowItem *closedWindowItem)
0160 {
0161     if (real_sender == this) {
0162         return;
0163     }
0164 
0165     populate();
0166 
0167     QList<KonqClosedItem *>::iterator it = std::find(m_closedItemList.begin(), m_closedItemList.end(), closedWindowItem);
0168 
0169     // If the item was found, remove it from the list
0170     if (it != m_closedItemList.end()) {
0171         m_closedItemList.erase(it);
0172         emit undoAvailable(this->undoAvailable());
0173         emit closedItemsListChanged();
0174     }
0175 }
0176 
0177 const QList<KonqClosedItem *> &KonqUndoManager::closedItemsList()
0178 {
0179     populate();
0180     return m_closedItemList;
0181 }
0182 
0183 void KonqUndoManager::undoClosedItem(int index)
0184 {
0185     populate();
0186     Q_ASSERT(!m_closedItemList.isEmpty());
0187     KonqClosedItem *closedItem = m_closedItemList.at(index);
0188     m_closedItemList.removeAt(index);
0189 
0190     const KonqClosedTabItem *closedTabItem =
0191         dynamic_cast<const KonqClosedTabItem *>(closedItem);
0192     KonqClosedRemoteWindowItem *closedRemoteWindowItem =
0193         dynamic_cast<KonqClosedRemoteWindowItem *>(closedItem);
0194     KonqClosedWindowItem *closedWindowItem =
0195         dynamic_cast<KonqClosedWindowItem *>(closedItem);
0196     if (closedTabItem) {
0197         emit openClosedTab(*closedTabItem);
0198     } else if (closedRemoteWindowItem) {
0199         m_cwManager->removeClosedWindowItem(this, closedRemoteWindowItem);
0200         emit openClosedWindow(*closedRemoteWindowItem);
0201     } else if (closedWindowItem) {
0202         m_cwManager->removeClosedWindowItem(this, closedWindowItem);
0203         emit openClosedWindow(*closedWindowItem);
0204         closedWindowItem->configGroup().deleteGroup();
0205 
0206         // Save config so that this window won't appear in new konqueror processes
0207         m_cwManager->saveConfig();
0208     }
0209     delete closedItem;
0210     emit undoAvailable(this->undoAvailable());
0211     emit undoTextChanged(this->undoText());
0212     emit closedItemsListChanged();
0213 }
0214 
0215 void KonqUndoManager::slotClosedItemsActivated(QAction *action)
0216 {
0217     // Open a closed tab
0218     const int index = action->data().toInt();
0219     undoClosedItem(index);
0220 }
0221 
0222 void KonqUndoManager::slotFileUndoTextChanged(const QString & /*text*/)
0223 {
0224     // We will forward this call but changing the text, because if for example
0225     // there' no more files to undo, the text will be "Und&o" but maybe
0226     // we want it to be "Und&o: Closed Tab" if we have a closed tab that can be
0227     // reopened.
0228     emit undoTextChanged(undoText());
0229 }
0230 
0231 quint64 KonqUndoManager::newCommandSerialNumber()
0232 {
0233     return KIO::FileUndoManager::self()->newCommandSerialNumber();
0234 }
0235 
0236 void KonqUndoManager::addClosedTabItem(KonqClosedTabItem *closedTabItem)
0237 {
0238     populate();
0239 
0240     if (m_closedItemList.size() >= KonqSettings::maxNumClosedItems()) {
0241         const KonqClosedItem *last = m_closedItemList.last();
0242         const KonqClosedTabItem *lastTab =
0243             dynamic_cast<const KonqClosedTabItem *>(last);
0244         m_closedItemList.removeLast();
0245 
0246         // Delete only if it's a tab
0247         if (lastTab) {
0248             delete lastTab;
0249         }
0250     }
0251 
0252     m_closedItemList.prepend(closedTabItem);
0253     emit undoTextChanged(i18n("Und&o: Closed Tab"));
0254     emit undoAvailable(true);
0255 }
0256 
0257 void KonqUndoManager::updateSupportsFileUndo(bool enable)
0258 {
0259     m_supportsFileUndo = enable;
0260     emit undoAvailable(this->undoAvailable());
0261 }
0262 
0263 void KonqUndoManager::clearClosedItemsList(bool onlyInthisWindow)
0264 {
0265     populate();
0266     QList<KonqClosedItem *>::iterator it = m_closedItemList.begin();
0267     for (; it != m_closedItemList.end();) {
0268         KonqClosedItem *closedItem = *it;
0269         const KonqClosedTabItem *closedTabItem =
0270             dynamic_cast<const KonqClosedTabItem *>(closedItem);
0271         const KonqClosedWindowItem *closedWindowItem =
0272             dynamic_cast<const KonqClosedWindowItem *>(closedItem);
0273 
0274         it = m_closedItemList.erase(it);
0275         if (closedTabItem) {
0276             delete closedTabItem;
0277         } else if (closedWindowItem && !onlyInthisWindow) {
0278             m_cwManager->removeClosedWindowItem(this, closedWindowItem, true);
0279             delete closedWindowItem;
0280         }
0281     }
0282 
0283     emit closedItemsListChanged();
0284     emit undoAvailable(this->undoAvailable());
0285 
0286     // Save config so that this window won't appear in new konqueror processes
0287     m_cwManager->saveConfig();
0288 }
0289 
0290 void KonqUndoManager::undoLastClosedItem()
0291 {
0292     undoClosedItem(0);
0293 }
0294