1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-19 23:39:42 +01:00

A breadcrumb widget, tomahawk style.

This commit is contained in:
Casey Link 2011-08-31 18:49:37 +00:00
parent 0c3a9c61b5
commit c2fe912277
12 changed files with 1364 additions and 0 deletions

View File

@ -193,6 +193,11 @@ set( libSources
widgets/infowidgets/sourceinfowidget.cpp
widgets/infowidgets/ArtistInfoWidget.cpp
widgets/infowidgets/AlbumInfoWidget.cpp
widgets/kbreadcrumbselectionmodel.cpp
widgets/breadcrumbbar.cpp
widgets/breadcrumbbuttonbase.cpp
widgets/headerbreadcrumb.cpp
widgets/siblingcrumbbutton.cpp
kdsingleapplicationguard/kdsingleapplicationguard.cpp
kdsingleapplicationguard/kdsharedmemorylocker.cpp
@ -379,6 +384,12 @@ set( libHeaders
widgets/infowidgets/sourceinfowidget.h
widgets/infowidgets/ArtistInfoWidget.h
widgets/infowidgets/AlbumInfoWidget.h
widgets/kbreadcrumbselectionmodel.h
widgets/kbreadcrumbselectionmodel_p.h
widgets/breadcrumbbar.h
widgets/breadcrumbbuttonbase.h
widgets/headerbreadcrumb.h
widgets/siblingcrumbbutton.h
kdsingleapplicationguard/kdsingleapplicationguard.h
)

View File

@ -0,0 +1,282 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Casey Link <unnamedrambler@gmail.com>
* Copyright (C) 2004-2011 Glenn Van Loon, glenn@startupmanager.org
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "breadcrumbbar.h"
#include "breadcrumbbuttonbase.h"
#include <QAbstractItemModel>
#include <QAbstractProxyModel>
#include <QHBoxLayout>
#include <QItemSelectionModel>
#include <QLabel>
#include <QPropertyAnimation>
#include <QDebug>
BreadcrumbBar::BreadcrumbBar(BreadcrumbButtonFactory *buttonFactory, QWidget *parent)
: QWidget(parent)
, m_model(0)
, m_selectionModel(0)
, m_layout(new QHBoxLayout(this))
, m_buttonFactory(buttonFactory)
, m_useAnimation(false)
{
m_layout->setSpacing(0);
m_layout->setMargin(0);
m_layout->setAlignment(Qt::AlignLeft);
setAutoFillBackground(false);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setLayoutDirection(Qt::LeftToRight);
setLayout(m_layout);
setMinimumWidth(100);
show();
}
BreadcrumbBar::BreadcrumbBar(QWidget *parent)
: QWidget(parent)
, m_model(0)
, m_selectionModel(0)
, m_layout(new QHBoxLayout(this))
, m_buttonFactory(0)
, m_useAnimation(false)
{
m_layout->setSpacing(0);
m_layout->setMargin(0);
m_layout->setAlignment(Qt::AlignLeft);
setAutoFillBackground(false);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setLayoutDirection(Qt::LeftToRight);
setLayout(m_layout);
setMinimumWidth(100);
show();
}
BreadcrumbBar::~BreadcrumbBar()
{
}
void BreadcrumbBar::setButtonFactory(BreadcrumbButtonFactory *buttonFactory)
{
m_buttonFactory = buttonFactory;
}
BreadcrumbButtonFactory* BreadcrumbBar::buttonFactory() const
{
return m_buttonFactory;
}
void BreadcrumbBar::appendButton(BreadcrumbButtonBase *widget, int stretch)
{
m_layout->insertWidget(m_layout->count(), widget, stretch);
if( !m_useAnimation )
return; //we're done here.
// A nifty trick to force the widget to calculate its position and geometry
//widget->setAttribute(Qt::WA_DontShowOnScreen);
widget->show();
//widget->setAttribute(Qt::WA_DontShowOnScreen, false);
if( m_navButtons.size() > 0 ) {
QWidget* neighbor = m_layout->itemAt(m_layout->count()-2)->widget();
QPropertyAnimation *animation = new QPropertyAnimation(widget,"pos");
animation->setDuration(300);
animation->setStartValue(neighbor->pos());
animation->setEndValue(widget->pos());
animation->start(QAbstractAnimation::DeleteWhenStopped);
}
}
void BreadcrumbBar::deleteAnimationFinished()
{
QPropertyAnimation *anim = qobject_cast<QPropertyAnimation*>(sender());
if( !anim )
return;
QObject *obj = anim->targetObject();
obj->deleteLater();
anim->deleteLater();
}
void BreadcrumbBar::deleteButton(BreadcrumbButtonBase *widget)
{
if( !m_useAnimation ) {
widget->hide();
widget->deleteLater();
return; // all done here
}
int index = m_layout->indexOf(widget);
if( index != 0 && m_navButtons.size() > 0 ) {
QWidget* neighbor = m_layout->itemAt(index-1)->widget();
QPropertyAnimation *animation = new QPropertyAnimation(widget,"pos");
m_layout->removeWidget(widget);
connect(animation, SIGNAL(finished()), SLOT(deleteAnimationFinished()));
animation->setDuration(300);
animation->setStartValue(widget->pos());
animation->setEndValue(neighbor->pos());
animation->start();
} else {
widget->hide();
widget->deleteLater();
}
}
void BreadcrumbBar::updateButtons()
{
if (!m_buttonFactory || !m_selectionModel || !m_selectionModel->currentIndex().isValid())
return;
QLinkedList<BreadcrumbButtonBase*>::iterator it = m_navButtons.begin();
QLinkedList<BreadcrumbButtonBase*>::const_iterator const itEnd = m_navButtons.end();
bool createButton = false;
QModelIndex index = m_selectionModel->currentIndex();
QList<QModelIndex> indexes;
while (index.parent().isValid())
{
indexes.prepend(index);
index = index.parent();
}
qDebug() << index.data().toString();
indexes.prepend(index);
int count = indexes.size(), i = 0;
foreach (index, indexes)
{
createButton = (it == itEnd);
bool isLastButton = (++i == count);
QString const dirName = index.data().toString();
BreadcrumbButtonBase *button = 0;
if (createButton)
{
button = m_buttonFactory->newButton(index, this);
appendButton(button);
button->setActive(isLastButton);
m_navButtons.append(button);
}
else
{
button = *it;
button->setIndex(index);
button->setActive(isLastButton);
++it;
}
}
QLinkedList<BreadcrumbButtonBase*>::Iterator itBegin = it;
while (it != itEnd)
{
deleteButton(*it);
++it;
}
m_navButtons.erase(itBegin, m_navButtons.end());
foreach (BreadcrumbButtonBase *button, m_navButtons)
button->show();
adjustSize();
}
void BreadcrumbBar::clearButtons()
{
foreach (BreadcrumbButtonBase *button, m_navButtons)
{
button->hide();
button->deleteLater();
}
m_navButtons.clear();
}
void BreadcrumbBar::currentIndexChanged()
{
updateButtons();
}
void BreadcrumbBar::setRootIcon(const QIcon &icon)
{
m_rootIcon = icon;
QLabel *label= new QLabel(this);
label->setPixmap(icon.pixmap(16,16));
m_layout->insertWidget(0, label);
m_layout->insertSpacing(0,5);
m_layout->insertSpacing(2,5);
}
void BreadcrumbBar::setRootText(const QString &text)
{
//TODO: implement this
m_rootText = text;
/*QLabel *label= new QLabel(this);
label->setPixmap(icon.pixmap(16,16));
m_layout->insertWidget(0, label);
m_layout->insertSpacing(0,5);
m_layout->insertSpacing(2,5);*/
}
void BreadcrumbBar::setUseAnimation(bool use)
{
m_useAnimation = use;
}
bool BreadcrumbBar::useAnimation() const
{
return m_useAnimation;
}
void BreadcrumbBar::setModel(QAbstractItemModel *model)
{
m_model = model;
updateButtons();
}
QAbstractItemModel* BreadcrumbBar::model()
{
return m_model;
}
void BreadcrumbBar::setSelectionModel(QItemSelectionModel *selectionModel)
{
m_selectionModel = selectionModel;
connect(m_selectionModel,
SIGNAL(currentChanged(QModelIndex const&, QModelIndex const&)),
this, SLOT(currentIndexChanged()));
updateButtons();
}
QItemSelectionModel* BreadcrumbBar::selectionModel()
{
return m_selectionModel;
}
QModelIndex BreadcrumbBar::currentIndex()
{
return m_selectionModel->currentIndex();
}
void BreadcrumbBar::currentChangedTriggered(QModelIndex const& index)
{
Q_ASSERT(m_selectionModel);
m_selectionModel->setCurrentIndex( index, QItemSelectionModel::SelectCurrent);
}

View File

@ -0,0 +1,183 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Casey Link <unnamedrambler@gmail.com>
* Copyright (C) 2004-2011 Glenn Van Loon, glenn@startupmanager.org
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BREADCRUMBBAR_H
#define BREADCRUMBBAR_H
#include "breadcrumbbuttonbase.h"
#include <QModelIndex>
#include <QWidget>
#include <QLinkedList>
#include <QIcon>
class QAbstractItemModel;
class QItemSelectionModel;
class QAbstractItemModel;
class QAbstractProxyModel;
class QHBoxLayout;
class QItemSelectionModel;
/**
* \brief A breadcrumb view for a QAbstractItemModel
*
* This a lean Breadcrumb navigation bar that supports the following features:
* - a QAbstractItemModel data source for MV goodness
* - client provided crumb button widgets (to use your own style and behavior)
* - client provided crumb animation [optional]
* - client provided root item (icon or text) [optional]
*
*/
class BreadcrumbBar : public QWidget
{
Q_OBJECT
public:
/**
* \brief breadcrumb bar constructor
* \param buttonFactory the button factory to instantiate bread crumbs from
*/
BreadcrumbBar(BreadcrumbButtonFactory *buttonFactory, QWidget *parent = 0);
/**
* \brief breadcrumb bar constructor
* You must set the button factory using BreadcrumbBar::setButtonFactory
*/
BreadcrumbBar(QWidget *parent = 0);
virtual ~BreadcrumbBar();
/**
* \brief sets the button factory to use to create buttons
* \param buttonFactory the button factory
*/
void setButtonFactory(BreadcrumbButtonFactory *buttonFactory);
BreadcrumbButtonFactory* buttonFactory() const;
/**
* \brief Set the icon that should be displayed at the root
* \param icon the icon
*/
void setRootIcon(const QIcon &icon);
/**
* \brief Set the text that should be displayed at the root
* \param test the text
*/
void setRootText(const QString &text);
/**
* \brief Set whether the crumb animation should be used (default: false)
*/
void setUseAnimation(bool use);
bool useAnimation() const;
/**
* \brief set the item model to use as a data source
* \param model the item model
*
* Although the item model can be of any structure, the breadcrumb bar
* works best when the model's structure is a tree.
*/
void setModel(QAbstractItemModel *model);
QAbstractItemModel *model();
/**
* \brief set the selection model used to determine the crumb items
* \param selectionModel the selection model
*
* The selection model is just as important as your model. In fact your
* model can be of any structure (even not-tree-like) as long as your
* selection model understands what it means for an item to be a crumb,
* and knows how to select it.
*
* If you have a standard tree model, you probably should use
* KBreadCrumbSelectionModel which encapsulates the concept of "When an
* item is selected, make a selection which includes its parent and
* ancestor items until the top is reached".
*
* \sa See Stephen Kelley's blog post here http://steveire.wordpress.com/2010/04/21/breadcrumbs-for-your-view
*/
void setSelectionModel(QItemSelectionModel *selectionModel);
QItemSelectionModel *selectionModel();
/**
* \brief get the index of the currently active item
* \return the active index
*/
QModelIndex currentIndex();
/**
* \brief used by crumbs to notify that the current index has changed
* \param index the new current index
*/
void currentChangedTriggered(QModelIndex const& index);
protected:
/**
* \brief append a crumb widget
* \param button the crumb button to add
* \param stretch widget stretch factor
* Respects the useAnimation() setting.
*/
void appendButton(BreadcrumbButtonBase *button, int stretch = 0);
/**
* \brief deletes a crumb from the bar
* \param button the crumb button to delete
* Respects the useAnimation() setting.
*/
void deleteButton(BreadcrumbButtonBase *button);
protected slots:
/**
* \brief The current index has changed in the selection model
* When the selection model changes, we get notified here
*/
void currentIndexChanged();
/**
* \brief Recreate the button bar from the selection model
*/
void updateButtons();
/**
* \brief clear breadcrumb buttons
*/
void clearButtons();
/**
* Called when the delete animation finishes so we can delete the button
* object.
*/
void deleteAnimationFinished();
private:
BreadcrumbButtonFactory *m_buttonFactory; /*!< Factory used to create new crumbs */
QAbstractItemModel *m_model; /*!< The source model */
QItemSelectionModel *m_selectionModel; /*!< The selection model */
QHBoxLayout *m_layout; /*!< The layout holding out crumb buttons */
QLinkedList<BreadcrumbButtonBase*> m_navButtons; /*< Our list of crumbs! */
QIcon m_rootIcon; /*!< The root icon */
QString m_rootText; /*!< The root text */
bool m_useAnimation; /*<!< Whether we should animate the transition or not */
};
#endif // BREADCRUMBBAR_H

View File

@ -0,0 +1,39 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Casey Link <unnamedrambler@gmail.com>
* Copyright (C) 2004-2011 Glenn Van Loon, glenn@startupmanager.org
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "breadcrumbbuttonbase.h"
#include "breadcrumbbar.h"
BreadcrumbButtonBase::BreadcrumbButtonBase(BreadcrumbBar *parent)
: QPushButton(parent), m_breadcrumbBar(parent)
{
setFocusPolicy(Qt::NoFocus);
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
setMinimumHeight(parent->minimumHeight());
}
BreadcrumbButtonBase::~BreadcrumbButtonBase()
{
}
BreadcrumbBar* BreadcrumbButtonBase::breadcrumbBar() const
{
return m_breadcrumbBar;
}

View File

@ -0,0 +1,94 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Casey Link <unnamedrambler@gmail.com>
* Copyright (C) 2004-2011 Glenn Van Loon, glenn@startupmanager.org
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BREADCRUMBBUTTONBASE_P_H
#define BREADCRUMBBUTTONBASE_P_H
#include <QPushButton>
#include <QModelIndex>
class BreadcrumbBar;
class BreadcrumbButtonBase;
/**
* \brief an abstract factory class to create crumb buttons
* Subclass this class and make it return bread crumb buttons of your type.
*/
class BreadcrumbButtonFactory {
public:
BreadcrumbButtonFactory(){}
virtual ~BreadcrumbButtonFactory(){}
/**
* \brief instantiates a new bread crumb button
* \param index the initial index this crumb should hold
* \param parent the breadcrumb bar this button will belong to
* \returns a new bread crumb button allocated on the heap.
*
* This method can be as simple as:
* \code
* return new MyBreadCrumbButton(index, parent);
* \endcode
*
*/
virtual BreadcrumbButtonBase* newButton(QModelIndex index, BreadcrumbBar *parent) = 0;
};
/**
* \brief The button base class for the BreadcrumbBar
* Re-implement this to provide your own crumb buttons. Don't forget to supply
* a BreadcrumbButtonFactory as well.
*/
class BreadcrumbButtonBase : public QPushButton
{
Q_OBJECT
public:
explicit BreadcrumbButtonBase(BreadcrumbBar *parent);
virtual ~BreadcrumbButtonBase();
/**
* \brief retrieve the breadcrumb bar that this button belongs to
* \return the parent breadcrumb bar
*/
BreadcrumbBar* breadcrumbBar() const;
/**
* \brief set the model item that this button represents
* \param index the index of the model items to display
*/
virtual void setIndex(QModelIndex index) = 0;
virtual QModelIndex index() const = 0;
/**
* \brief sets whether this button is active or not
* \param active true for active, false for inactive
* You could, for example, make the active button bold.
*/
virtual void setActive(bool active) = 0;
virtual bool isActive() const = 0;
private:
BreadcrumbBar *m_breadcrumbBar;
};
#endif // BREADCRUMBBUTTONBASE_P_H

View File

@ -0,0 +1,46 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Casey Link <unnamedrambler@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "headerbreadcrumb.h"
#include "utils/stylehelper.h"
#include <QStyle>
#include <QStylePainter>
#include <QPaintEvent>
HeaderBreadCrumb::HeaderBreadCrumb(BreadcrumbButtonFactory *buttonFactory, QWidget *parent) :
BreadcrumbBar(buttonFactory, parent)
{
}
HeaderBreadCrumb::HeaderBreadCrumb(QWidget *parent) :
BreadcrumbBar(parent)
{
}
HeaderBreadCrumb::~HeaderBreadCrumb()
{
}
void HeaderBreadCrumb::paintEvent(QPaintEvent *event)
{
QStylePainter p(this);
StyleHelper::horizontalHeader(&p, event->rect());
}

View File

@ -0,0 +1,44 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Casey Link <unnamedrambler@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADERBREADCRUMB_H
#define HEADERBREADCRUMB_H
#include "breadcrumbbar.h"
class QPaintEvent;
/**
* \brief a bread crumb widget with Tomahawk's distinctive header style
*/
class HeaderBreadCrumb : public BreadcrumbBar
{
Q_OBJECT
public:
HeaderBreadCrumb(BreadcrumbButtonFactory *buttonFactory, QWidget *parent = 0);
HeaderBreadCrumb(QWidget *parent = 0);
~HeaderBreadCrumb();
protected:
virtual void paintEvent(QPaintEvent *event);
};
#endif

View File

@ -0,0 +1,202 @@
/*
Copyright (C) 2010 Klarälvdalens Datakonsult AB,
a KDAB Group company, info@kdab.net,
author Stephen Kelly <stephen@kdab.com>
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include "kbreadcrumbselectionmodel.h"
#include "kbreadcrumbselectionmodel_p.h"
#include <QDebug>
KBreadcrumbSelectionModel::KBreadcrumbSelectionModel(QItemSelectionModel *selectionModel, QObject* parent)
: QItemSelectionModel(const_cast<QAbstractItemModel *>(selectionModel->model()), parent),
d_ptr(new KBreadcrumbSelectionModelPrivate(this, selectionModel, MakeBreadcrumbSelectionInSelf))
{
d_ptr->init();
}
KBreadcrumbSelectionModel::KBreadcrumbSelectionModel(QItemSelectionModel *selectionModel, BreadcrumbTarget direction, QObject* parent)
: QItemSelectionModel(const_cast<QAbstractItemModel *>(selectionModel->model()), parent),
d_ptr(new KBreadcrumbSelectionModelPrivate(this, selectionModel, direction))
{
if ( direction != MakeBreadcrumbSelectionInSelf)
connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),
this, SLOT(sourceSelectionChanged(const QItemSelection&,const QItemSelection&)));
d_ptr->init();
}
KBreadcrumbSelectionModel::~KBreadcrumbSelectionModel()
{
delete d_ptr;
}
bool KBreadcrumbSelectionModel::isActualSelectionIncluded() const
{
Q_D(const KBreadcrumbSelectionModel);
return d->m_includeActualSelection;
}
void KBreadcrumbSelectionModel::setActualSelectionIncluded(bool includeActualSelection)
{
Q_D(KBreadcrumbSelectionModel);
d->m_includeActualSelection = includeActualSelection;
}
int KBreadcrumbSelectionModel::breadcrumbLength() const
{
Q_D(const KBreadcrumbSelectionModel);
return d->m_selectionDepth;
}
void KBreadcrumbSelectionModel::setBreadcrumbLength(int breadcrumbLength)
{
Q_D(KBreadcrumbSelectionModel);
d->m_selectionDepth = breadcrumbLength;
}
QItemSelection KBreadcrumbSelectionModelPrivate::getBreadcrumbSelection(const QModelIndex& index)
{
QItemSelection breadcrumbSelection;
if (m_includeActualSelection)
breadcrumbSelection.append(QItemSelectionRange(index));
QModelIndex parent = index.parent();
int sumBreadcrumbs = 0;
bool includeAll = m_selectionDepth < 0;
while (parent.isValid() && (includeAll || sumBreadcrumbs < m_selectionDepth)) {
breadcrumbSelection.append(QItemSelectionRange(parent));
parent = parent.parent();
}
return breadcrumbSelection;
}
QItemSelection KBreadcrumbSelectionModelPrivate::getBreadcrumbSelection(const QItemSelection& selection)
{
QItemSelection breadcrumbSelection;
if (m_includeActualSelection)
breadcrumbSelection = selection;
QItemSelection::const_iterator it = selection.constBegin();
const QItemSelection::const_iterator end = selection.constEnd();
for ( ; it != end; ++it)
{
QModelIndex parent = it->parent();
if (breadcrumbSelection.contains(parent))
continue;
int sumBreadcrumbs = 0;
bool includeAll = m_selectionDepth < 0;
while (parent.isValid() && (includeAll || sumBreadcrumbs < m_selectionDepth))
{
breadcrumbSelection.append(QItemSelectionRange(parent));
parent = parent.parent();
if (breadcrumbSelection.contains(parent))
break;
++sumBreadcrumbs;
}
}
return breadcrumbSelection;
}
void KBreadcrumbSelectionModelPrivate::sourceSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
{
Q_Q(KBreadcrumbSelectionModel);
QItemSelection deselectedCrumbs = getBreadcrumbSelection(deselected);
QItemSelection selectedCrumbs = getBreadcrumbSelection(selected);
QItemSelection removed = deselectedCrumbs;
foreach(const QItemSelectionRange &range, selectedCrumbs)
{
removed.removeAll(range);
}
QItemSelection added = selectedCrumbs;
foreach(const QItemSelectionRange &range, deselectedCrumbs)
{
added.removeAll(range);
}
if (!removed.isEmpty())
{
q->QItemSelectionModel::select(removed, QItemSelectionModel::Deselect);
}
if (!added.isEmpty())
{
q->QItemSelectionModel::select(added, QItemSelectionModel::Select);
}
}
void KBreadcrumbSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
{
Q_D(KBreadcrumbSelectionModel);
// When an item is removed, the current index is set to the top index in the model.
// That causes a selectionChanged signal with a selection which we do not want.
if ( d->m_ignoreCurrentChanged )
{
d->m_ignoreCurrentChanged = false;
return;
}
if ( d->m_direction == MakeBreadcrumbSelectionInOther )
{
d->m_selectionModel->select(d->getBreadcrumbSelection(index), command);
QItemSelectionModel::select(index, command);
} else {
d->m_selectionModel->select(index, command);
QItemSelectionModel::select(d->getBreadcrumbSelection(index), command);
}
}
void KBreadcrumbSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
{
Q_D(KBreadcrumbSelectionModel);
QItemSelection bcc = d->getBreadcrumbSelection(selection);
if ( d->m_direction == MakeBreadcrumbSelectionInOther )
{
d->m_selectionModel->select(selection, command);
QItemSelectionModel::select(bcc, command);
} else {
d->m_selectionModel->select(bcc, command);
QItemSelectionModel::select(selection, command);
}
}
void KBreadcrumbSelectionModelPrivate::init()
{
Q_Q(KBreadcrumbSelectionModel);
q->connect(m_selectionModel->model(), SIGNAL(layoutChanged()), SLOT(syncBreadcrumbs()));
q->connect(m_selectionModel->model(), SIGNAL(modelReset()), SLOT(syncBreadcrumbs()));
q->connect(m_selectionModel->model(), SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), SLOT(syncBreadcrumbs()));
// Don't need to handle insert & remove because they can't change the breadcrumbs on their own.
}
void KBreadcrumbSelectionModelPrivate::syncBreadcrumbs()
{
Q_Q(KBreadcrumbSelectionModel);
q->select(m_selectionModel->selection(), QItemSelectionModel::ClearAndSelect);
}

View File

@ -0,0 +1,164 @@
/*
Copyright (C) 2010 Klarälvdalens Datakonsult AB,
a KDAB Group company, info@kdab.net,
author Stephen Kelly <stephen@kdab.com>
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#ifndef KBREADCRUMBSPROXYMODEL_H
#define KBREADCRUMBSPROXYMODEL_H
#include <QtGui/QItemSelectionModel>
#include <QtCore/QAbstractItemModel>
#include <QObject>
class KBreadcrumbSelectionModelPrivate;
/**
@class KBreadcrumbSelectionModel kbreadcrumbselectionmodel.h
@brief Selects the parents of selected items to create breadcrumbs
For example, if the tree is
@verbatim
- A
- B
- - C
- - D
- - - E
- - - - F
@endverbatim
and E is selected, the selection can contain
@verbatim
- B
- D
@endverbatim
or
@verbatim
- B
- D
- E
@endverbatim
if isActualSelectionIncluded is true.
The depth of the selection may also be set. For example if the breadcrumbLength is 1:
@verbatim
- D
- E
@endverbatim
And if breadcrumbLength is 2:
@verbatim
- B
- D
- E
@endverbatim
A KBreadcrumbsProxyModel with a breadcrumbLength of 0 and including the actual selection is
the same as a KSelectionProxyModel in the KSelectionProxyModel::ExactSelection configuration.
@code
view1->setModel(rootModel);
QItemSelectionModel *breadcrumbSelectionModel = new QItemSelectionModel(rootModel, this);
KBreadcrumbSelectionModel *breadcrumbProxySelector = new KBreadcrumbSelectionModel(breadcrumbSelectionModel, rootModel, this);
view1->setSelectionModel(breadcrumbProxySelector);
KSelectionProxyModel *breadcrumbSelectionProxyModel = new KSelectionProxyModel( breadcrumbSelectionModel, this);
breadcrumbSelectionProxyModel->setSourceModel( rootModel );
breadcrumbSelectionProxyModel->setFilterBehavior( KSelectionProxyModel::ExactSelection );
view2->setModel(breadcrumbSelectionProxyModel);
@endcode
@image html kbreadcrumbselectionmodel.png "KBreadcrumbSelectionModel in several configurations"
This can work in two directions. One option is for a single selection in the KBreadcrumbSelectionModel to invoke
the breadcrumb selection in its constructor argument.
The other is for a selection in the itemselectionmodel in the constructor argument to cause a breadcrumb selection
in @p this.
@since 4.5
*/
class KBreadcrumbSelectionModel : public QItemSelectionModel
{
Q_OBJECT
public:
enum BreadcrumbTarget
{
MakeBreadcrumbSelectionInOther,
MakeBreadcrumbSelectionInSelf
};
explicit KBreadcrumbSelectionModel(QItemSelectionModel *selectionModel, QObject* parent = 0);
KBreadcrumbSelectionModel(QItemSelectionModel *selectionModel, BreadcrumbTarget target, QObject* parent = 0);
virtual ~KBreadcrumbSelectionModel();
/**
Returns whether the actual selection in included in the proxy.
The default is true.
*/
bool isActualSelectionIncluded() const;
/**
Set whether the actual selection in included in the proxy to @p isActualSelectionIncluded.
*/
void setActualSelectionIncluded(bool isActualSelectionIncluded);
/**
Returns the depth that the breadcrumb selection should go to.
*/
int breadcrumbLength() const;
/**
Sets the depth that the breadcrumb selection should go to.
If the @p breadcrumbLength is -1, all breadcrumbs are selected.
The default is -1
*/
void setBreadcrumbLength(int breadcrumbLength);
/* reimp */ void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command);
/* reimp */ void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command);
protected:
KBreadcrumbSelectionModelPrivate * const d_ptr;
private:
//@cond PRIVATE
Q_DECLARE_PRIVATE(KBreadcrumbSelectionModel)
Q_PRIVATE_SLOT( d_func(),void sourceSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected))
Q_PRIVATE_SLOT( d_func(),void syncBreadcrumbs())
//@cond PRIVATE
};
#include "kbreadcrumbselectionmodel_p.h" //HACK ALERT - Why doesn't it compile without this?!
#endif

View File

@ -0,0 +1,71 @@
/*
Copyright (C) 2010 Klarälvdalens Datakonsult AB,
a KDAB Group company, info@kdab.net,
author Stephen Kelly <stephen@kdab.com>
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#ifndef KBREADCRUMBSPROXYMODEL_P_H
#define KBREADCRUMBSPROXYMODEL_P_H
#include "kbreadcrumbselectionmodel.h"
#include <QtGui/QItemSelectionModel>
#include <QtCore/QAbstractItemModel>
#include <QObject>
class KBreadcrumbSelectionModelPrivate
{
Q_DECLARE_PUBLIC(KBreadcrumbSelectionModel)
KBreadcrumbSelectionModel * const q_ptr;
public:
KBreadcrumbSelectionModelPrivate(KBreadcrumbSelectionModel *breadcrumbSelector, QItemSelectionModel *selectionModel, KBreadcrumbSelectionModel::BreadcrumbTarget direction)
: q_ptr(breadcrumbSelector),
m_includeActualSelection(true),
m_selectionDepth(-1),
m_showHiddenAscendantData(false),
m_selectionModel(selectionModel),
m_direction(direction),
m_ignoreCurrentChanged(false)
{
}
/**
Returns a selection containing the breadcrumbs for @p index
*/
QItemSelection getBreadcrumbSelection(const QModelIndex &index);
/**
Returns a selection containing the breadcrumbs for @p selection
*/
QItemSelection getBreadcrumbSelection(const QItemSelection &selection);
void sourceSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void init();
void syncBreadcrumbs();
bool m_includeActualSelection;
int m_selectionDepth;
bool m_showHiddenAscendantData;
QItemSelectionModel *m_selectionModel;
KBreadcrumbSelectionModel::BreadcrumbTarget m_direction;
bool m_ignoreCurrentChanged;
};
#endif

View File

@ -0,0 +1,149 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Casey Link <unnamedrambler@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "siblingcrumbbutton.h"
#include "combobox.h"
#include "utils/stylehelper.h"
#include <QTimer>
#include <QDebug>
#include <QPainter>
#include <QStyle>
#include <QStyleOption>
BreadcrumbButtonBase* SiblingCrumbButtonFactory::newButton(QModelIndex index, BreadcrumbBar *parent)
{
return new SiblingCrumbButton(index, parent);
}
SiblingCrumbButton::SiblingCrumbButton(
QModelIndex index, BreadcrumbBar *parent)
: BreadcrumbButtonBase(parent),
m_index(index), m_combo( new ComboBox(this) )
{
setIndex(index);
connect(this, SIGNAL(clicked()),
this, SLOT(updateNavigatorCurrentIndex()));
connect(m_combo, SIGNAL(activated(int)), SLOT(comboboxActivated(int)));
// QTimer::singleShot(0, this, SLOT(activateSelf()));
}
void SiblingCrumbButton::setIndex(QModelIndex index)
{
m_index = index;
setText(index.data().toString());
qDebug() << "i am " << text();
fillCombo();
}
QModelIndex SiblingCrumbButton::index() const
{
return m_index;
}
void SiblingCrumbButton::setActive(bool active)
{
}
bool SiblingCrumbButton::isActive() const
{
return false;
}
QSize SiblingCrumbButton::sizeHint() const
{
// our width = width of combo + 20px for right-arrow and spacing
return m_combo->sizeHint() + QSize(20,0);
}
void SiblingCrumbButton::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter p(this);
QStyleOption opt;
opt.initFrom(this);
QRect r = opt.rect;
StyleHelper::horizontalHeader(&p, r); // draw the background
bool reverse = opt.direction == Qt::RightToLeft;
int menuButtonWidth = 12;
int rightSpacing = 10;
int left = !reverse ? r.right()-rightSpacing - menuButtonWidth : r.left();
int right = !reverse ? r.right()-rightSpacing : r.left() + menuButtonWidth;
int height = sizeHint().height();
QRect arrowRect((left + right) / 2 + (reverse ? 6 : -6), 0, height, height);
QStyleOption arrowOpt = opt;
arrowOpt.rect = arrowRect;
QLine l1(left, 0, right, height/2);
QLine l2(left, height, right, height/2);
p.setRenderHint(QPainter::Antialiasing, true);
// Draw the shadow
QColor shadow(0, 0, 0, 100);
p.translate(0, -1);
p.setPen(shadow);
p.drawLine(l1);
p.drawLine(l2);
// Draw the main arrow
QColor foreGround("#747474");
p.translate(0, 1);
p.setPen(foreGround);
p.drawLine(l1);
p.drawLine(l2);
}
void SiblingCrumbButton::fillCombo()
{
QStringList list;
int count = breadcrumbBar()->model()->rowCount(m_index.parent());
for(int i = 0; i < count; ++i) {
QModelIndex sibling = m_index.sibling(i,0);
if( sibling.isValid() )
list << sibling.data().toString();
}
m_combo->clear();
m_combo->addItems(list);
m_combo->setCurrentIndex( m_combo->findText(text()));
}
void SiblingCrumbButton::comboboxActivated(int i)
{
QModelIndex activated = m_index.sibling(i,0);
int count = breadcrumbBar()->model()->rowCount(activated);
if( count > 0 ) {
qDebug() << "activated" << activated.child(0,0).data().toString();
breadcrumbBar()->currentChangedTriggered(activated.child(0,0));
}
}
void SiblingCrumbButton::activateSelf()
{
comboboxActivated(m_index.row());
}

View File

@ -0,0 +1,79 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Casey Link <unnamedrambler@gmail.com>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SIBLINGCRUMBBUTTON_H
#define SIBLINGCRUMBBUTTON_H
#include "breadcrumbbuttonbase.h"
#include "breadcrumbbar.h"
#include "combobox.h"
#include <QList>
#include <QModelIndex>
#include <QPointer>
#include <QSize>
#include <QMenu>
/**
* \brief A factory for sibling crumb buttons
*/
class SiblingCrumbButtonFactory : public BreadcrumbButtonFactory
{
public:
SiblingCrumbButtonFactory(){}
virtual ~SiblingCrumbButtonFactory(){}
virtual BreadcrumbButtonBase* newButton(QModelIndex index, BreadcrumbBar *parent);
};
/**
* \brief A crumb button implementation where the dropdowns show sibling items
* Unlike most crumb buttons, this one shows a list of sibling items (as
* opposed to child items). This is desireable in certain circumstances.
*/
class SiblingCrumbButton : public BreadcrumbButtonBase
{
Q_OBJECT
public:
SiblingCrumbButton(QModelIndex index, BreadcrumbBar *parent);
void setIndex(QModelIndex index);
QModelIndex index() const;
void setActive(bool active);
bool isActive() const;
virtual QSize sizeHint() const;
protected:
virtual void paintEvent(QPaintEvent *event);
private slots:
void fillCombo();
void comboboxActivated(int i);
void activateSelf();
private:
QModelIndex m_index; /*!< our current index */
ComboBox *m_combo; /*!< our combobox! */
};
#endif // SIBLINGCRUMBBUTTON_H