#
#
# add_file "res/images/close.svg"
# content [68c1fd79b2d42f89823747a02e7f9c06fa5e5d69]
#
# add_file "res/images/search.svg"
# content [b0f0d68b564390106ec0d64a0ccfa84c00d79fba]
#
# add_file "src/view/widgets/SearchInput.cpp"
# content [e46ad9c696ada33e34da30344acca3ac7cdf66ff]
#
# add_file "src/view/widgets/SearchInput.h"
# content [8d3b0bd2ebee053cc3b5efe4f8e0803eeb8c78ee]
#
# patch "src/model/Inventory.cpp"
# from [dbd52e14bb66a0aa0e2737f70af4da384f4a0ef3]
# to [758c0469a1427919e7af3814b8437a79e6f8a35c]
#
# patch "src/model/Inventory.h"
# from [268e93aa6b0b830a5bcc947353018fba8508ded3]
# to [705eda6338ef80e953adaaa0b490e06c67a62138]
#
# patch "src/model/InventoryModel.cpp"
# from [d957fdce854d8b0b59565817d5dc14d5bb390be9]
# to [376f3442efd15efb785342f562bbf37b35561d06]
#
# patch "src/model/InventoryModel.h"
# from [c4bdceaabf117ed45fe64da4bd3d56ca6d9e31a1]
# to [1915c6ef78d7902a9fe55d206e8c6ea6de564ce5]
#
# patch "src/model/InventoryProxyModel.cpp"
# from [208e2c793a5b154ee6c3088c23dda52dc9922bce]
# to [41d21933f657f8770ad2bdb9326713a5fb87e304]
#
# patch "src/model/InventoryProxyModel.h"
# from [feb55b88ad3148ca79c6b03117b77c3d251bed57]
# to [31ef55bd31c2a7d42b78e2075d55ec0790d878d5]
#
# patch "src/view/mainwindows/WorkspaceWindow.cpp"
# from [ea508344b2cd8067b9ff3b02340462104ac05409]
# to [f9c8af974e5585beff33b6f55b69e2fd9bd1f10e]
#
# patch "src/view/mainwindows/WorkspaceWindow.h"
# from [99c36a0a442928d9c0653e3fe12fc0d4fef92de7]
# to [f20d3515c093e43af587667d01ff49a8a3154c2f]
#
============================================================
--- res/images/close.svg 68c1fd79b2d42f89823747a02e7f9c06fa5e5d69
+++ res/images/close.svg 68c1fd79b2d42f89823747a02e7f9c06fa5e5d69
@@ -0,0 +1,29 @@
+
+
+
+
============================================================
--- res/images/search.svg b0f0d68b564390106ec0d64a0ccfa84c00d79fba
+++ res/images/search.svg b0f0d68b564390106ec0d64a0ccfa84c00d79fba
@@ -0,0 +1,26 @@
+
+
+
+
============================================================
--- src/view/widgets/SearchInput.cpp e46ad9c696ada33e34da30344acca3ac7cdf66ff
+++ src/view/widgets/SearchInput.cpp e46ad9c696ada33e34da30344acca3ac7cdf66ff
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (C) 2009 by Thomas Keller *
+ * address@hidden *
+ * *
+ * This program 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. *
+ * *
+ * This program 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 this program. If not, see . *
+ ***************************************************************************/
+
+#include "SearchInput.h"
+#include "vocab.h"
+#include
+#include
+
+SearchInput::SearchInput(QWidget * parent)
+ : QLineEdit(parent)
+{
+ setMaximumHeight(20);
+
+#ifdef Q_WS_MAC
+ setAttribute(Qt::WA_MacShowFocusRect, false);
+#endif
+
+ QFont font;
+ font.setPointSize(12);
+ setFont(font);
+
+ setStyleSheet(
+ "QLineEdit { "
+ " border: 1px solid palette(dark); "
+ " border-radius: 10px; "
+ " padding: 0 20px 0 16px; "
+ " selection-background-color: palette(dark); "
+ " background: url(:/images/search.svg) no-repeat left center; "
+ "} "
+ );
+
+ QBoxLayout * layout = new QBoxLayout(QBoxLayout::RightToLeft, this);
+ clearButton = new QPushButton(this);
+ clearButton->setStyleSheet(
+ "QPushButton { "
+ " border: 0; "
+ " background: transparent no-repeat center middle url(:/images/close.svg);"
+ "} "
+ );
+ layout->addWidget(clearButton);
+ layout->addStretch();
+ layout->setContentsMargins(0, 4, 0, 4);
+
+ connect(
+ clearButton, SIGNAL(clicked()),
+ this, SLOT(clear())
+ );
+
+ connect(
+ clearButton, SIGNAL(clicked()),
+ clearButton, SLOT(hide())
+ );
+
+ connect(
+ this, SIGNAL(textChanged(const QString &)),
+ this, SLOT(slotTextChanged(const QString &))
+ );
+
+ clearButton->setVisible(text().size() > 0);
+}
+
+SearchInput::~SearchInput()
+{
+ delete clearButton;
+}
+
+void SearchInput::slotTextChanged(const QString & text)
+{
+ clearButton->setVisible(text.size() > 0);
+}
+
============================================================
--- src/view/widgets/SearchInput.h 8d3b0bd2ebee053cc3b5efe4f8e0803eeb8c78ee
+++ src/view/widgets/SearchInput.h 8d3b0bd2ebee053cc3b5efe4f8e0803eeb8c78ee
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2009 by Thomas Keller *
+ * address@hidden *
+ * *
+ * This program 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. *
+ * *
+ * This program 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 this program. If not, see . *
+ ***************************************************************************/
+
+#ifndef SEARCH_INPUT_H
+#define SEARCH_INPUT_H
+
+#include
+#include
+#include
+#include
+
+class SearchInput : public QLineEdit
+{
+ Q_OBJECT
+public:
+ SearchInput(QWidget *);
+ ~SearchInput();
+
+private:
+ QPushButton * clearButton;
+
+private slots:
+ void slotTextChanged(const QString &);
+};
+
+#endif
+
============================================================
--- src/model/Inventory.cpp dbd52e14bb66a0aa0e2737f70af4da384f4a0ef3
+++ src/model/Inventory.cpp 758c0469a1427919e7af3814b8437a79e6f8a35c
@@ -47,6 +47,16 @@ void Inventory::read(const QString & pat
{
I(!workspacePath.isEmpty());
+ if (itemMap.contains(path))
+ {
+ const InventoryItem * item = itemMap.value(path);
+ if (item->hasStatus(InventoryItem::Unknown))
+ {
+ W(QString("skipping read on unknown path '%1'").arg(path));
+ return;
+ }
+ }
+
QStringList cmd = QStringList() << "inventory";
if (!path.isEmpty())
{
@@ -112,8 +122,10 @@ void Inventory::processTaskResult(const
// not tell us if the node exists on the filesystem - in this case we
// want to _keep_ the node because otherwise people won't be able to
// add unknown paths later on...
- if (output.indexOf("unknown path") != -1 &&
- itemMap.contains(queriedPath))
+ if (task->outOfBandMessagesMatch(
+ MonotoneTask::Warning,
+ QRegExp("/restriction includes unknown path .+/")
+ ) && itemMap.contains(queriedPath))
{
if (QFile::exists(workspacePath + "/" + itemMap[queriedPath]->getPath()))
{
@@ -134,10 +146,8 @@ void Inventory::processTaskResult(const
// everything else _should_ be a problem with the workspace format.
// note that we do not explicitely check for this, we throw it just
- // back to the user...
- emit invalidWorkspaceFormat(
- MonotoneUtil::stripMtnPrefix(output)
- );
+ // back to the user and hopefully log something useful
+ emit invalidWorkspaceFormat();
return;
}
============================================================
--- src/model/Inventory.h 268e93aa6b0b830a5bcc947353018fba8508ded3
+++ src/model/Inventory.h 705eda6338ef80e953adaaa0b490e06c67a62138
@@ -60,7 +60,7 @@ signals:
void dataChanged(ModelItem *);
void inventoryRead(const QString &);
- void invalidWorkspaceFormat(const QString &);
+ void invalidWorkspaceFormat();
};
#endif
============================================================
--- src/model/InventoryModel.cpp d957fdce854d8b0b59565817d5dc14d5bb390be9
+++ src/model/InventoryModel.cpp 376f3442efd15efb785342f562bbf37b35561d06
@@ -29,8 +29,8 @@ InventoryModel::InventoryModel(QObject *
);
connect(
- inventory, SIGNAL(invalidWorkspaceFormat(const QString &)),
- this, SIGNAL(invalidWorkspaceFormat(const QString &))
+ inventory, SIGNAL(invalidWorkspaceFormat()),
+ this, SIGNAL(invalidWorkspaceFormat())
);
connect(
@@ -183,6 +183,11 @@ QModelIndex InventoryModel::index(int ro
QModelIndex InventoryModel::index(int row, int column, const QModelIndex & parent) const
{
+ if (column < 0)
+ {
+ return QModelIndex();
+ }
+
ModelItem * parentItem;
if (!parent.isValid())
@@ -291,6 +296,11 @@ int InventoryModel::rowCount(const QMode
int InventoryModel::rowCount(const QModelIndex & parent) const
{
+ if (parent.column() > 0)
+ {
+ return 0;
+ }
+
ModelItem * parentItem = inventory->rootItem;
if (parent.isValid())
============================================================
--- src/model/InventoryModel.h c4bdceaabf117ed45fe64da4bd3d56ca6d9e31a1
+++ src/model/InventoryModel.h 1915c6ef78d7902a9fe55d206e8c6ea6de564ce5
@@ -74,7 +74,7 @@ signals:
signals:
//! forward
- void invalidWorkspaceFormat(const QString &);
+ void invalidWorkspaceFormat();
void pathsInserted(const QStringList &);
void pathsRemoved(const QStringList &);
};
============================================================
--- src/model/InventoryProxyModel.cpp 208e2c793a5b154ee6c3088c23dda52dc9922bce
+++ src/model/InventoryProxyModel.cpp 41d21933f657f8770ad2bdb9326713a5fb87e304
@@ -24,21 +24,23 @@ InventoryProxyModel::InventoryProxyModel
: QSortFilterProxyModel(parent), folderTree(isFolderTree),
sortColumn(0), hideIgnored(false), viewOption(All),
sortOrder(Qt::AscendingOrder)
-{}
+{
+ filter.setCaseSensitivity(Qt::CaseInsensitive);
+}
InventoryProxyModel::~InventoryProxyModel() {}
bool InventoryProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const
{
- QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
- if (!index.isValid()) return false;
- ModelItem * item = static_cast(index.internalPointer());
+ QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
+ ModelItem * item = static_cast(sourceIndex.internalPointer());
+
// always return the root item
if (item->isRoot())
return true;
- PseudoItem * psitem = dynamic_cast(item);
+ PseudoItem * psitem = qobject_cast(item);
if (psitem)
{
// only display this item if this is not the folder tree view
@@ -50,7 +52,7 @@ bool InventoryProxyModel::filterAcceptsR
I(false);
}
- InventoryItem * invitem = dynamic_cast(item);
+ InventoryItem * invitem = qobject_cast(item);
I(invitem);
// hide ignored files (not recursively)
@@ -88,23 +90,28 @@ bool InventoryProxyModel::filterAcceptsR
// check if we should only display folders
acceptRow &= !folderTree || invitem->isDirectory();
+
+ acceptRow &= filter.isEmpty() ||
+ const_cast(this)->itemMatchesFilter(invitem);
+
return acceptRow;
}
bool InventoryProxyModel::lessThan(const QModelIndex & left, const QModelIndex & right) const
{
- ModelItem * itemLeft = static_cast(left.internalPointer());
+ ModelItem * itemLeft = static_cast(left.internalPointer());
ModelItem * itemRight = static_cast(right.internalPointer());
- InventoryItem * invitemLeft = dynamic_cast(itemLeft);
- InventoryItem * invitemRight = dynamic_cast(itemRight);
+ InventoryItem * invitemLeft = qobject_cast(itemLeft);
+ InventoryItem * invitemRight = qobject_cast(itemRight);
- // We shall sort by the name of the item
+ // place pseudo items always right on top, in no particular order
+ if (!invitemLeft || !invitemRight)
+ return false;
+
+ // we shall sort by the name of the item
if (sortColumn == 0)
{
- // place pseudo items always right on top
- if (!invitemLeft || !invitemRight) return false;
-
if (invitemLeft->isDirectory() && invitemRight->isDirectory())
{
return invitemLeft->getFilename() < invitemRight->getFilename();
@@ -123,16 +130,15 @@ bool InventoryProxyModel::lessThan(const
// last case: !invitemLeft->isDirectory() && invitemRight->isDirectory()
return false;
}
+
// we shall sort only by status
- else if (sortColumn == 1)
+ if (sortColumn == 1)
{
return invitemLeft->getStatusString() < invitemRight->getStatusString();
}
+
// anything else
- else
- {
- return false;
- }
+ return false;
}
void InventoryProxyModel::sort(int column, Qt::SortOrder order)
@@ -146,7 +152,7 @@ void InventoryProxyModel::setHideIgnored
{
if (hide == hideIgnored) return;
hideIgnored = hide;
- filterChanged();
+ invalidateFilter();
}
void InventoryProxyModel::setViewOption(int opt)
@@ -154,6 +160,56 @@ void InventoryProxyModel::setViewOption(
ViewOption newOpt = static_cast(opt);
if (viewOption == newOpt) return;
viewOption = newOpt;
- filterChanged();
+ invalidateFilter();
}
+void InventoryProxyModel::filterItemsByName(const QString & pattern)
+{
+ if (pattern.isEmpty())
+ {
+ filter.setPattern(QString());
+ filterCache.clear();
+ invalidateFilter();
+ return;
+ }
+
+ QString escapedPattern = QRegExp::escape(pattern);
+ if (filter.pattern() == escapedPattern)
+ return;
+
+ filter.setPattern(escapedPattern);
+ filterCache.clear();
+ invalidateFilter();
+}
+
+bool InventoryProxyModel::itemMatchesFilter(const InventoryItem * item)
+{
+ QString path = item->getPath();
+ if (filterCache.contains(path))
+ {
+ return filterCache[path];
+ }
+
+ if (filter.indexIn(item->getLabel()) >= 0)
+ {
+ filterCache.insert(path, true);
+ return true;
+ }
+
+ if (folderTree)
+ {
+ foreach (const ModelItem * child, item->getChildren())
+ {
+ const InventoryItem * invitem =
+ qobject_cast(child);
+
+ if (invitem && itemMatchesFilter(invitem))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
============================================================
--- src/model/InventoryProxyModel.h feb55b88ad3148ca79c6b03117b77c3d251bed57
+++ src/model/InventoryProxyModel.h 31ef55bd31c2a7d42b78e2075d55ec0790d878d5
@@ -19,6 +19,7 @@
#ifndef INVENTORYPROXYMODEL_H
#define INVENTORYPROXYMODEL_H
+#include "InventoryItem.h"
#include
class InventoryProxyModel : public QSortFilterProxyModel
@@ -35,16 +36,23 @@ public:
bool lessThan(const QModelIndex &, const QModelIndex &) const;
void sort(int, Qt::SortOrder order = Qt::AscendingOrder);
+ static QModelIndex inventoryIndex(const QModelIndex &);
+
public slots:
void setHideIgnoredFiles(bool);
void setViewOption(int);
+ void filterItemsByName(const QString &);
private:
+ bool itemMatchesFilter(const InventoryItem *);
+
bool folderTree;
int sortColumn;
bool hideIgnored;
ViewOption viewOption;
Qt::SortOrder sortOrder;
+ QRegExp filter;
+ QMap filterCache;
};
#endif
============================================================
--- src/view/mainwindows/WorkspaceWindow.cpp ea508344b2cd8067b9ff3b02340462104ac05409
+++ src/view/mainwindows/WorkspaceWindow.cpp f9c8af974e5585beff33b6f55b69e2fd9bd1f10e
@@ -28,11 +28,12 @@ WorkspaceWindow::WorkspaceWindow() : Dat
WorkspaceWindow::WorkspaceWindow() : DatabaseWindow(), mainSplitter(0),
listSplitter(0), treeView(0), listView(0), attrView(0), statusBar(0),
- iconHelp(0), invModel(0), attrModel(0), proxyModelFolderTree(0),
- proxyModelFileList(0), invWatcher(0)
+ toolBar(0), searchInput(0), iconHelp(0), invModel(0), attrModel(0),
+ proxyModelFolderTree(0), proxyModelFileList(0), invWatcher(0)
{
setObjectName("WorkspaceWindow");
setDockOptions(QMainWindow::ForceTabbedDocks);
+ setUnifiedTitleAndToolBarOnMac(true);
}
WorkspaceWindow::~WorkspaceWindow()
@@ -48,6 +49,8 @@ WorkspaceWindow::~WorkspaceWindow()
if (listSplitter) delete listSplitter;
if (mainSplitter) delete mainSplitter;
if (statusBar) delete statusBar;
+ if (searchInput) delete searchInput;
+ if (toolBar) delete toolBar;
if (iconHelp)
{
removeDockWidget(iconHelp);
@@ -97,6 +100,18 @@ void WorkspaceWindow::setup()
statusBar = new QStatusBar(this);
setStatusBar(statusBar);
+ toolBar = new QToolBar(this);
+
+ QWidget * spacer = new QWidget(toolBar);
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ toolBar->addWidget(spacer);
+
+ searchInput = new SearchInput(toolBar);
+ searchInput->setMaximumWidth(150);
+ toolBar->addWidget(searchInput);
+
+ addToolBar(toolBar);
+
mainSplitter = new Splitter(this, "MainSplitter");
mainSplitter->setOrientation(Qt::Horizontal);
@@ -198,6 +213,16 @@ void WorkspaceWindow::setup()
proxyModelFolderTree = new InventoryProxyModel(this, true);
proxyModelFileList = new InventoryProxyModel(this, false);
+ connect(
+ searchInput, SIGNAL(textChanged(const QString &)),
+ proxyModelFolderTree, SLOT(filterItemsByName(const QString &))
+ );
+
+ connect(
+ searchInput, SIGNAL(textChanged(const QString &)),
+ proxyModelFileList, SLOT(filterItemsByName(const QString &))
+ );
+
proxyModelFolderTree->setSourceModel(invModel);
proxyModelFileList->setSourceModel(invModel);
@@ -217,8 +242,8 @@ void WorkspaceWindow::setup()
);
connect(
- invModel, SIGNAL(invalidWorkspaceFormat(const QString &)),
- this, SLOT(invalidWorkspaceFormat(const QString &))
+ invModel, SIGNAL(invalidWorkspaceFormat()),
+ this, SLOT(invalidWorkspaceFormat())
);
connect(
@@ -356,12 +381,12 @@ void WorkspaceWindow::maybeReadNodeInfo(
attrModel->readAttributes(invitem->getPath());
}
-void WorkspaceWindow::invalidWorkspaceFormat(const QString & error)
+void WorkspaceWindow::invalidWorkspaceFormat()
{
QMessageBox::critical(
this,
tr("Error"),
- tr("Unable to read workspace format:\n%1").arg(error),
+ tr("Unable to read the workspace. Please check the log for details."),
QMessageBox::Ok, 0, 0
);
close();
============================================================
--- src/view/mainwindows/WorkspaceWindow.h 99c36a0a442928d9c0653e3fe12fc0d4fef92de7
+++ src/view/mainwindows/WorkspaceWindow.h f20d3515c093e43af587667d01ff49a8a3154c2f
@@ -31,8 +31,10 @@
#include "Splitter.h"
#include "IconHelp.h"
#include "NodeInfo.h"
+#include "SearchInput.h"
#include
+#include
class WorkspaceWindow: public DatabaseWindow
{
@@ -55,18 +57,20 @@ protected:
InventoryView * listView;
AttributesView * attrView;
QStatusBar * statusBar;
+ QToolBar * toolBar;
+ SearchInput * searchInput;
IconHelp * iconHelp;
NodeInfo * nodeInfo;
- InventoryModel * invModel;
- GetAttributes * attrModel;
- InventoryProxyModel * proxyModelFolderTree;
- InventoryProxyModel * proxyModelFileList;
- InventoryWatcher * invWatcher;
+ InventoryModel * invModel;
+ GetAttributes * attrModel;
+ InventoryProxyModel * proxyModelFolderTree;
+ InventoryProxyModel * proxyModelFileList;
+ InventoryWatcher * invWatcher;
private slots:
void maybeReadNodeInfo(const QModelIndexList &);
- void invalidWorkspaceFormat(const QString &);
+ void invalidWorkspaceFormat();
void openFile(const QString &);
};