Index: src/konqcloseditem.cpp =================================================================== --- src/konqcloseditem.cpp (revisión: 794475) +++ src/konqcloseditem.cpp (copia de trabajo) @@ -19,6 +19,7 @@ */ #include "konqcloseditem.h" +#include "konqundomanager.h" #include #include #include @@ -34,27 +35,6 @@ #include #include -class KConfigNew -{ -public: - KConfigNew() - { - filename = "closeditems/closeditems_" + QString::number(getpid()); - QString file = KStandardDirs::locateLocal("appdata", filename); - if(QFile::exists(file)) - QFile::remove(file); - - config = new KConfig(filename, KConfig::SimpleConfig, "appdata"); - kDebug(); - } - ~KConfigNew() { - QFile::remove(KStandardDirs::locateLocal("appdata", filename)); - delete config; - } - KConfig *config; - QString filename; -}; - class KonqIcon { public: KonqIcon() @@ -66,11 +46,10 @@ QImage image; }; -K_GLOBAL_STATIC(KConfigNew, s_config) K_GLOBAL_STATIC(KonqIcon, s_lightIconImage) KonqClosedItem::KonqClosedItem(const QString& title, const QString& group, quint64 serialNumber) - : m_title(title), m_configGroup(s_config->config, group), m_serialNumber(serialNumber) + : m_title(title), m_configGroup(KonqClosedWindowsManager::self()->config(), group), m_serialNumber(serialNumber) { } @@ -92,7 +71,7 @@ kDebug(1202) << "deleted group" << m_configGroup.name(); } -QPixmap KonqClosedTabItem::icon() { +QPixmap KonqClosedTabItem::icon() const { return KonqPixmapProvider::self()->pixmapFor(m_url); } @@ -104,11 +83,12 @@ KonqClosedWindowItem::~KonqClosedWindowItem() { - m_configGroup.deleteGroup(); - kDebug(1202) << "deleted group" << m_configGroup.name(); +// Do this manually when needed: +// m_configGroup.deleteGroup(); } -QPixmap KonqClosedWindowItem::icon() { +QPixmap KonqClosedWindowItem::icon() const +{ QImage overlayImg = s_lightIconImage->image.copy(); int oldWidth = overlayImg.width(); QString countStr = QString::number( m_numTabs ); @@ -134,3 +114,57 @@ return QPixmap::fromImage(overlayImg); } + +int KonqClosedWindowItem::numTabs() const +{ + return m_numTabs; +} + +KonqClosedRemoteWindowItem::KonqClosedRemoteWindowItem(const QString& title, + const QString& groupName, const QString& configFileName, quint64 serialNumber, + int numTabs, const QString& dbusService) + : KonqClosedWindowItem(title, serialNumber, numTabs), + m_remoteGroupName(groupName), m_remoteConfigFileName(configFileName), + m_dbusService(dbusService), m_remoteConfigGroup(0L), m_remoteConfig(0L) +{ + kDebug(); +} + +KonqClosedRemoteWindowItem::~KonqClosedRemoteWindowItem() +{ + delete m_remoteConfigGroup; + delete m_remoteConfig; +} + +void KonqClosedRemoteWindowItem::readConfig() +{ + // only do this once + if(m_remoteConfig || m_remoteConfigGroup) + return; + + m_remoteConfig = new KConfig( + KStandardDirs::locateLocal("appdata", m_remoteConfigFileName), + KConfig::SimpleConfig, "appdata"); + m_remoteConfigGroup = new KConfigGroup(m_remoteConfig, m_remoteGroupName); + kDebug(); +} + +const KConfigGroup& KonqClosedRemoteWindowItem::configGroup() const +{ + KonqClosedRemoteWindowItem *nonConstThis = const_cast(this); + nonConstThis->readConfig(); + return *m_remoteConfigGroup; +} + +KConfigGroup& KonqClosedRemoteWindowItem::configGroup() +{ + readConfig(); + return *m_remoteConfigGroup; +} + +bool KonqClosedRemoteWindowItem::equalsTo(const QString& groupName, + const QString& configFileName) const +{ + return (m_remoteGroupName == groupName && + m_remoteConfigFileName == configFileName); +} Index: src/konqviewmanager.cpp =================================================================== --- src/konqviewmanager.cpp (revisión: 794475) +++ src/konqviewmanager.cpp (copia de trabajo) @@ -358,9 +358,11 @@ } mainWindow->viewManager()->loadRootItem( closedWindowItem.configGroup(), mainWindow->viewManager()->tabContainer(), KUrl(), true, KUrl() ); + // read window settings + mainWindow->applyMainWindowSettings( KConfigGroup( KGlobal::config(), "KonqMainWindow" ), true ); + mainWindow->applyMainWindowSettings( KConfigGroup( & closedWindowItem.configGroup(), "Main Window Settings" ), true ); mainWindow->activateChild(); mainWindow->show(); - kDebug(1202) << "done"; } Index: src/org.kde.Konqueror.UndoManager.xml =================================================================== --- src/org.kde.Konqueror.UndoManager.xml (revisión: 0) +++ src/org.kde.Konqueror.UndoManager.xml (revisión: 0) @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + Index: src/konqmainwindow.cpp =================================================================== --- src/konqmainwindow.cpp (revisión: 794475) +++ src/konqmainwindow.cpp (copia de trabajo) @@ -2895,7 +2895,7 @@ QMenu* popup = m_paClosedItems->menu(); // Clear the menu and fill it with a maximum of s_closedTabsListLength number of urls popup->clear(); - QAction* clearAction = popup->addAction( i18n("Empty Closed Tabs History") ); + QAction* clearAction = popup->addAction( i18n("Empty Closed Items History") ); connect(clearAction, SIGNAL(triggered()), m_undoManager, SLOT(clearClosedItemsList())); popup->insertSeparator((QAction*)0); @@ -4994,10 +4994,7 @@ // save size to have something to restore if the profile does not contain size saveWindowSize(); - // Save the window tabs so that we can restore it later, but only if there - // are other windows opened - if(s_konqMainWindowInstancesCount > 1) - addClosedWindowToUndoList(); + addClosedWindowToUndoList(); hide(); qApp->flush(); @@ -5040,7 +5037,11 @@ closedWindowItem->configGroup().writeEntry( "Height", height() ); closedWindowItem->configGroup().writeEntry( "FullScreen", fullScreenMode() ); tabContainer->saveConfig( closedWindowItem->configGroup(), prefix, flags, 0L, 0, 1); - + // Save window settings + KConfigGroup cfg( &closedWindowItem->configGroup(), "Main Window Settings" ); + saveMainWindowSettings( cfg ); + closedWindowItem->configGroup().sync(); + // 3. Finally add the KonqClosedWindowItem to the undo list m_paClosedItems->setEnabled(true); m_undoManager->addClosedWindowItem( closedWindowItem ); Index: src/CMakeLists.txt =================================================================== --- src/CMakeLists.txt (revisión: 794475) +++ src/CMakeLists.txt (copia de trabajo) @@ -69,6 +69,9 @@ qt4_add_dbus_interface(konqueror_KDEINIT_SRCS org.kde.Konqueror.Main.xml konqueror_interface) qt4_add_dbus_interface(konqueror_KDEINIT_SRCS ${KDE4_DBUS_INTERFACES_DIR}/org.kde.kded.xml kded_interface) +qt4_add_dbus_adaptor(konqueror_KDEINIT_SRCS org.kde.Konqueror.UndoManager.xml konqundomanager.h KonqClosedWindowsManager konqundomanageradaptor KonqClosedWindowsManagerAdaptor) +qt4_add_dbus_interface(konqueror_KDEINIT_SRCS org.kde.Konqueror.UndoManager.xml konqundomanager_interface) +kde4_add_kdeinit_executable(konqueror ${konqueror_KDEINIT_SRCS} konqmain.cpp) kde4_add_app_icon(konqueror_KDEINIT_SRCS "${KDE4_ICON_INSTALL_DIR}/oxygen/*/apps/konqueror.png") Index: src/konqundomanager.h =================================================================== --- src/konqundomanager.h (revisión: 794475) +++ src/konqundomanager.h (copia de trabajo) @@ -21,12 +21,16 @@ #ifndef KONQUNDOMANAGER_H #define KONQUNDOMANAGER_H -#include "konqprivate_export.h" - #include +#include +#include +#include #include "konqcloseditem.h" +#include "konqundomanager_interface.h" class QAction; -class KonqUndoManagerCommunicatorPrivate; +class KonqClosedWindowsManagerPrivate; +class QDBusMessage; + /** * Note that there is one KonqUndoManager per mainwindow. * It integrates KonqFileUndoManager (undoing file operations) @@ -54,7 +58,7 @@ public Q_SLOTS: void undo(); - void clearClosedItemsList(); + void clearClosedItemsList(bool onlyInthisWindow = false); void undoLastClosedItem(); /** * Opens in a new tab/window the item the user selected from the closed tabs @@ -102,31 +106,157 @@ /** * Provides a shared singleton for all Konq window instances. * This class is a singleton, use self() to access its only instance. + * + * - it synchronizes the closed window list with other + * Konqueror instances via DBUS. + * + * - When a konqueror instance is closed, the closed window list is written + * to disk so that the undo closed windows list can be retrieved even when + * no other konqueror instance is running. */ -class KONQ_TESTS_EXPORT KonqUndoManagerCommunicator : public QObject +class KONQ_TESTS_EXPORT KonqClosedWindowsManager : public QObject { Q_OBJECT public: - friend class KonqUndoManagerCommunicatorPrivate; - static KonqUndoManagerCommunicator *self(); + friend class KonqClosedWindowsManagerPrivate; + + static KonqClosedWindowsManager *self(); + const QList& closedWindowItemList(); + void addClosedWindowItem(KonqUndoManager *real_sender, KonqClosedWindowItem - *closedWindowItem); + *closedWindowItem, bool propagate = true); + void removeClosedWindowItem(KonqUndoManager *real_sender, const - KonqClosedWindowItem *closedWindowItem); + + KonqClosedWindowItem *closedWindowItem, bool propagate = true); + void applySettings(); + int maxNumClosedItems(); + void setMaxNumClosedItems(int max); + + KConfig* config(); + public Q_SLOTS: void readSettings(); + + /** + * Reads the list of closed window from the configuration file if it couldn't + * be retrieved from running konqueror windows + */ + void readConfig(); + Q_SIGNALS: + /** + * Notifies the addition the closed window list in all the konqueror windows of + * this konqueror instance. + */ void addWindowInOtherInstances(KonqUndoManager *real_sender, KonqClosedWindowItem *closedWindowItem); + + /** + * Notifies the removal the closed window list in all the konqueror windows of + * this konqueror instance. + */ void removeWindowInOtherInstances(KonqUndoManager *real_sender, const - KonqClosedWindowItem *closedWindowItem); + KonqClosedWindowItem *closedWindowItem); + private: - KonqUndoManagerCommunicator(); - virtual ~KonqUndoManagerCommunicator(); + KonqClosedWindowsManager(); + + virtual ~KonqClosedWindowsManager(); + + /** + * Called by readSettings(), which is called by a singleShot timer inside + * the constructor. Fills the closed window list with items from other + * konqueror instances, being the list retrieved via DBUS using the method + * localClosedWindowItems(); + * + * It also sets a timer so that if no other konqueror instance pings back in + * X miliseconds, then the closed window list is read from disk. + */ + void populate(); + + /** + * Called by the destructor. Saves the closed windows list to disk inside a + * config file + */ + void saveConfig(); + + KonqClosedRemoteWindowItem* findClosedRemoteWindowItem(const QString& configFileName, + const QString& configGroup); + + KonqClosedWindowItem* findClosedLocalWindowItem(const QString& configFileName, + const QString& configGroup); + + /** + * This function removes all the files in appdata/closeditem/. Thus, it's + * used to clean the config files inside that directory. + */ + void removeClosedItemsConfigFiles(); +private: + QList m_closedWindowItemList; + KConfig *m_konqClosedItemsConfig; + int m_maxNumClosedItems; + bool m_amIalone; +Q_SIGNALS: // DBUS signals + /** + * Every konqueror instance broadcasts new closed windows to other + * konqueror instances. + */ + void notifyClosedWindowItem( const QString& title, const int& numTabs, + const QString& configFileName, const QString& configGroup ); + + /** + * Every konqueror instance broadcasts removed closed windows to other + * konqueror instances. + */ + void notifyRemove( const QString& configFileName, + const QString& configGroup ); + + /** + * Ask over D-BUS to all running konqueror instances to return their list + * of local closed window items. + */ + void requestLocalClosedWindowItems(); +public Q_SLOTS: // DBUS methods + /** + * This is the answer call when a konqueror instance receives a call from + * requestLocalClosedWindowItems(). + */ + void localClosedWindowItems(const QList& windowItems, + const QString& dbusService); + + /** + * This signal is received from other konqueror instances in order to let + * us know that there are other konqueror instances from which we can + * retrieve the list of closed window items, so that we don't need to read + * them from disk. + */ + void pong(); + +private Q_SLOTS:// connected to DBUS signals + void slotNotifyClosedWindowItem( const QString& title, const int& numTabs, + const QString& configFileName, const QString& configGroup, + const QString& service ); + + void slotNotifyClosedWindowItem( const QString& title, const int& numTabs, + const QString& configFileName, const QString& configGroup, + const QDBusMessage& msg ); + + void slotNotifyRemove( const QString& configFileName, + const QString& configGroup, const QDBusMessage& msg ); + + void slotRequestLocalClosedWindowItems( const QDBusMessage& msg ); + +private: + void emitNotifyClosedWindowItem(const KonqClosedWindowItem *closedWindowItem); + + void emitNotifyRemove(const KonqClosedWindowItem *closedWindowItem); + + void emitPong(const QString & service); }; #endif /* KONQUNDOMANAGER_H */ Index: src/konqcloseditem.h =================================================================== --- src/konqcloseditem.h (revisión: 794475) +++ src/konqcloseditem.h (copia de trabajo) @@ -23,17 +23,20 @@ #include "konqprivate_export.h" #include +#include #include #include +class KConfig; + class KONQ_TESTS_EXPORT KonqClosedItem : public QObject { public: virtual ~KonqClosedItem(); - const KConfigGroup& configGroup() const { return m_configGroup; } - KConfigGroup& configGroup() { return m_configGroup; } + virtual KConfigGroup& configGroup() { return m_configGroup; } + virtual const KConfigGroup& configGroup() const { return m_configGroup; } quint64 serialNumber() const { return m_serialNumber; } QString title() const { return m_title; } - virtual QPixmap icon() = 0; + virtual QPixmap icon() const = 0; protected: KonqClosedItem(const QString& title, const QString& group, quint64 serialNumber); @@ -50,7 +53,7 @@ public: KonqClosedTabItem(const QString& url, const QString& title, int index, quint64 serialNumber); virtual ~KonqClosedTabItem(); - virtual QPixmap icon(); + virtual QPixmap icon() const; QString url() const { return m_url; } /// The position inside the tabbar that the tab had when it was closed int pos() const { return m_pos; } @@ -68,11 +71,35 @@ public: KonqClosedWindowItem(const QString& title, quint64 serialNumber, int numTabs); virtual ~KonqClosedWindowItem(); - virtual QPixmap icon(); + virtual QPixmap icon() const; + int numTabs() const; protected: int m_numTabs; }; +class KONQ_TESTS_EXPORT KonqClosedRemoteWindowItem : public KonqClosedWindowItem { +public: + KonqClosedRemoteWindowItem(const QString& title, const QString& groupName, const QString& configFileName, quint64 serialNumber, int numTabs, const QString& dbusService); + virtual ~KonqClosedRemoteWindowItem(); + virtual KConfigGroup& configGroup(); + virtual const KConfigGroup& configGroup() const; + bool equalsTo(const QString& groupName, const QString& configFileName) const; + QString dbusService() const { return m_dbusService; } + const QString& remoteGroupName() const { return m_remoteGroupName; } + const QString& remoteConfigFileName() const { return m_remoteConfigFileName; } +protected: + /** + * Actually reads the config file. Call to this function before calling to + * configGroup(). + */ + void readConfig(); + QString m_remoteGroupName; + QString m_remoteConfigFileName; + QString m_dbusService; + KConfigGroup* m_remoteConfigGroup; + KConfig* m_remoteConfig; +}; + #endif /* KONQCLOSEDITEM_H */ Index: src/konqundomanager.cpp =================================================================== --- src/konqundomanager.cpp (revisión: 794475) +++ src/konqundomanager.cpp (copia de trabajo) @@ -19,23 +19,36 @@ */ #include "konqundomanager.h" +#include "konqundomanageradaptor.h" +#include "konqundomanager_interface.h" #include +#include +#include +#include +#include +#include +#include #include +#include #include -#include #include #include #include +#include -class KonqUndoManagerCommunicatorPrivate { +Q_DECLARE_METATYPE(QList); + +class KonqClosedWindowsManagerPrivate +{ public: - KonqUndoManagerCommunicator instance; - QList m_closedWindowItemList; + KonqClosedWindowsManager instance; int m_maxNumClosedItems; + bool m_amIalone; }; -K_GLOBAL_STATIC(KonqUndoManagerCommunicatorPrivate, myKonqUndoManagerCommunicatorPrivate) +K_GLOBAL_STATIC(KonqClosedWindowsManagerPrivate, myKonqClosedWindowsManagerPrivate); + KonqUndoManager::KonqUndoManager(QObject* parent) : QObject(parent) { @@ -45,14 +58,12 @@ connect( KonqFileUndoManager::self(), SIGNAL(undoTextChanged(QString)), this, SLOT(slotFileUndoTextChanged(QString)) ); - connect(KonqUndoManagerCommunicator::self(), + connect(KonqClosedWindowsManager::self(), SIGNAL(addWindowInOtherInstances(KonqUndoManager *, KonqClosedWindowItem *)), this, SLOT( slotAddClosedWindowItem(KonqUndoManager *, KonqClosedWindowItem *) )); - connect(KonqUndoManagerCommunicator::self(), + connect(KonqClosedWindowsManager::self(), SIGNAL(removeWindowInOtherInstances(KonqUndoManager *, const KonqClosedWindowItem *)), this, SLOT( slotRemoveClosedWindowItem(KonqUndoManager *, const KonqClosedWindowItem *) )); - - populate(); } KonqUndoManager::~KonqUndoManager() @@ -62,22 +73,24 @@ disconnect( KonqFileUndoManager::self(), SIGNAL(undoTextChanged(QString)), this, SLOT(slotFileUndoTextChanged(QString)) ); - disconnect(KonqUndoManagerCommunicator::self(), + disconnect(KonqClosedWindowsManager::self(), SIGNAL(addWindowInOtherInstances(KonqUndoManager *, KonqClosedWindowItem *)), this, SLOT( slotAddClosedWindowItem(KonqUndoManager *, KonqClosedWindowItem *) )); - disconnect(KonqUndoManagerCommunicator::self(), + disconnect(KonqClosedWindowsManager::self(), SIGNAL(removeWindowInOtherInstances(KonqUndoManager *, const KonqClosedWindowItem *)), this, SLOT( slotRemoveClosedWindowItem(KonqUndoManager *, const KonqClosedWindowItem *) )); KonqFileUndoManager::decRef(); - clearClosedItemsList(); + + // Clear the closed item lists but only removed closed windows items + // in this window + clearClosedItemsList(true); } void KonqUndoManager::populate() { - kDebug(); const QList closedWindowItemList = - KonqUndoManagerCommunicator::self()->closedWindowItemList(); + KonqClosedWindowsManager::self()->closedWindowItemList(); foreach(KonqClosedWindowItem *closedWindowItem, closedWindowItemList) slotAddClosedWindowItem(0L, closedWindowItem); @@ -115,27 +128,11 @@ void KonqUndoManager::undo() { if (!m_closedItemList.isEmpty()) { - const KonqClosedItem* closedItem = m_closedItemList.first(); + KonqClosedItem* closedItem = m_closedItemList.first(); // Check what to undo - kDebug() << "closedTabItem->serialNumber:" << closedItem->serialNumber() - << ", KonqFileUndoManager currentCommandSerialNumber(): " << KonqFileUndoManager::self()->currentCommandSerialNumber(); - if (closedItem->serialNumber() > KonqFileUndoManager::self()->currentCommandSerialNumber()) { - m_closedItemList.removeFirst(); - const KonqClosedTabItem* closedTabItem = - dynamic_cast(closedItem); - const KonqClosedWindowItem* closedWindowItem = - dynamic_cast(closedItem); - if(closedTabItem) - emit openClosedTab(*closedTabItem); - else if(closedWindowItem) { - emit openClosedWindow(*closedWindowItem); - KonqUndoManagerCommunicator::self()->removeClosedWindowItem(this, closedWindowItem); - } - delete closedItem; - emit undoAvailable(this->undoAvailable()); - emit closedItemsListChanged(); + undoClosedItem(0); } else { KonqFileUndoManager::self()->undo(); } @@ -149,7 +146,7 @@ if(real_sender == this) return; - if(m_closedItemList.size() >= KonqUndoManagerCommunicator::self()->maxNumClosedItems()) + if(m_closedItemList.size() >= KonqClosedWindowsManager::self()->maxNumClosedItems()) { const KonqClosedItem* last = m_closedItemList.last(); const KonqClosedTabItem* lastTab = @@ -161,7 +158,6 @@ delete lastTab; } - kDebug(); m_closedItemList.prepend(closedWindowItem); emit undoTextChanged(i18n("Und&o: Closed Window")); emit undoAvailable(true); @@ -170,7 +166,7 @@ void KonqUndoManager::addClosedWindowItem(KonqClosedWindowItem *closedWindowItem) { - KonqUndoManagerCommunicator::self()->addClosedWindowItem(this, closedWindowItem); + KonqClosedWindowsManager::self()->addClosedWindowItem(this, closedWindowItem); } void KonqUndoManager::slotRemoveClosedWindowItem(KonqUndoManager *real_sender, const KonqClosedWindowItem *closedWindowItem) @@ -201,15 +197,21 @@ const KonqClosedTabItem* closedTabItem = dynamic_cast(closedItem); - const KonqClosedWindowItem* closedWindowItem = - dynamic_cast(closedItem); + KonqClosedRemoteWindowItem* closedRemoteWindowItem = + dynamic_cast(closedItem); + KonqClosedWindowItem* closedWindowItem = + dynamic_cast(closedItem); if(closedTabItem) emit openClosedTab(*closedTabItem); - else if(closedWindowItem) { + else if(closedRemoteWindowItem) { + emit openClosedWindow(*closedRemoteWindowItem); + KonqClosedWindowsManager::self()->removeClosedWindowItem(this, closedRemoteWindowItem); + } else if(closedWindowItem) { emit openClosedWindow(*closedWindowItem); - emit removeWindowInOtherInstances(this, closedWindowItem); + KonqClosedWindowsManager::self()->removeClosedWindowItem(this, closedWindowItem); + closedWindowItem->configGroup().deleteGroup(); } - delete closedTabItem; + delete closedItem; emit undoAvailable(this->undoAvailable()); emit undoTextChanged(this->undoText()); emit closedItemsListChanged(); @@ -235,7 +237,7 @@ void KonqUndoManager::addClosedTabItem(KonqClosedTabItem* closedTabItem) { - if(m_closedItemList.size() >= KonqUndoManagerCommunicator::self()->maxNumClosedItems()) + if(m_closedItemList.size() >= KonqClosedWindowsManager::self()->maxNumClosedItems()) { const KonqClosedItem* last = m_closedItemList.last(); const KonqClosedTabItem* lastTab = @@ -258,7 +260,7 @@ emit undoAvailable(this->undoAvailable()); } -void KonqUndoManager::clearClosedItemsList() +void KonqUndoManager::clearClosedItemsList(bool onlyInthisWindow) { // we only DELETE tab items! So we can't do this anymore: // qDeleteAll(m_closedItemList); @@ -268,13 +270,16 @@ KonqClosedItem *closedItem = *it; const KonqClosedTabItem* closedTabItem = dynamic_cast(closedItem); -// const KonqClosedWindowItem* closedWindowItem = -// dynamic_cast(closedItem); + const KonqClosedWindowItem* closedWindowItem = + dynamic_cast(closedItem); m_closedItemList.erase(it); if(closedTabItem) delete closedTabItem; - // we never delete closed window items here + else if (closedWindowItem && !onlyInthisWindow) { + KonqClosedWindowsManager::self()->removeClosedWindowItem(this, closedWindowItem, false); + delete closedWindowItem; + } } emit closedItemsListChanged(); emit undoAvailable(this->undoAvailable()); @@ -285,81 +290,426 @@ undoClosedItem(0); } -KonqUndoManagerCommunicator::KonqUndoManagerCommunicator() +KonqClosedWindowsManager::KonqClosedWindowsManager() { QTimer::singleShot(0, this, SLOT(readSettings())); + + qDBusRegisterMetaType >(); + + new KonqClosedWindowsManagerAdaptor ( this ); + + const QString dbusPath = "/KonqUndoManager"; + const QString dbusInterface = "org.kde.Konqueror.UndoManager"; + + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerObject( dbusPath, this ); + dbus.connect(QString(), dbusPath, dbusInterface, "notifyClosedWindowItem", this, SLOT(slotNotifyClosedWindowItem(QString,int,QString,QString,QDBusMessage))); + dbus.connect(QString(), dbusPath, dbusInterface, "notifyRemove", this, SLOT(slotNotifyRemove(QString,QString,QDBusMessage))); + dbus.connect(QString(), dbusPath, dbusInterface, "requestLocalClosedWindowItems", this, SLOT(slotRequestLocalClosedWindowItems(QDBusMessage))); + + QString filename = "closeditems/closeditems_" + QString::number(getpid()); + QString file = KStandardDirs::locateLocal("appdata", filename); + QFile::remove(file); + + m_konqClosedItemsConfig = new KConfig(filename, KConfig::SimpleConfig, "appdata"); + } -KonqUndoManagerCommunicator::~KonqUndoManagerCommunicator() +KonqClosedWindowsManager::~KonqClosedWindowsManager() { + saveConfig(); + + delete m_konqClosedItemsConfig; } -KonqUndoManagerCommunicator *KonqUndoManagerCommunicator::self() +KConfig* KonqClosedWindowsManager::config() { - return &myKonqUndoManagerCommunicatorPrivate->instance; + return m_konqClosedItemsConfig; } -void KonqUndoManagerCommunicator::addClosedWindowItem(KonqUndoManager -*real_sender, KonqClosedWindowItem *closedWindowItem) +KonqClosedWindowsManager *KonqClosedWindowsManager::self() { + return &myKonqClosedWindowsManagerPrivate->instance; +} + +void KonqClosedWindowsManager::addClosedWindowItem(KonqUndoManager +*real_sender, KonqClosedWindowItem *closedWindowItem, bool propagate) +{ // If we are off the limit, remove the last closed window item - if(myKonqUndoManagerCommunicatorPrivate->m_closedWindowItemList.size() >= + if(m_closedWindowItemList.size() >= maxNumClosedItems()) { - QList &closedWindowItemList = - myKonqUndoManagerCommunicatorPrivate->m_closedWindowItemList; - KonqClosedWindowItem* last = closedWindowItemList.last(); + KonqClosedWindowItem* last = m_closedWindowItemList.last(); + emit removeWindowInOtherInstances(0L, last); - closedWindowItemList.removeLast(); + emitNotifyClosedWindowItem(closedWindowItem); + + m_closedWindowItemList.removeLast(); delete last; } - myKonqUndoManagerCommunicatorPrivate->m_closedWindowItemList.prepend(closedWindowItem); + m_closedWindowItemList.prepend(closedWindowItem); emit addWindowInOtherInstances(real_sender, closedWindowItem); + + if(propagate) + emitNotifyClosedWindowItem(closedWindowItem); } -void KonqUndoManagerCommunicator::removeClosedWindowItem(KonqUndoManager -*real_sender, const KonqClosedWindowItem *closedWindowItem) +void KonqClosedWindowsManager::removeClosedWindowItem(KonqUndoManager +*real_sender, const KonqClosedWindowItem *closedWindowItem, bool propagate) { - QList &closedWindowItemList = - myKonqUndoManagerCommunicatorPrivate->m_closedWindowItemList; - QList::iterator it = qFind(closedWindowItemList.begin(), - closedWindowItemList.end(), closedWindowItem); + QList::iterator it = qFind(m_closedWindowItemList.begin(), + m_closedWindowItemList.end(), closedWindowItem); // If the item was found, remove it from the list - if(it != closedWindowItemList.end()) { - closedWindowItemList.erase(it); + if(it != m_closedWindowItemList.end()) { + m_closedWindowItemList.erase(it); } emit removeWindowInOtherInstances(real_sender, closedWindowItem); + + if(propagate) + emitNotifyRemove(closedWindowItem); } -const QList& KonqUndoManagerCommunicator::closedWindowItemList() +const QList& KonqClosedWindowsManager::closedWindowItemList() { - return myKonqUndoManagerCommunicatorPrivate->m_closedWindowItemList; + return m_closedWindowItemList; } -int KonqUndoManagerCommunicator::maxNumClosedItems() +int KonqClosedWindowsManager::maxNumClosedItems() { - return myKonqUndoManagerCommunicatorPrivate->m_maxNumClosedItems; + return m_maxNumClosedItems; } -void KonqUndoManagerCommunicator::setMaxNumClosedItems(int max) +void KonqClosedWindowsManager::setMaxNumClosedItems(int max) { - myKonqUndoManagerCommunicatorPrivate->m_maxNumClosedItems = qMax(1, max); + m_maxNumClosedItems = qMax(1, max); } -void KonqUndoManagerCommunicator::readSettings() +void KonqClosedWindowsManager::readSettings() { KSharedConfigPtr config = KGlobal::config(); KConfigGroup configGroup( config, "UndoManagerSettings"); - myKonqUndoManagerCommunicatorPrivate->m_maxNumClosedItems = configGroup.readEntry("Maximum number of Closed Items", 20 ); - myKonqUndoManagerCommunicatorPrivate->m_maxNumClosedItems = qMax(1, myKonqUndoManagerCommunicatorPrivate->m_maxNumClosedItems); + m_maxNumClosedItems = configGroup.readEntry("Maximum number of Closed Items", 20 ); + m_maxNumClosedItems = qMax(1, m_maxNumClosedItems); + + m_amIalone = true; + populate(); + + // If in 0.5 seconds no other konqueror instance answer, we will assume that + // we're alone and therefore instead of getting the undo closed window list + // via dbus, we'll read it from disk + QTimer::singleShot(500, this, SLOT(readConfig())); } -void KonqUndoManagerCommunicator::applySettings() + + +void KonqClosedWindowsManager::applySettings() { KConfigGroup configGroup(KSharedConfig::openConfig("konquerorrc"), "UndoManagerSettings"); - configGroup.writeEntry("Value youngerThan", myKonqUndoManagerCommunicatorPrivate->m_maxNumClosedItems ); + configGroup.writeEntry("Value youngerThan", m_maxNumClosedItems ); } + +static QString dbusService() +{ + return QDBusConnection::sessionBus().baseService(); +} + +/** + * Returns whether the DBUS call we are handling was a call from us self + */ +bool isSenderOfSignal( const QDBusMessage& msg ) +{ + return dbusService() == msg.service(); +} + +bool isSenderOfSignal( const QString& service ) +{ + return dbusService() == service; +} + +void KonqClosedWindowsManager::emitNotifyClosedWindowItem( + const KonqClosedWindowItem *closedWindowItem) +{ + emit notifyClosedWindowItem( closedWindowItem->title(), + closedWindowItem->numTabs(), + closedWindowItem->configGroup().config()->name(), + closedWindowItem->configGroup().name() ); +} + +void KonqClosedWindowsManager::emitNotifyRemove( + const KonqClosedWindowItem *closedWindowItem) +{ + const KonqClosedRemoteWindowItem* closedRemoteWindowItem = + dynamic_cast(closedWindowItem); + + // Here we do this because there's no need to call to configGroup() if it's + // a remote window item, and it would be error prone to be so, because + // it could give us a null pointer and konqueror would crash + if(closedRemoteWindowItem) + emit notifyRemove( closedRemoteWindowItem->remoteConfigFileName(), + closedRemoteWindowItem->remoteGroupName() ); + else + emit notifyRemove( closedWindowItem->configGroup().config()->name(), + closedWindowItem->configGroup().name() ); +} + +void KonqClosedWindowsManager::slotNotifyClosedWindowItem( + const QString& title, const int& numTabs, const QString& configFileName, + const QString& configGroup, const QString& service ) +{ + if ( isSenderOfSignal( service ) ) + return; + + // Create a new ClosedWindowItem and add it to the list + KonqClosedWindowItem* closedWindowItem = new KonqClosedRemoteWindowItem( + title, configGroup, configFileName, + KonqFileUndoManager::self()->newCommandSerialNumber(), numTabs, + service); + + // Add it to all the windows but don't propogate over dbus, + // as it already comes from dbus) + addClosedWindowItem(0L, closedWindowItem, false); +} + +void KonqClosedWindowsManager::slotNotifyClosedWindowItem( + const QString& title, const int& numTabs, const QString& configFileName, + const QString& configGroup, const QDBusMessage& msg ) +{ + slotNotifyClosedWindowItem(title, numTabs, configFileName, configGroup, + msg.service() ); +} + +void KonqClosedWindowsManager::slotNotifyRemove( + const QString& configFileName, const QString& configGroup, + const QDBusMessage& msg ) +{ + if ( isSenderOfSignal( msg ) ) + return; + + // Find the window item. It can be either remote or local + KonqClosedWindowItem* closedWindowItem = + findClosedRemoteWindowItem(configFileName, configGroup); + if(!closedWindowItem) + { + closedWindowItem = findClosedLocalWindowItem(configFileName, configGroup); + if(!closedWindowItem) + return; + } + + // Remove it in all the windows but don't propogate over dbus, + // as it already comes from dbus) + removeClosedWindowItem(0L, closedWindowItem, false); +} + +void KonqClosedWindowsManager::slotRequestLocalClosedWindowItems( + const QDBusMessage& msg) +{ + if ( isSenderOfSignal( msg ) ) + return; + + emitPong(msg.service()); + + + if ( closedWindowItemList().empty() ) + return; + + QList windowItems; + KonqClosedWindowItem *closedWindowItem; + for (QList::const_iterator it = closedWindowItemList().begin(); + it != closedWindowItemList().end(); ++it) + { + closedWindowItem = *it; + KonqClosedRemoteWindowItem* closedRemoteWindowItem = + dynamic_cast(closedWindowItem); + + if(!closedRemoteWindowItem && closedWindowItem) + { + // Add to the list + QByteArray data; + QDataStream stream( &data, QIODevice::WriteOnly ); + stream << closedWindowItem->title(); + stream << closedWindowItem->numTabs(); + stream << closedWindowItem->configGroup().config()->name(); + stream << closedWindowItem->configGroup().name(); + QVariant variant(data); + windowItems.append(variant); + } + } + + if(!windowItems.empty()) + { + org::kde::Konqueror::UndoManager interface(msg.service(), + "/KonqUndoManager", QDBusConnection::sessionBus(), this); + + if(!interface.isValid()) + return; + + interface.localClosedWindowItems(windowItems, dbusService()); + } +} + +void KonqClosedWindowsManager::emitPong(const QString & service) +{ + org::kde::Konqueror::UndoManager interface(service, + "/KonqUndoManager", QDBusConnection::sessionBus(), this); + + if(!interface.isValid()) + return; + + interface.pong(); +} + +void KonqClosedWindowsManager::localClosedWindowItems( + const QList& windowItems, const QString& service) +{ + + QListIterator it(windowItems); + for (it.toBack(); it.hasPrevious(); ) + { + QString title, configFileName, configGroup; + int numTabs; + QByteArray data = (it.previous()).toByteArray(); + QDataStream stream( const_cast( &data ), QIODevice::ReadOnly ); + stream >> title >> numTabs >> configFileName >> configGroup; + slotNotifyClosedWindowItem(title, numTabs, configFileName, configGroup, + service); + } + +} + +void KonqClosedWindowsManager::pong() +{ + m_amIalone = false; +} + +KonqClosedRemoteWindowItem* KonqClosedWindowsManager::findClosedRemoteWindowItem( + const QString& configFileName, + const QString& configGroup) +{ + KonqClosedRemoteWindowItem* closedRemoteWindowItem = 0L; + for (QList::const_iterator it = closedWindowItemList().begin(); + it != closedWindowItemList().end(); ++it) + { + closedRemoteWindowItem = dynamic_cast(*it); + + if(closedRemoteWindowItem && + closedRemoteWindowItem->equalsTo(configFileName, configGroup)) + return closedRemoteWindowItem; + } + + return closedRemoteWindowItem; +} + +KonqClosedWindowItem* KonqClosedWindowsManager::findClosedLocalWindowItem( + const QString& configFileName, + const QString& configGroup) +{ + KonqClosedWindowItem* closedWindowItem = 0L; + for (QList::const_iterator it = closedWindowItemList().begin(); + it != closedWindowItemList().end(); ++it) + { + closedWindowItem = *it; + KonqClosedRemoteWindowItem* closedRemoteWindowItem = + dynamic_cast(closedWindowItem); + + if(!closedRemoteWindowItem && closedWindowItem && + closedWindowItem->configGroup().config()->name() == configFileName && + closedWindowItem->configGroup().name() == configGroup) + return closedWindowItem; + } + + return closedWindowItem; +} + +void KonqClosedWindowsManager::populate() +{ + emit requestLocalClosedWindowItems(); +} + +void KonqClosedWindowsManager::removeClosedItemsConfigFiles() +{ + QString dir= KStandardDirs::locateLocal("appdata", "closeditems/"); + + QDirIterator it(dir, QDir::Writable|QDir::Files); + while (it.hasNext()) + { + QFile::remove(it.next()); + } +} + + +void KonqClosedWindowsManager::saveConfig() +{ + // Create / overwrite the saved closed windows list + QString filename = "closeditems_saved"; + QString file = KStandardDirs::locateLocal("appdata", filename); + if(QFile::exists(file)) + QFile::remove(file); + + KConfig *config = new KConfig(filename, KConfig::SimpleConfig, "appdata"); + + // Populate the config file + KonqClosedWindowItem* closedWindowItem = 0L; + uint counter = closedWindowItemList().size()-1; + for (QList::const_iterator it = closedWindowItemList().begin(); + it != closedWindowItemList().end(); ++it, --counter) + { + closedWindowItem = *it; + KConfigGroup configGroup(config, "Closed_Window" + QString::number(counter)); + configGroup.writeEntry("title", closedWindowItem->title()); + configGroup.writeEntry("numTabs", closedWindowItem->numTabs()); + closedWindowItem->configGroup().copyTo(&configGroup); + } + + KConfigGroup configGroup(config, "General"); + configGroup.writeEntry("Number of Closed Windows", closedWindowItemList().size()); + + delete config; +} + +void KonqClosedWindowsManager::readConfig() +{ + // We will read the configuration file *only* if we are alone, which means + // only if we couldn't get the closed windows list via dbus because no + // dbus instance answered/exists + if(!m_amIalone) + return; + + // Simplification: we assume there was no time to open and close + // a konqueror window in 500ms of konqueror life time and thus there + // shouldn't be any file in closeditem/* to do some houskeeping everytime + // konqueror starts + removeClosedItemsConfigFiles(); + + QString filename = "closeditems_saved"; + QString file = KStandardDirs::locateLocal("appdata", filename); + + // If the config file doesn't exists, there's nothing to read + if(!QFile::exists(file)) + return; + + KConfig config(filename, KConfig::SimpleConfig, "appdata"); + KConfigGroup generalGroup(&config, "General"); + int numClosedWindows = generalGroup.readEntry("Number of Closed Windows", 0); + + for(int i = 0; i < numClosedWindows; i++) + { + // For each item, create a new ClosedWindowItem + KConfigGroup configGroup(&config, "Closed_Window" + QString::number(i)); + QString title = configGroup.readEntry("title", i18n("no name")); + int numTabs = configGroup.readEntry("numTabs", 0); + + KonqClosedWindowItem* closedWindowItem = new KonqClosedWindowItem( + title, KonqFileUndoManager::self()->newCommandSerialNumber(), + numTabs); + configGroup.copyTo(&closedWindowItem->configGroup()); + configGroup.writeEntry("foo", 0); + closedWindowItem->configGroup().config()->sync(); + + // Add the item to all the windows and propagate over dbus + addClosedWindowItem(0L, closedWindowItem, true); + } +}