Bug 109793 - open file tab-order should be restored as part of the project session
Summary: open file tab-order should be restored as part of the project session
Status: RESOLVED FIXED
Alias: None
Product: kdevplatform
Classification: Developer tools
Component: sublime (show other bugs)
Version: git master
Platform: Gentoo Packages Linux
: NOR wishlist
Target Milestone: ---
Assignee: kdevelop-bugs-null
URL:
Keywords:
: 190121 207342 212479 232567 237704 248022 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-07-28 20:01 UTC by Peter Kirk
Modified: 2010-08-16 10:19 UTC (History)
7 users (show)

See Also:
Latest Commit:
Version Fixed In: 1.1.0


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Kirk 2005-07-28 20:01:39 UTC
Version:           3.2.1 (using KDE KDE 3.4.1)
Installed from:    Gentoo Packages

Running kdevelop in IDEAI mode with "Tabbed Browsing" set to "Open new tab after current tab" (all this can be configured at Settings->Configure KDevelop->User Interface).
The problem is that in the .kdevses file the order of files is not saved correctly. Every file that I open is appended to the end of the .kdevses file, even if I open the file while a tab is highlighted that is not the last, which (combined with the "Open new tab after current tab") leads the file to be opened next to the selected tab, instead of the end. 
To reproduce:
Open two files, "A" and "B", now the tab in kdevelop would look like: "| A | B |", now I select the file "A", and open the file "C". This leads to the kdevelop tabs looking like: "| A | C | B |". Now I close the project, reopen the project and get: "| A | B | C |".
Comment 1 Jens Dagerbo 2006-04-27 22:07:27 UTC
I just looked at this again and it doesn't seem rational to even try to get this working for the various KMDI UI modes when we're working to remove KMDI altogether in the next version.

Personally, I don't want a tabbar, but if we end up having one, it should try to maintain file order between project reloads.

Changing to wishlist. (It was technically never a bug - the code didn't try to do this.)
Comment 2 Maciej Pilichowski 2006-04-28 10:15:26 UTC
> it doesn't seem rational to even try to get this working 

It is quit opposite to

> I don't want a tabbar, but if we end up having one, it should try to
> maintain file order between project reloads. 

above sentence, don't you think?
 
> (It was technically never a bug - the code didn't try to do this.) 

Code is not the guideline, but the project /or HIG/ is. And I doubt there is the section saying something like this "if the user opened several documents, at the next session open them in random or pseudo-random order".

Bug doesn't always mean some messed up function but lack of a function too!
Comment 3 Ross Collins 2006-07-26 11:58:33 UTC
Although this isn't technically a bug with the code. It's certainly a bug with the design. If your are to have the concept of projects with component files displayed in tabs then tab order should be maintained. The non-persistence of tab-order is clearly a design oversight, and KDevelop would be a much more professional looking project if it didn't randomly reorganise project tabs between open and close cycles. I hope the KDevelop developers are aware of this and consider a solution for the next version.
Comment 4 Alessandro Garberi 2007-02-26 00:18:11 UTC
I can confirm this behaviour also with KDevelop 3.4.0.

Please solve this bug!
Comment 5 Marian Ciobanu 2007-11-03 14:04:24 UTC
*** This bug has been confirmed by popular vote. ***
Comment 6 Marian Ciobanu 2007-11-03 14:37:39 UTC
From the user's point of view this is clearly a bug and not some misplaced wish. If the code didn't ever try to do this it's because it wasn't properly designed. Why allow the user to move the tabs in the current session to establish a tab order and then restore them in a different order? It's more consistent to not restore them at all. Then at least I know what to expect.

Also, this looks like a 15-minutes fix for somebody who knows the code, so it seems a bit much for this to stay as a "wishlist" for more than 2 years expecting some "new version" where the problem will go away.

Now I understand that some people don't use tabs (and Jens is one of them, so it's easy to him to dismiss it), but for those of us who use tabs, fixing this would make working with KDevelop significantly more enjoyable, and to me that justifies doing the irrational thing and actually fix this now, especially if the fix is easy.
Comment 7 Andreas Pakulat 2007-11-03 16:12:12 UTC
Don't try to estimate time for code-changes if you don't know the code ;)

Apart from that there's simply nearly no work, and certainly no feature-work, done in KDevelop3. We need all the time we can get to release KDevelop4 before KDE 5.0 is released already. 

And no this is a wishlist, because its a new feature, the moving-support is not part of KDevelop but of the underlying kdelibs. If that makes you happy, its a 1-line fix to disable the movement of tabs ;)
Comment 8 Marian Ciobanu 2008-07-07 09:57:11 UTC
I decided to spend several hours on a workaround for this issue, so I created an external application that opens .kdevses files and allows the user change the tab order, so the next time the user opens the corresponding project the tabs are where they should be.

For some use cases this workaround is probably unacceptable, but for me it's good enough, so I'm making it available to anybody who might want it at http://www.clicknet.ro/mciobanu/arrangekdeveloptabs

Perhaps my time would have been better spent on actually fixing the bug (namely get a notification when the tab order is changed and update the internal status to reflect this), but I feel that the best I can achieve in several hours is something that works in some cases. (Due to limited knowledge of Qt 3 and no knowledge of KDevelop's code, I'm bound to miss important details unless I devote a lot more time to actually understand what's going on.)

Ciobi
Comment 9 Andreas Pakulat 2009-04-20 12:48:05 UTC
*** Bug 190121 has been marked as a duplicate of this bug. ***
Comment 10 Andreas Pakulat 2009-09-14 13:39:42 UTC
*** Bug 207342 has been marked as a duplicate of this bug. ***
Comment 11 Andreas Pakulat 2009-10-31 08:52:12 UTC
*** Bug 212479 has been marked as a duplicate of this bug. ***
Comment 12 Andreas Pakulat 2010-03-29 14:08:00 UTC
*** Bug 232567 has been marked as a duplicate of this bug. ***
Comment 13 Julien Michot 2010-04-17 23:37:30 UTC
I have the same bug with the "working sets", when I switch the a different "working set" and go back the tab-ordering is...random ! nothing is saved.
Comment 14 Andreas Pakulat 2010-05-15 14:31:55 UTC
*** Bug 237704 has been marked as a duplicate of this bug. ***
Comment 15 Niko Sams 2010-07-25 12:10:19 UTC
commit 165f5483f2b1e06d1202da38e82a6a1c06755e47
Author: Niko Sams <niko.sams@gmail.com>
Date:   Sat Jul 24 21:09:18 2010 +0200

    correctly restore tab order when loading workingset/session
    
    - don't let Sublime::Container choose the position where new Tabs are inserted
    - instead insert it into the AreaIndex at the correct position - depending on the "Open new
      Tabs after current" setting
    - "Open new Tabs after current" setting had to be moved from Sublime::Container
      to Sublime::Controller
    - to load this setting Sublime::Controller::loadSettings was added
    
    BUG: 109793

diff --git a/shell/settings/uipreferences.cpp b/shell/settings/uipreferences.cpp
index bf55cf3..43c63d6 100644
--- a/shell/settings/uipreferences.cpp
+++ b/shell/settings/uipreferences.cpp
@@ -62,4 +62,5 @@ void UiPreferences::save()
     UiController *uiController = Core::self()->uiControllerInternal();
     foreach (Sublime::MainWindow *window, uiController->mainWindows())
         (static_cast<KDevelop::MainWindow*>(window))->loadSettings();
+    uiController->loadSettings();
 }
diff --git a/sublime/area.cpp b/sublime/area.cpp
index c75200d..21d1545 100644
--- a/sublime/area.cpp
+++ b/sublime/area.cpp
@@ -161,18 +161,19 @@ void Area::setActiveView(View* view)
     d->activeView = view;
 }
 
-void Sublime::Area::addView(View *view, AreaIndex *index)
+void Area::addView(View *view, AreaIndex *index)
 {
-    index->add(view);
-    connect(view, SIGNAL(positionChanged(Sublime::View*, int)), this, SLOT(positionChanged(Sublime::View*, int)));
-    kDebug() << "view added in" << this;
+    addViewSilently(view, index);
     emit viewAdded(index, view);
-    connect(this, SIGNAL(destroyed()), view, SLOT(deleteLater()));
 }
 
-void Sublime::Area::addViewSilently(View *view, AreaIndex *index)
+void Area::addViewSilently(View *view, AreaIndex *index)
 {
-    index->add(view);
+    View *after = 0;
+    if (controller()->openAfterCurrent()) {
+        after = activeView();
+    }
+    index->add(view, after);
     connect(view, SIGNAL(positionChanged(Sublime::View*, int)), this, SLOT(positionChanged(Sublime::View*, int)));
     kDebug() << "view added in" << this;
     connect(this, SIGNAL(destroyed()), view, SLOT(deleteLater()));
diff --git a/sublime/areaindex.cpp b/sublime/areaindex.cpp
index 48f7432..a27c375 100644
--- a/sublime/areaindex.cpp
+++ b/sublime/areaindex.cpp
@@ -103,7 +103,7 @@ void AreaIndex::add(View *view, View *after)
         return;
 
     if (after)
-        d->views.insert(d->views.indexOf(after), view);
+        d->views.insert(d->views.indexOf(after)+1, view);
     else
         d->views.append(view);
 }
diff --git a/sublime/container.cpp b/sublime/container.cpp
index 87557e1..fac423c 100644
--- a/sublime/container.cpp
+++ b/sublime/container.cpp
@@ -82,8 +82,6 @@ struct ContainerPrivate {
     QLabel *fileStatus;
     QLabel *statusCorner;
     QPointer<QWidget> leftCornerWidget;
-
-    bool openAfterCurrent;
 };
 
 class UnderlinedLabel: public QLabel {
@@ -188,8 +186,6 @@ Container::Container(QWidget *parent)
     d->tabBar->setTabsClosable(true);
     d->tabBar->setMovable(true);
     d->tabBar->setExpanding(false);
-
-    setOpenAfterCurrent(group.readEntry("TabBarOpenAfterCurrent", 1) == 1);
 }
 
 void Container::setLeftCornerWidget(QWidget* widget)
@@ -253,13 +249,13 @@ void Container::widgetActivated(int idx)
     }
 }
 
-void Container::addWidget(View *view)
+void Container::addWidget(View *view, int position)
 {
     QWidget *w = view->widget(this);
     int idx = 0;
-    if (d->openAfterCurrent)
+    if (position != -1)
     {
-        idx = d->stack->insertWidget(d->stack->currentIndex()+1, w);
+        idx = d->stack->insertWidget(position, w);
         view->notifyPositionChanged(idx);
     }
     else
@@ -394,11 +390,6 @@ void Container::setTabBarHidden(bool hide)
     }
 }
 
-void Container::setOpenAfterCurrent(bool after)
-{
-    d->openAfterCurrent = after;
-}
-
 void Container::tabMoved(int from, int to)
 {
     QWidget *w = d->stack->widget(from);
diff --git a/sublime/container.h b/sublime/container.h
index 1dad7c3..6b79df7 100644
--- a/sublime/container.h
+++ b/sublime/container.h
@@ -47,7 +47,7 @@ public:
     ~Container();
 
     /**Adds the widget for given @p view to the container.*/
-    void addWidget(View *view);
+    void addWidget(Sublime::View* view, int position = -1);
     /**Removes the widget from the container.*/
     void removeWidget(QWidget *w);
     /** @return true if widget is placed inside this container.*/
@@ -62,7 +62,6 @@ public:
     View *viewForWidget(QWidget *w) const;
 
     void setTabBarHidden(bool hide);
-    void setOpenAfterCurrent(bool after);
 
     /** Adds a corner widget to the left of this containers tab-bar. To remove it again, just delete it.
       * The ownership otherwise goes to the container. */
diff --git a/sublime/controller.cpp b/sublime/controller.cpp
index 2c6e95f..31765df 100644
--- a/sublime/controller.cpp
+++ b/sublime/controller.cpp
@@ -25,6 +25,7 @@
 #include <QApplication>
 
 #include <kdebug.h>
+#include <KSharedConfig>
 
 #include "area.h"
 #include "view.h"
@@ -94,6 +95,7 @@ struct ControllerPrivate {
     QMap<Area*, MainWindow*> shownAreas;
     QList<MainWindow*> controlledWindows;
     QVector< QList<Area*> > mainWindowAreas;
+    bool openAfterCurrent;
 };
 
 
@@ -108,7 +110,7 @@ Controller::Controller(QObject *parent)
 
 void Controller::init()
 {
-
+    loadSettings();
     qApp->installEventFilter(this);
 }
 
@@ -383,6 +385,17 @@ void Controller::setStatusIcon(Document * document, const QIcon & icon)
     document->setStatusIcon(icon);
 }
 
+void Controller::loadSettings()
+{
+    KConfigGroup uiGroup = KGlobal::config()->group("UiSettings");
+    d->openAfterCurrent = (uiGroup.readEntry("TabBarOpenAfterCurrent", 1) == 1);
+}
+
+bool Controller::openAfterCurrent() const
+{
+    return d->openAfterCurrent;
+}
+
 }
 
 #include "controller.moc"
diff --git a/sublime/controller.h b/sublime/controller.h
index e67369f..3e44beb 100644
--- a/sublime/controller.h
+++ b/sublime/controller.h
@@ -143,6 +143,9 @@ public:
 
     void setStatusIcon(Document* document, const QIcon& icon);
 
+    bool openAfterCurrent() const;
+
+    void loadSettings();
 public Q_SLOTS:
     //@todo adymo: this should not be a part of public API
     /**Area can connect to this slot to release itself from its mainwindow.*/
diff --git a/sublime/mainwindow.cpp b/sublime/mainwindow.cpp
index 7d96f73..51513a0 100644
--- a/sublime/mainwindow.cpp
+++ b/sublime/mainwindow.cpp
@@ -335,7 +335,6 @@ void MainWindow::loadSettings()
     foreach (Container *container, findChildren<Container*>())
     {
         container->setTabBarHidden(uiGroup.readEntry("TabBarVisibility", 1) == 0);
-        container->setOpenAfterCurrent(uiGroup.readEntry("TabBarOpenAfterCurrent", 1) == 1);
     }
 
     cg.sync();
diff --git a/sublime/mainwindow_p.cpp b/sublime/mainwindow_p.cpp
index 8548c11..80efa90 100644
--- a/sublime/mainwindow_p.cpp
+++ b/sublime/mainwindow_p.cpp
@@ -241,6 +241,8 @@ Area::WalkerMode MainWindowPrivate::ViewCreator::operator() (AreaIndex *index)
         else
             container = qobject_cast<Container*>(splitter->widget(0));
         container->show();
+
+        int position = 0;
         foreach (View *view, index->views())
         {
             QWidget *widget = view->widget(container);
@@ -249,10 +251,11 @@ Area::WalkerMode MainWindowPrivate::ViewCreator::operator() (AreaIndex *index)
                 widget->installEventFilter(d);
                 foreach (QWidget* w, widget->findChildren<QWidget*>())
                     w->installEventFilter(d);
-                container->addWidget(view);
+                container->addWidget(view, position);
                 d->viewContainers[view] = container;
                 d->widgetToView[widget] = view;
             }
+            position++;
         }
     }
     return Area::ContinueWalker;
Comment 16 Niko Sams 2010-08-02 17:57:35 UTC
commit ec1564db0155bef0e79d8455e6e9f16bfec699a5
Author: Niko Sams <niko.sams@gmail.com>
Date:   Sat Jul 24 21:09:18 2010 +0200

    correctly restore tab order when loading workingset/session
    
    - don't let Sublime::Container choose the position where new Tabs are inserted
    - instead insert it into the AreaIndex at the correct position - depending on the "Open new
      Tabs after current" setting
    - "Open new Tabs after current" setting had to be moved from Sublime::Container
      to Sublime::Controller
    - to load this setting Sublime::Controller::loadSettings was added
    
    BUG: 109793

diff --git a/shell/settings/uipreferences.cpp b/shell/settings/uipreferences.cpp
index bf55cf3..43c63d6 100644
--- a/shell/settings/uipreferences.cpp
+++ b/shell/settings/uipreferences.cpp
@@ -62,4 +62,5 @@ void UiPreferences::save()
     UiController *uiController = Core::self()->uiControllerInternal();
     foreach (Sublime::MainWindow *window, uiController->mainWindows())
         (static_cast<KDevelop::MainWindow*>(window))->loadSettings();
+    uiController->loadSettings();
 }
diff --git a/sublime/area.cpp b/sublime/area.cpp
index c75200d..21d1545 100644
--- a/sublime/area.cpp
+++ b/sublime/area.cpp
@@ -161,18 +161,19 @@ void Area::setActiveView(View* view)
     d->activeView = view;
 }
 
-void Sublime::Area::addView(View *view, AreaIndex *index)
+void Area::addView(View *view, AreaIndex *index)
 {
-    index->add(view);
-    connect(view, SIGNAL(positionChanged(Sublime::View*, int)), this, SLOT(positionChanged(Sublime::View*, int)));
-    kDebug() << "view added in" << this;
+    addViewSilently(view, index);
     emit viewAdded(index, view);
-    connect(this, SIGNAL(destroyed()), view, SLOT(deleteLater()));
 }
 
-void Sublime::Area::addViewSilently(View *view, AreaIndex *index)
+void Area::addViewSilently(View *view, AreaIndex *index)
 {
-    index->add(view);
+    View *after = 0;
+    if (controller()->openAfterCurrent()) {
+        after = activeView();
+    }
+    index->add(view, after);
     connect(view, SIGNAL(positionChanged(Sublime::View*, int)), this, SLOT(positionChanged(Sublime::View*, int)));
     kDebug() << "view added in" << this;
     connect(this, SIGNAL(destroyed()), view, SLOT(deleteLater()));
diff --git a/sublime/areaindex.cpp b/sublime/areaindex.cpp
index 48f7432..a27c375 100644
--- a/sublime/areaindex.cpp
+++ b/sublime/areaindex.cpp
@@ -103,7 +103,7 @@ void AreaIndex::add(View *view, View *after)
         return;
 
     if (after)
-        d->views.insert(d->views.indexOf(after), view);
+        d->views.insert(d->views.indexOf(after)+1, view);
     else
         d->views.append(view);
 }
diff --git a/sublime/container.cpp b/sublime/container.cpp
index 87557e1..fac423c 100644
--- a/sublime/container.cpp
+++ b/sublime/container.cpp
@@ -82,8 +82,6 @@ struct ContainerPrivate {
     QLabel *fileStatus;
     QLabel *statusCorner;
     QPointer<QWidget> leftCornerWidget;
-
-    bool openAfterCurrent;
 };
 
 class UnderlinedLabel: public QLabel {
@@ -188,8 +186,6 @@ Container::Container(QWidget *parent)
     d->tabBar->setTabsClosable(true);
     d->tabBar->setMovable(true);
     d->tabBar->setExpanding(false);
-
-    setOpenAfterCurrent(group.readEntry("TabBarOpenAfterCurrent", 1) == 1);
 }
 
 void Container::setLeftCornerWidget(QWidget* widget)
@@ -253,13 +249,13 @@ void Container::widgetActivated(int idx)
     }
 }
 
-void Container::addWidget(View *view)
+void Container::addWidget(View *view, int position)
 {
     QWidget *w = view->widget(this);
     int idx = 0;
-    if (d->openAfterCurrent)
+    if (position != -1)
     {
-        idx = d->stack->insertWidget(d->stack->currentIndex()+1, w);
+        idx = d->stack->insertWidget(position, w);
         view->notifyPositionChanged(idx);
     }
     else
@@ -394,11 +390,6 @@ void Container::setTabBarHidden(bool hide)
     }
 }
 
-void Container::setOpenAfterCurrent(bool after)
-{
-    d->openAfterCurrent = after;
-}
-
 void Container::tabMoved(int from, int to)
 {
     QWidget *w = d->stack->widget(from);
diff --git a/sublime/container.h b/sublime/container.h
index 1dad7c3..6b79df7 100644
--- a/sublime/container.h
+++ b/sublime/container.h
@@ -47,7 +47,7 @@ public:
     ~Container();
 
     /**Adds the widget for given @p view to the container.*/
-    void addWidget(View *view);
+    void addWidget(Sublime::View* view, int position = -1);
     /**Removes the widget from the container.*/
     void removeWidget(QWidget *w);
     /** @return true if widget is placed inside this container.*/
@@ -62,7 +62,6 @@ public:
     View *viewForWidget(QWidget *w) const;
 
     void setTabBarHidden(bool hide);
-    void setOpenAfterCurrent(bool after);
 
     /** Adds a corner widget to the left of this containers tab-bar. To remove it again, just delete it.
       * The ownership otherwise goes to the container. */
diff --git a/sublime/controller.cpp b/sublime/controller.cpp
index 2c6e95f..31765df 100644
--- a/sublime/controller.cpp
+++ b/sublime/controller.cpp
@@ -25,6 +25,7 @@
 #include <QApplication>
 
 #include <kdebug.h>
+#include <KSharedConfig>
 
 #include "area.h"
 #include "view.h"
@@ -94,6 +95,7 @@ struct ControllerPrivate {
     QMap<Area*, MainWindow*> shownAreas;
     QList<MainWindow*> controlledWindows;
     QVector< QList<Area*> > mainWindowAreas;
+    bool openAfterCurrent;
 };
 
 
@@ -108,7 +110,7 @@ Controller::Controller(QObject *parent)
 
 void Controller::init()
 {
-
+    loadSettings();
     qApp->installEventFilter(this);
 }
 
@@ -383,6 +385,17 @@ void Controller::setStatusIcon(Document * document, const QIcon & icon)
     document->setStatusIcon(icon);
 }
 
+void Controller::loadSettings()
+{
+    KConfigGroup uiGroup = KGlobal::config()->group("UiSettings");
+    d->openAfterCurrent = (uiGroup.readEntry("TabBarOpenAfterCurrent", 1) == 1);
+}
+
+bool Controller::openAfterCurrent() const
+{
+    return d->openAfterCurrent;
+}
+
 }
 
 #include "controller.moc"
diff --git a/sublime/controller.h b/sublime/controller.h
index e67369f..3e44beb 100644
--- a/sublime/controller.h
+++ b/sublime/controller.h
@@ -143,6 +143,9 @@ public:
 
     void setStatusIcon(Document* document, const QIcon& icon);
 
+    bool openAfterCurrent() const;
+
+    void loadSettings();
 public Q_SLOTS:
     //@todo adymo: this should not be a part of public API
     /**Area can connect to this slot to release itself from its mainwindow.*/
diff --git a/sublime/mainwindow.cpp b/sublime/mainwindow.cpp
index 7d96f73..51513a0 100644
--- a/sublime/mainwindow.cpp
+++ b/sublime/mainwindow.cpp
@@ -335,7 +335,6 @@ void MainWindow::loadSettings()
     foreach (Container *container, findChildren<Container*>())
     {
         container->setTabBarHidden(uiGroup.readEntry("TabBarVisibility", 1) == 0);
-        container->setOpenAfterCurrent(uiGroup.readEntry("TabBarOpenAfterCurrent", 1) == 1);
     }
 
     cg.sync();
diff --git a/sublime/mainwindow_p.cpp b/sublime/mainwindow_p.cpp
index 8548c11..80efa90 100644
--- a/sublime/mainwindow_p.cpp
+++ b/sublime/mainwindow_p.cpp
@@ -241,6 +241,8 @@ Area::WalkerMode MainWindowPrivate::ViewCreator::operator() (AreaIndex *index)
         else
             container = qobject_cast<Container*>(splitter->widget(0));
         container->show();
+
+        int position = 0;
         foreach (View *view, index->views())
         {
             QWidget *widget = view->widget(container);
@@ -249,10 +251,11 @@ Area::WalkerMode MainWindowPrivate::ViewCreator::operator() (AreaIndex *index)
                 widget->installEventFilter(d);
                 foreach (QWidget* w, widget->findChildren<QWidget*>())
                     w->installEventFilter(d);
-                container->addWidget(view);
+                container->addWidget(view, position);
                 d->viewContainers[view] = container;
                 d->widgetToView[widget] = view;
             }
+            position++;
         }
     }
     return Area::ContinueWalker;
Comment 17 Niko Sams 2010-08-16 10:19:45 UTC
*** Bug 248022 has been marked as a duplicate of this bug. ***