[prev in list] [next in list] [prev in thread] [next in thread]
List: kdevelop-devel
Subject: Preliminary breadcrumbs implementation - patch
From: <bisc122006 () mail ! ru>
Date: 2008-11-22 14:04:34
Message-ID: E1L3t6A-000F3M-00.bisc122006-mail-ru () f112 ! mail ! ru
[Download RAW message or body]
Preliminary breadcrumbs implementation
This patch is work-in-progress towards 'breadcrumbs' nagivation in KDevelop, that \
hopefully will be able to replace tabs one day. The patch is preliminary, and is not \
meant to be committed right now, but I wanted to check if the general direction is \
right.
-On each tab a special 'breadcrumbs' navigation bar, showing the path from root to \
current document, is added.
-The list of files is split into 2 categories: files that have already been opened \
somewhen and other files. This feature is now in development and maybe will be \
changed, so in this version files are split into categories using the filename \
lenght, just for testing purposes.
Intended changes:
-Implement real code for detecting what files are open - the current code is dummy.
-Improve the popup dialog with files.
-Include project name and current function in the navigator.
-Change in general appearance.
--
Best regards,
Ruchkin I
["=?koi8-r?Q?kdevelop=5Fpatch=5Fscreenshot3.png?=" (image/png)]
["=?koi8-r?Q?kdevplatform=5Fpatch.diff?=" (text/x-diff)]
Index: shell/uicontroller.h
===================================================================
--- shell/uicontroller.h (revision 875444)
+++ shell/uicontroller.h (working copy)
@@ -93,6 +93,7 @@
public Q_SLOTS:
void raiseToolView(Sublime::View * view);
+ void onOpenDocumentRequest(const KUrl &);
private:
class UiControllerPrivate* const d;
Index: shell/uicontroller.cpp
===================================================================
--- shell/uicontroller.cpp (revision 875444)
+++ shell/uicontroller.cpp (working copy)
@@ -148,7 +148,9 @@
UiController::UiController(Core *core)
:Sublime::Controller(0), IUiController(), d(new UiControllerPrivate(this))
{
- setObjectName("UiController");
+ connect(d->defaultMainWindow, SIGNAL(openDocumentRequest(const KUrl \
&)),this,SLOT(onOpenDocumentRequest(const KUrl &))); +
+ setObjectName("UiController");
// FIXME: restore.
#if 0
KSettings::Dispatcher::registerComponent( KGlobal::mainComponent(),
@@ -584,6 +586,10 @@
mw->registerStatus(status);
}
+void UiController::onOpenDocumentRequest(const KUrl &url){
+ KDevelop::ICore::self()->documentController()->openDocument(url);
}
+}
+
#include "uicontroller.moc"
Index: sublime/mainwindow_p.h
===================================================================
--- sublime/mainwindow_p.h (revision 875444)
+++ sublime/mainwindow_p.h (working copy)
@@ -107,6 +107,7 @@
void slotDockShown(Sublime::View*, Sublime::Position, bool);
void widgetResized(IdealMainLayout::Role role, int thickness);
void widgetCloseRequest(QWidget* widget);
+ void viewCloseRequest(View* view);
protected:
virtual bool eventFilter(QObject *, QEvent *event);
Index: sublime/urldocument.h
===================================================================
--- sublime/urldocument.h (revision 875444)
+++ sublime/urldocument.h (working copy)
@@ -39,11 +39,13 @@
virtual QString documentSpecifier() const;
+ KUrl url() const;
+
+ void setUrl(const KUrl& newUrl);
protected:
virtual QWidget *createViewWidget(QWidget *parent = 0);
- KUrl url() const;
- void setUrl(const KUrl& newUrl);
+
private:
struct UrlDocumentPrivate * const d;
Index: sublime/fileview.h
===================================================================
--- sublime/fileview.h (revision 0)
+++ sublime/fileview.h (revision 0)
@@ -0,0 +1,28 @@
+#ifndef FILEVIEW_H
+#define FILEVIEW_H
+
+#include "filter.h"
+
+class FileView : public QDialog
+{
+Q_OBJECT
+public:
+ FileView(QPoint, const QString &);
+ ~FileView();
+ void leaveEvent ( QEvent * ) ;
+ void enterEvent ( QEvent * ) ;
+public slots:
+ void itemClicked(QModelIndex);
+ void itemClickedReverse(QModelIndex);
+signals:
+ void itemSelected(const QString & );
+private:
+ QDirModel *model1,*model2;
+ Filter *proxy1,*proxy2;
+ QTreeView *view1, *view2;
+ QLabel *label1, *label2;
+ QVBoxLayout *layout;
+};
+
+
+#endif
Property changes on: sublime/fileview.h
___________________________________________________________________
Name: svn:executable
+ *
Index: sublime/mainwindow.h
===================================================================
--- sublime/mainwindow.h (revision 875444)
+++ sublime/mainwindow.h (working copy)
@@ -84,7 +84,9 @@
void activeToolViewChanged(Sublime::View*);
/**Emitted when the user interface settings have changed.*/
void settingsLoaded();
-
+ /**Emitted when user selects new file via navigator.*/
+ void openDocumentRequest(const KUrl &);
+
protected:
public: // FIXME?
/**Saves size/toolbar/menu/statusbar settings to the global configuration file.
Index: sublime/container.cpp
===================================================================
--- sublime/container.cpp (revision 875444)
+++ sublime/container.cpp (working copy)
@@ -22,6 +22,7 @@
#include <QLayout>
#include <QTabBar>
#include <QStackedLayout>
+#include <QPushButton>
#include <kconfig.h>
#include <kconfiggroup.h>
@@ -29,20 +30,25 @@
#include <kglobal.h>
#include <kacceleratormanager.h>
+#include <assert.h>
+
#include "view.h"
#include "document.h"
#include "containerstyle.h"
+#include "urldocument.h"
+#include "navigator.h"
+
namespace Sublime {
// struct ContainerPrivate
struct ContainerPrivate {
QMap<QWidget*, View*> viewForWidget;
+ QMap<View*, QWidget*> widgetForView;//my
};
-
// class Container
Container::Container(QWidget *parent)
@@ -62,6 +68,8 @@
setHoverCloseButton(true);
setCloseButtonEnabled(true);
connect(this, SIGNAL(currentChanged(int)), this, SLOT(widgetActivated(int)));
+
+ connect(this,SIGNAL(closeRequest(QWidget *)),this,SLOT(onCloseRequest(QWidget *) \
)); }
Container::~Container()
@@ -82,12 +90,43 @@
void Container::addWidget(View *view)
{
+ if(d->widgetForView.count(view) != 0)
+ return;
+
QWidget *w = view->widget(this);
+ if (UrlDocument* ud = dynamic_cast<UrlDocument *>(view->document())){
+ //creating a parent for navigator and widget from view
+ QWidget *nw = new QWidget(this);
+ w->setParent(nw);
+ Navigator * navigator = new Navigator;
+ connect(navigator, SIGNAL(newElementOpened(const QString &)),this, \
SLOT(documentOpenRequest(const QString &))); + \
navigator->setPath(ud->url().path()); + QVBoxLayout *layout = new \
QVBoxLayout(nw); + nw->setLayout(layout);
+ layout->addWidget(navigator);
+ layout->addWidget(w);
+ w=nw;//now w points to the outer widget
+ }
+ d->widgetForView[view]=w;
addTab(w, view->document()->title());
d->viewForWidget[w] = view;
connect(view->document(), SIGNAL(titleChanged(Sublime::Document*)), this, \
SLOT(documentTitleChanged(Sublime::Document*))); }
+void Sublime::Container::removeWidget(View *view)
+{
+ assert(view);
+ removeTab(indexOf(d->widgetForView[view]));
+ d->viewForWidget.take(d->widgetForView[view]);
+ disconnect(view->document(), SIGNAL(titleChanged(Sublime::Document*)), this, \
SLOT(documentTitleChanged(Sublime::Document*))); +}
+
+void Container::setCurrentView(View *view){
+ assert(hasWidget(d->widgetForView[view]));
+ setCurrentWidget(d->widgetForView[view]);
+}
+
+
void Container::documentTitleChanged(Sublime::Document* doc)
{
QMapIterator<QWidget*, View*> it = d->viewForWidget;
@@ -101,14 +140,14 @@
}
}
}
+void Container::documentOpenRequest(const QString &str){
+ KUrl url;
+ url.setPath(str);
+ emit openDocumentRequest(url);
+}
-void Sublime::Container::removeWidget(QWidget *w)
-{
- if (w) {
- removeTab(indexOf(w));
- View* view = d->viewForWidget.take(w);
- disconnect(view->document(), SIGNAL(titleChanged(Sublime::Document*)), this, \
SLOT(documentTitleChanged(Sublime::Document*)));
- }
+void Container::onCloseRequest(QWidget *w){
+ emit closeViewRequest(viewForWidget(w));
}
bool Container::hasWidget(QWidget *w)
Index: sublime/filter.cpp
===================================================================
--- sublime/filter.cpp (revision 0)
+++ sublime/filter.cpp (revision 0)
@@ -0,0 +1,26 @@
+#include "filter.h"
+#include "fileview.h"
+
+Filter::Filter(bool inv,const QString &path, QWidget \
*parent):QSortFilterProxyModel(parent), reverse(inv),path(path){ +
+}
+Filter::~Filter(){
+
+}
+
+
+QModelIndex Filter::index(const QString &str) const{
+ return mapFromSource ((dynamic_cast<QDirModel*>(sourceModel()))->index(str));
+}
+
+bool Filter::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const{
+ QDirModel * source = dynamic_cast<QDirModel*>(sourceModel());
+ QModelIndex index = source->index(sourceRow, 0, sourceParent);
+ if (path == source->filePath( index ))//so that root is accepted
+ return true;
+ if (source->isDir( index ))
+ return reverse^false;
+ //dummy version of condition
+ return reverse^(source -> fileName( index ).length()<10);
+ }
+
Property changes on: sublime/filter.cpp
___________________________________________________________________
Name: svn:executable
+ *
Index: sublime/mainwindow_p.cpp
===================================================================
--- sublime/mainwindow_p.cpp (revision 875444)
+++ sublime/mainwindow_p.cpp (working copy)
@@ -157,8 +157,12 @@
//we need to create view container
container = new Container(splitter);
connect(container, SIGNAL(activateView(Sublime::View*)), \
d->m_mainWindow, SLOT(activateView(Sublime::View*)));
- connect(container, SIGNAL(closeRequest(QWidget*)),
- d, SLOT(widgetCloseRequest(QWidget*)));
+
+ connect(container, SIGNAL(closeViewRequest(View *)),d, \
SLOT(viewCloseRequest(View *))); +
+ connect (container,SIGNAL(openDocumentRequest(const KUrl \
&)),d->m_mainWindow, SIGNAL(openDocumentRequest(const KUrl &))); +
+
splitter->addWidget(container);
}
else
@@ -323,8 +327,10 @@
{
bool wasActive = m_mainWindow->activeView() == view;
//container is not empty or this is a root index
- //just remove a widget
- container->removeWidget(view->widget());
+ //just remove a view
+
+ container->removeWidget(view);
+
view->widget()->setParent(0);
//activate what is visible currently in the container if the removed view \
was active if (wasActive)
@@ -338,8 +344,9 @@
// If we have a container, then it should be the only child of
// the splitter.
Q_ASSERT(splitter->count() == 1);
- container->removeWidget(view->widget());
+ container->removeWidget(view);
+
if (view->widget())
view->widget()->setParent(0);
else
@@ -480,7 +487,7 @@
{
area->setThickness(IdealMainLayout::positionForRole(role), thickness);
}
-
+//deprecated
void MainWindowPrivate::widgetCloseRequest(QWidget* widget)
{
if (widgetToView.contains(widget))
@@ -490,7 +497,15 @@
delete view;
}
}
+//new
+void MainWindowPrivate::viewCloseRequest(View* view)
+{
+ area->removeView(view);
+ delete view;
+}
+
+
}
#include "mainwindow_p.moc"
Index: sublime/CMakeLists.txt
===================================================================
--- sublime/CMakeLists.txt (revision 875444)
+++ sublime/CMakeLists.txt (working copy)
@@ -22,6 +22,9 @@
ideal.cpp
ideallayout.cpp
containerstyle.cpp
+ navigator.cpp
+ fileview.cpp
+ filter.cpp
)
kde4_add_library(sublime SHARED ${sublime_LIB_SRCS})
@@ -47,4 +50,7 @@
switcher.h
tooldocument.h
view.h
+ navigator.h
+ fileview.h
+ filter.h
DESTINATION ${INCLUDE_INSTALL_DIR}/kdevplatform/sublime )
Index: sublime/navigator.h
===================================================================
--- sublime/navigator.h (revision 0)
+++ sublime/navigator.h (revision 0)
@@ -0,0 +1,45 @@
+#ifndef NAVIGATOR_H
+#define NAVIGATOR_H
+
+#include <QtGui>
+
+class NavigElem;
+
+class Navigator : public QGroupBox{
+ Q_OBJECT
+ private:
+ QHBoxLayout layout;
+ QString path;
+ QList <NavigElem *> elements;
+ void clearElements();
+ public:
+ Navigator(QWidget *parent=0);
+ ~Navigator();
+ public slots:
+ bool setPath(const QString & );
+ signals:
+ void needOutput(const QString &);
+ void pathChanged(const QString & );
+ void newElementOpened(const QString &);
+};
+
+class NavigElem : public QPushButton{
+ Q_OBJECT
+ QString path;
+ QString elemText;
+ public:
+ NavigElem(QWidget *parent=0, QString filepath="", bool final=false);
+ ~NavigElem();
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+ protected:
+ void enterEvent ( QEvent * event ) ;
+ void leaveEvent ( QEvent * event ) ;
+ void mousePressEvent ( QMouseEvent * event ) ;
+ void resizeEvent ( QResizeEvent * event);
+ signals:
+ void elementSelected(const QString &);
+};
+
+
+#endif
Property changes on: sublime/navigator.h
___________________________________________________________________
Name: svn:executable
+ *
Index: sublime/fileview.cpp
===================================================================
--- sublime/fileview.cpp (revision 0)
+++ sublime/fileview.cpp (revision 0)
@@ -0,0 +1,91 @@
+#include "filter.h"
+#include "fileview.h"
+
+FileView::FileView(QPoint pos, const QString &path):QDialog(0,Qt::ToolTip){
+ layout = new QVBoxLayout;
+ label1 = new QLabel (this);
+ label2 = new QLabel (this);
+ model1=new QDirModel(this);
+ model2=new QDirModel(this);
+ proxy1=new Filter(false,path,this);
+ proxy2=new Filter(true,path,this);
+ view1 = new QTreeView(this);
+ view2 = new QTreeView(this);
+
+ setLayout(layout);
+
+ label1->setText("Opened files");
+ label2->setText("Other files");
+ label1->setAlignment( Qt::AlignCenter );
+ label2->setAlignment( Qt::AlignCenter );
+
+ proxy1->setSourceModel(model1);
+ proxy2->setSourceModel(model2);
+
+ view1 -> setModel(proxy1);
+ view2 -> setModel(proxy2);
+
+ view1->setRootIndex(proxy1->index(path));
+ view2->setRootIndex(proxy2->index(path));
+
+ view1->header()->hide();
+ view2->header()->hide();
+ for (int i=1;i< model1->columnCount();i++){
+ view1->setColumnHidden(i,true);
+ }
+ for (int i=1;i< model2->columnCount();i++){
+ view2->setColumnHidden(i,true);
+ }
+
+ view1->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
+ view2->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
+ view1->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
+ view2->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
+
+ layout -> addWidget(label1);
+ layout -> addWidget(view1);
+ layout -> addWidget(label2);
+ layout -> addWidget(view2);
+
+ layout -> setMargin(0);
+ layout -> setSpacing(0);
+
+ move(pos);
+
+
+ connect(view1,SIGNAL(clicked(QModelIndex)),this, SLOT(itemClicked(QModelIndex)));
+ connect(view2,SIGNAL(clicked(QModelIndex)),this, \
SLOT(itemClickedReverse(QModelIndex))); + show();
+}
+
+FileView::~FileView(){
+
+
+}
+
+void FileView::itemClicked(QModelIndex index){
+ if(!model1->isDir(proxy1->mapToSource(index))){
+ emit(itemSelected(model1->filePath(proxy1->mapToSource(index))));
+ close();
+ }
+ else
+ view1->setExpanded( index,!view1->isExpanded( index ) );
+}
+
+void FileView::itemClickedReverse(QModelIndex index){
+ if(!model2->isDir(proxy2->mapToSource(index))){
+ emit(itemSelected(model2->filePath(proxy2->mapToSource(index))));
+ close();
+ }
+ else
+ view2->setExpanded( index,!view2->isExpanded( index ) );
+}
+
+void FileView::leaveEvent( QEvent *){
+ close();
+}
+
+
+void FileView::enterEvent( QEvent *){
+
+}
Property changes on: sublime/fileview.cpp
___________________________________________________________________
Name: svn:executable
+ *
Index: sublime/mainwindow.cpp
===================================================================
--- sublime/mainwindow.cpp (revision 875444)
+++ sublime/mainwindow.cpp (working copy)
@@ -116,8 +116,7 @@
{
if (!d->viewContainers.contains(view))
return;
- d->viewContainers[view]->setCurrentWidget(view->widget());
-
+ d->viewContainers[view]->setCurrentView(view);
setActiveView(view);
}
Index: sublime/container.h
===================================================================
--- sublime/container.h (revision 875444)
+++ sublime/container.h (working copy)
@@ -20,7 +20,7 @@
#define SUBLIMECONTAINER_H
#include <ktabwidget.h>
-
+#include <kurl.h>
#include "sublimeexport.h"
class QPaintEvent;
@@ -44,8 +44,12 @@
/**Adds the widget for given @p view to the container.*/
void addWidget(View *view);
- /**Removes the widget from the container.*/
- void removeWidget(QWidget *w);
+ /**Removes the widget associated with the view from the container.*/
+ void removeWidget(View *v);
+ /**Activates the widget associated withe the view*/
+ void setCurrentView(View *v);
+
+
/** @return true if widget is placed inside this container.*/
bool hasWidget(QWidget *w);
@@ -64,10 +68,14 @@
Q_SIGNALS:
void activateView(Sublime::View* view);
+ void openDocumentRequest(const KUrl &);
+ void closeViewRequest(View *);
private slots:
void widgetActivated(int idx);
void documentTitleChanged(Sublime::Document* doc);
+ void documentOpenRequest(const QString &);
+ void onCloseRequest(QWidget *);
private:
struct ContainerPrivate * const d;
Index: sublime/filter.h
===================================================================
--- sublime/filter.h (revision 0)
+++ sublime/filter.h (revision 0)
@@ -0,0 +1,20 @@
+#ifndef FILTER_H
+#define FILTER_H
+
+#include <QtGui>
+
+class Filter : public QSortFilterProxyModel {
+Q_OBJECT
+public:
+ Filter(bool,const QString &, QWidget *parent = 0);
+ ~Filter();
+ virtual QModelIndex index(const QString &) const;
+ bool filterAcceptsRow(int sourceRow,const QModelIndex & sourceParent) const;
+
+ using QSortFilterProxyModel::index;
+private:
+ bool reverse;
+ QString path;
+};
+
+#endif
Property changes on: sublime/filter.h
___________________________________________________________________
Name: svn:executable
+ *
Index: sublime/navigator.cpp
===================================================================
--- sublime/navigator.cpp (revision 0)
+++ sublime/navigator.cpp (revision 0)
@@ -0,0 +1,134 @@
+#include "filter.h"
+#include "fileview.h"
+#include "navigator.h"
+
+
+Navigator :: Navigator(QWidget *parent): QGroupBox(parent){
+ path = "";
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed));
+ setLayout( &layout );
+ layout.setMargin( 0 );
+ layout.setSpacing( 0 );
+}
+
+Navigator :: ~Navigator(){
+ clearElements();
+}
+
+bool Navigator :: setPath(const QString & str){
+ if (str.isEmpty())
+ return false;
+
+ setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed));
+ NavigElem *p;
+ QString elemName,elemDir;
+ int i=0;
+ path = str;
+ QStringList lst=str.split('/');
+ clearElements();
+ while(!lst.empty()){
+ elemName = lst.takeFirst();
+ elemDir = path.section('/',0,i++);
+ if (elemDir!="/"){
+ if(elemDir.isEmpty())
+ elemDir="/";
+ if (!lst.empty())
+ p=new NavigElem(this,elemDir);
+ else
+ p=new NavigElem(this,elemDir,true);
+
+ //FIXME not needed when class exported
+ //connect(p,SIGNAL(elementSelected(const QString & )),this,SLOT(setPath(const \
QString &))); +
+ connect(p,SIGNAL(elementSelected(const QString & \
)),this,SIGNAL(newElementOpened(const QString &))); + elements.push_back(p);
+ layout.addWidget(p);
+ }
+ }
+ layout.addStretch( 10 );
+ emit(pathChanged(str));
+ return true;
+}
+
+
+void Navigator::clearElements(){
+ while (!elements.isEmpty()){
+ delete elements.takeFirst();
+ }
+
+ while(layout.itemAt(0)){
+ QLayoutItem *temp =layout.itemAt(0);
+ layout.removeItem (temp);
+ delete temp;
+ }
+}
+
+NavigElem :: NavigElem(QWidget *parent, QString filepath, bool final): \
QPushButton(parent){ + path=filepath;
+ setFocusPolicy( Qt::NoFocus );
+ setFlat( true );
+ setAutoFillBackground(true);
+ setMouseTracking( true );
+ setSizePolicy(QSizePolicy(QSizePolicy::Preferred,QSizePolicy::Expanding));
+
+ elemText = path.section('/',-1);
+ if(!final)
+ if(!elemText.isEmpty())
+ elemText += " >";
+ else
+ elemText = "/ >";
+ else {
+ QFont fnt=font();
+ fnt.setBold( true );
+ setFont(fnt);
+ }
+ setText(elemText);
+}
+
+NavigElem :: ~NavigElem(){
+
+}
+
+QSize NavigElem ::sizeHint() const{
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ int w = fontMetrics().size(Qt::TextShowMnemonic,text()).width(),
+ h = fontMetrics().size(Qt::TextShowMnemonic,text()).height();
+ return (style()->sizeFromContents(QStyle::CT_CheckBox, &opt, QSize(w, h), \
this).expandedTo(QApplication::globalStrut())); +}
+
+
+QSize NavigElem ::minimumSizeHint() const{
+ return QSize(20,20);
+}
+
+
+
+void NavigElem::enterEvent ( QEvent * ) {
+ QPalette p=palette();
+ p.setColor( QPalette::ButtonText, QColor(Qt::white) );
+ p.setColor( QPalette::Button, QColor(Qt::darkGray) );
+ setPalette( p );
+}
+
+void NavigElem::leaveEvent ( QEvent *) {
+ setPalette( QPalette() );//set default palette
+}
+
+void NavigElem::mousePressEvent ( QMouseEvent *event) {
+
+ QFileInfo file(path);
+ FileView *dlg;
+ if(file.isDir())//for the last one in list - file not a dir
+ dlg = new FileView(event->globalPos(),path);
+ else
+ dlg = new FileView(event->globalPos(),file.absoluteDir().absolutePath());
+
+ connect(dlg,SIGNAL(itemSelected(const QString &)),this,SIGNAL(elementSelected(const \
QString &))); +
+
+}
+
+void NavigElem::resizeEvent ( QResizeEvent * ){
+ setText(fontMetrics().elidedText(elemText, Qt::ElideLeft,size().width()-1));
+}
Property changes on: sublime/navigator.cpp
___________________________________________________________________
Name: svn:executable
+ *
_______________________________________________
KDevelop-devel mailing list
KDevelop-devel@kdevelop.org
https://barney.cs.uni-potsdam.de/mailman/listinfo/kdevelop-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic