Commit a10c4c7a authored by Waqar Ahmed's avatar Waqar Ahmed Committed by Christoph Cullmann
Browse files

Use a listview for the bar display

parent d0f19b54
......@@ -11,6 +11,7 @@
#include <QAbstractListModel>
#include <QAction>
#include <QApplication>
#include <QDir>
#include <QHBoxLayout>
#include <QIcon>
......@@ -18,7 +19,10 @@
#include <QListView>
#include <QMenu>
#include <QMimeDatabase>
#include <QPainter>
#include <QScrollBar>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QToolButton>
#include <QUrl>
......@@ -62,6 +66,8 @@ public:
void setDir(const QDir &dir)
{
m_fileInfos.clear();
beginResetModel();
const auto fileInfos = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs | QDir::Hidden);
for (const auto &fi : fileInfos) {
......@@ -112,7 +118,7 @@ public:
const auto vScroll = m_list.verticalScrollBar();
int w = m_list.sizeHintForColumn(0) + (vScroll ? vScroll->height() / 2 : 0);
setFixedSize(qMin(w, 300), qMin(h, 600));
setFixedSize(qMin(w, 500), qMin(h, 600));
}
void onClicked(const QModelIndex &idx)
......@@ -138,16 +144,178 @@ private:
DirFilesModel m_model;
};
enum BreadCrumbRole {
PathRole = Qt::UserRole + 1,
IsFile = Qt::UserRole + 2,
};
class BreadCrumbDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
using QStyledItemDelegate::QStyledItemDelegate;
bool isDir(const QModelIndex &idx) const
{
return !idx.data(BreadCrumbRole::PathRole).toString().isEmpty();
}
void paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const override
{
auto option = opt;
if (isDir(index) && option.state & QStyle::State_MouseOver) {
painter->fillRect(opt.rect, option.palette.brush(QPalette::Inactive, QPalette::Highlight));
}
QStyledItemDelegate::paint(painter, opt, index);
}
QSize sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &idx) const override
{
constexpr int hMargin = 2;
const auto str = idx.data(Qt::DisplayRole).toString();
if (!str.isEmpty()) {
auto size = QStyledItemDelegate::sizeHint(opt, idx);
const int w = opt.fontMetrics.horizontalAdvance(str) + 8;
size.rwidth() = w;
if (idx.data(BreadCrumbRole::IsFile).toBool() && !idx.data(Qt::DecorationRole).isNull()) {
size.rwidth() += 16 + hMargin + hMargin;
}
return size;
} else if (!idx.data(Qt::DecorationRole).isNull()) {
QSize s(16, 16);
s = s.grownBy({hMargin, 0, hMargin, 0});
return s;
}
return QStyledItemDelegate::sizeHint(opt, idx);
}
};
class BreadCrumbView : public QListView
{
Q_OBJECT
public:
BreadCrumbView(QWidget *parent = nullptr)
: QListView(parent)
{
setFlow(QListView::LeftToRight);
setModel(&m_model);
setFrameStyle(QFrame::NoFrame);
setSelectionMode(QAbstractItemView::NoSelection);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setItemDelegate(new BreadCrumbDelegate(this));
setEditTriggers(QAbstractItemView::NoEditTriggers);
connect(qApp, &QApplication::paletteChanged, this, &BreadCrumbView::updatePalette, Qt::QueuedConnection);
auto font = this->font();
font.setPointSize(font.pointSize() - 1);
setFont(font);
updatePalette();
connect(this, &QListView::clicked, this, &BreadCrumbView::onClicked);
}
void updatePalette()
{
auto pal = palette();
pal.setBrush(QPalette::Base, parentWidget()->palette().window());
setPalette(pal);
}
void setUrl(const QUrl &url)
{
if (url.isEmpty()) {
return;
}
const QString s = url.toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile);
const auto res = splittedUrl(s);
const auto &file = res.first;
const auto &dirs = res.second;
m_model.clear();
for (const auto &dir : dirs) {
auto item = new QStandardItem(dir.name);
item->setData(dir.path, BreadCrumbRole::PathRole);
m_model.appendRow(item);
auto sep = new QStandardItem(QIcon::fromTheme(QStringLiteral("arrow-right")), {});
m_model.appendRow(sep);
}
const auto icon = QIcon::fromTheme(QMimeDatabase().mimeTypeForFile(s).iconName());
auto fileRow = new QStandardItem(icon, file);
fileRow->setData(true, BreadCrumbRole::IsFile);
m_model.appendRow(fileRow);
}
void onClicked(const QModelIndex &idx)
{
auto path = idx.data(BreadCrumbRole::PathRole).toString();
if (path.isEmpty()) {
return;
}
auto pos = mapToGlobal(rectForIndex(idx).bottomLeft());
QDir d(path);
DirFilesList m(this);
auto par = static_cast<KateUrlBar *>(parentWidget());
connect(&m, &DirFilesList::openUrl, par, &KateUrlBar::openUrlRequested);
m.setDir(d);
m.exec(pos);
}
private:
struct DirNamePath {
QString name;
QString path;
};
std::pair<QString, QVector<DirNamePath>> splittedUrl(const QString &s)
{
const int slashIndex = s.lastIndexOf(QLatin1Char('/'));
if (slashIndex == -1) {
return {};
}
const QString fileName = s.mid(slashIndex + 1);
QDir dir(s);
QVector<DirNamePath> dirsList;
while (dir.cdUp()) {
if (dir.dirName().isEmpty()) {
continue;
}
DirNamePath dnp{dir.dirName(), dir.absolutePath()};
dirsList.push_back(dnp);
}
std::reverse(dirsList.begin(), dirsList.end());
return {fileName, dirsList};
}
QStandardItemModel m_model;
};
KateUrlBar::KateUrlBar(KateViewSpace *parent)
: QWidget(parent)
{
setFixedHeight(25);
setFixedHeight(24);
setContentsMargins({});
m_layout = new QHBoxLayout(this);
m_layout->setContentsMargins({});
m_layout->setSpacing(0);
m_breadCrumbView = new BreadCrumbView(this);
m_layout->addWidget(m_breadCrumbView);
auto *vm = parent->viewManger();
connect(vm, &KateViewManager::viewChanged, this, &KateUrlBar::onViewChanged);
......@@ -172,119 +340,17 @@ void KateUrlBar::onViewChanged(KTextEditor::View *v)
if (vm && !vm->showUrlNavBar()) {
return;
}
m_paths.clear();
QLayoutItem *l;
while ((l = m_layout->takeAt(0)) != nullptr) {
delete l->widget();
delete l;
}
const auto url = v->document()->url();
if (url.isEmpty()) {
if (url.isEmpty() || !url.isLocalFile()) {
hide();
return;
}
auto res = splittedUrl(url);
const auto &file = res.first;
const auto &dirs = res.second;
if (dirs.isEmpty() || file.isEmpty()) {
hide();
return;
}
m_breadCrumbView->setUrl(v->document()->url());
for (const auto &dir : dirs) {
m_layout->addWidget(dirButton(dir.name, dir.path));
m_layout->addWidget(separatorLabel());
}
m_layout->addWidget(fileLabel(file));
m_layout->addStretch();
if (isHidden())
show();
}
std::pair<QString, QVector<KateUrlBar::DirNamePath>> KateUrlBar::splittedUrl(const QUrl &u)
{
QString s = u.toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile);
const int slashIndex = s.lastIndexOf(QLatin1Char('/'));
if (slashIndex == -1) {
return {};
}
const QString fileName = s.mid(slashIndex + 1);
QDir dir(s);
QVector<DirNamePath> dirsList;
while (dir.cdUp()) {
if (dir.dirName().isEmpty()) {
continue;
}
DirNamePath dnp{dir.dirName(), dir.absolutePath()};
dirsList.push_back(dnp);
}
std::reverse(dirsList.begin(), dirsList.end());
return {fileName, dirsList};
}
QLabel *KateUrlBar::separatorLabel()
{
QLabel *sep = new QLabel(this);
sep->setPixmap(QIcon::fromTheme(QStringLiteral("arrow-right")).pixmap(QSize(16, 16)));
return sep;
}
QToolButton *KateUrlBar::dirButton(const QString &dirName, const QString &path)
{
QToolButton *tb = new QToolButton(this);
tb->setText(dirName);
tb->setArrowType(Qt::RightArrow);
tb->setToolButtonStyle(Qt::ToolButtonTextOnly);
tb->setAutoRaise(true);
connect(tb, &QToolButton::clicked, this, &KateUrlBar::pathClicked);
m_paths.push_back({tb, path});
return tb;
}
QLabel *KateUrlBar::fileLabel(const QString &file)
{
auto l = new QLabel(file);
auto font = l->font();
font.setPointSize(font.pointSize() - 1);
l->setFont(font);
l->setAlignment(Qt::AlignCenter);
l->setContentsMargins({6, 0, 0, 0});
return l;
}
void KateUrlBar::pathClicked()
{
auto button = sender();
if (!button) {
return;
}
// Find the path that this toolbutton refers to
auto it = std::find_if(m_paths.begin(), m_paths.end(), [button](const std::pair<QToolButton *, QString> &tbPath) {
return tbPath.first == button;
});
// not found?
if (it == m_paths.end()) {
return;
}
const QToolButton *tb = it->first;
const QString path = it->second;
QDir d(path);
DirFilesList m(this);
connect(&m, &DirFilesList::openUrl, this, &KateUrlBar::openUrlRequested);
m.setDir(d);
auto pos = tb->mapToGlobal(tb->pos()) - tb->pos();
pos.setY(pos.y() + tb->height());
m.exec(pos);
}
#include "kateurlbar.moc"
......@@ -18,20 +18,9 @@ Q_SIGNALS:
void openUrlRequested(const QUrl &url);
private:
// helper struct containing dir name and path
struct DirNamePath {
QString name;
QString path;
};
void onViewChanged(KTextEditor::View *v);
std::pair<QString, QVector<DirNamePath>> splittedUrl(const QUrl &u);
class QLabel *separatorLabel();
class QToolButton *dirButton(const QString &dirName, const QString &path);
class QLabel *fileLabel(const QString &file);
class QHBoxLayout *m_layout;
void pathClicked();
QVector<std::pair<QToolButton *, QString>> m_paths;
class BreadCrumbView *m_breadCrumbView;
};
#endif
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment