Commit 4147788f authored by Kåre Särs's avatar Kåre Särs

Add the UI for replacing the matches (replace not ready yet)

Fix escaping of html in matches
Fix file name for local files in the match tree
parent 802a9cb5
......@@ -14,10 +14,11 @@ set(katesearchplugin_PART_SRCS
plugin_search.cpp
search_open_files.cpp
search_folder.cpp
replace_matches.cpp
htmldelegate.cpp
)
kde4_add_ui_files(katesearchplugin_PART_SRCS search.ui)
kde4_add_ui_files(katesearchplugin_PART_SRCS search.ui results.ui)
kde4_add_plugin(katesearchplugin ${katesearchplugin_PART_SRCS})
......
......@@ -27,6 +27,8 @@
#include <QtGui/QTextCharFormat>
#include <KLocalizedString>
#include <KDebug>
SPHtmlDelegate::SPHtmlDelegate( QObject* parent )
: QStyledItemDelegate(parent)
{}
......@@ -39,7 +41,7 @@ void SPHtmlDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option
initStyleOption(&options, index);
QTextDocument doc;
doc.setDocumentMargin(0);
//doc.setDocumentMargin(0);
doc.setHtml(index.data().toString());
painter->save();
......@@ -60,7 +62,8 @@ void SPHtmlDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option
QSize SPHtmlDelegate::sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& index) const
{
QTextDocument doc;
doc.setDocumentMargin(0);
//doc.setDocumentMargin(0);
doc.setHtml(index.data().toString());
return doc.size().toSize();;
//kDebug() << doc.toPlainText() << doc.size().toSize();
return doc.size().toSize() + QSize(30, 0); // add margin for the check-box
}
......@@ -44,6 +44,7 @@
#include <QKeyEvent>
#include <QClipboard>
#include <QMenu>
#include <QTextDocument>
static QAction *menuEntry(QMenu *menu,
const QString &before, const QString &after, const QString &desc,
......@@ -106,7 +107,7 @@ KatePluginSearchView::KatePluginSearchView(Kate::MainWindow *mainWin, Kate::Appl
: Kate::PluginView(mainWin),
Kate::XMLGUIClient(KatePluginSearchFactory::componentData()),
m_kateApp(application),
m_curResultTree(0)
m_curResults(0)
{
KAction *a = actionCollection()->addAction("search_in_files");
a->setText(i18n("Search in Files"));
......@@ -267,8 +268,8 @@ void KatePluginSearchView::startSearch()
// return pressed in the folder combo or filter combo
return;
}
m_curResultTree = qobject_cast<QTreeWidget *>(m_ui.resultTabWidget->currentWidget());
if (!m_curResultTree) {
m_curResults =qobject_cast<Results *>(m_ui.resultTabWidget->currentWidget());
if (!m_curResults) {
kWarning() << "This is a bug";
return;
}
......@@ -287,7 +288,7 @@ void KatePluginSearchView::startSearch()
m_useRegExp->isChecked() ? QRegExp::RegExp : QRegExp::FixedString);
clearMarks();
m_curResultTree->clear();
m_curResults->tree->clear();
m_ui.resultTabWidget->setTabText(m_ui.resultTabWidget->currentIndex(),
m_ui.searchCombo->currentText());
......@@ -303,6 +304,8 @@ void KatePluginSearchView::startSearch()
reg);
}
m_toolView->setCursor(Qt::WaitCursor);
m_curResults->matches = 0;
}
void KatePluginSearchView::toggleOptions(bool show)
......@@ -331,41 +334,43 @@ void KatePluginSearchView::searchPatternChanged()
QTreeWidgetItem * KatePluginSearchView::rootFileItem(const QString &url)
{
if (!m_curResultTree) {
if (!m_curResults) {
return 0;
}
KUrl kurl(url);
QString path = kurl.isLocalFile() ? kurl.path() : kurl.upUrl().url();
QString path = kurl.isLocalFile() ? kurl.upUrl().path() : kurl.upUrl().url();
QString name = kurl.fileName();
for (int i=0; i<m_curResultTree->topLevelItemCount(); i++) {
if (m_curResultTree->topLevelItem(i)->data(0, Qt::UserRole).toString() == url) {
int matches = m_curResultTree->topLevelItem(i)->data(1, Qt::UserRole).toInt() + 1;
for (int i=0; i<m_curResults->tree->topLevelItemCount(); i++) {
if (m_curResults->tree->topLevelItem(i)->data(0, Qt::UserRole).toString() == url) {
int matches = m_curResults->tree->topLevelItem(i)->data(1, Qt::UserRole).toInt() + 1;
QString tmpUrl = QString("%1<b>%2</b>: <b>%3</b>").arg(path).arg(name).arg(matches);
m_curResultTree->topLevelItem(i)->setData(0, Qt::DisplayRole, tmpUrl);
m_curResultTree->topLevelItem(i)->setData(1, Qt::UserRole, matches);
return m_curResultTree->topLevelItem(i);
m_curResults->tree->topLevelItem(i)->setData(0, Qt::DisplayRole, tmpUrl);
m_curResults->tree->topLevelItem(i)->setData(1, Qt::UserRole, matches);
return m_curResults->tree->topLevelItem(i);
}
}
// file item not found create a new one
QString tmpUrl = QString("%1<b>%2</b>: <b>%3</b>").arg(path).arg(name).arg(1);
QTreeWidgetItem *item = new QTreeWidgetItem(m_curResultTree, QStringList(tmpUrl));
QTreeWidgetItem *item = new QTreeWidgetItem(m_curResults->tree, QStringList(tmpUrl));
item->setData(0, Qt::UserRole, url);
item->setData(1, Qt::UserRole, 1);
item->setCheckState (0, Qt::Checked);
item->setFlags(item->flags() | Qt::ItemIsTristate);
return item;
}
void KatePluginSearchView::matchFound(const QString &url, int line, int column,
const QString &lineContent, int matchLen)
{
if (!m_curResultTree) {
if (!m_curResults) {
return;
}
QString bold = lineContent.left(column);
bold += "<b>" + lineContent.mid(column, matchLen) + "</b>";
bold += lineContent.mid(column + matchLen);
QString bold = Qt::escape(lineContent.left(column));
bold += "<b>" + Qt::escape(lineContent.mid(column, matchLen)) + "</b>";
bold += Qt::escape(lineContent.mid(column + matchLen));
QStringList row;
row << i18n("Line: <b>%1</b>: %2", line+1, bold);
......@@ -374,6 +379,7 @@ void KatePluginSearchView::matchFound(const QString &url, int line, int column,
item->setData(0, Qt::ToolTipRole, url);
item->setData(1, Qt::UserRole, line);
item->setData(2, Qt::UserRole, column);
item->setCheckState (0, Qt::Checked);
// Add mark if the document is open
KTextEditor::Document* doc = m_kateApp->documentManager()->findUrl(url);
......@@ -398,10 +404,17 @@ void KatePluginSearchView::matchFound(const QString &url, int line, int column,
connect(doc, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)),
this, SLOT(clearMarks()), Qt::UniqueConnection);
m_curResults->matches++;
m_curResults->matchLabel->setText(i18np("Found %1 match.",
"Found %1 matches.",
m_curResults->matches));
}
void KatePluginSearchView::clearMarks()
{
// FIXME: check for ongoing search...
KTextEditor::MarkInterface* iface;
foreach (KTextEditor::Document* doc, m_kateApp->documentManager()->documents()) {
iface = qobject_cast<KTextEditor::MarkInterface*>(doc);
......@@ -430,17 +443,17 @@ void KatePluginSearchView::searchDone()
m_ui.optionsButton->setDisabled(false);
m_ui.displayOptions->setDisabled(false);
if (!m_curResultTree) {
if (!m_curResults) {
return;
}
m_curResultTree->resizeColumnToContents(0);
if (m_curResultTree->topLevelItemCount() > 0) {
m_curResultTree->setCurrentItem(m_curResultTree->topLevelItem(0));
m_curResultTree->setFocus(Qt::OtherFocusReason);
if (m_curResults->tree->topLevelItemCount() > 0) {
m_curResults->tree->setCurrentItem(m_curResults->tree->topLevelItem(0));
m_curResults->setFocus(Qt::OtherFocusReason);
}
m_curResultTree->expandAll();
m_curResultTree = 0;
m_curResults->tree->expandAll();
m_curResults->tree->resizeColumnToContents(0);
m_curResults = 0;
m_toolView->unsetCursor();
}
......@@ -512,39 +525,38 @@ void KatePluginSearchView::writeSessionConfig(KConfigBase* config, const QString
void KatePluginSearchView::addTab()
{
QTreeWidget *tmp = new QTreeWidget();
tmp->header()->setStretchLastSection(false);
tmp->setHeaderHidden(true);
tmp->setTextElideMode(Qt::ElideLeft);
tmp->setAllColumnsShowFocus(false);
tmp->setAlternatingRowColors(true);
tmp->setEditTriggers(QAbstractItemView::NoEditTriggers);
tmp->setRootIsDecorated(true);
tmp->setSelectionBehavior(QAbstractItemView::SelectRows);
tmp->setUniformRowHeights(true);
tmp->setItemDelegate(new SPHtmlDelegate(tmp));
Results *res = new Results();
res->tree->setItemDelegate(new SPHtmlDelegate(res->tree));
// temporarily disable until replace works.
res->replaceButton->setDisabled(true);
connect(tmp, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
this, SLOT (itemSelected(QTreeWidgetItem*)));
connect(res->tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
this, SLOT (itemSelected(QTreeWidgetItem*)));
m_ui.resultTabWidget->addTab(tmp, "");
connect(res->replaceButton, SIGNAL(clicked(bool)), this, SLOT(replaceChecked()));
connect(res->replaceCombo, SIGNAL(returnPressed()), this, SLOT(replaceChecked()));
connect(&m_replacer, SIGNAL(replaceDone()), this, SLOT(replaceDone()));
m_ui.resultTabWidget->addTab(res, "");
m_ui.resultTabWidget->setCurrentIndex(m_ui.resultTabWidget->count()-1);
m_ui.stackedWidget->setCurrentIndex(0);
m_ui.resultTabWidget->tabBar()->show();
tmp->installEventFilter(this);
res->tree->installEventFilter(this);
}
void KatePluginSearchView::closeTab(QWidget *widget)
{
QTreeWidget *tmp = qobject_cast<QTreeWidget *>(widget);
if (m_curResultTree == tmp) {
Results *tmp = qobject_cast<Results *>(widget);
if (m_curResults == tmp) {
m_searchOpenFiles.cancelSearch();
m_searchFolder.cancelSearch();
}
if (m_ui.resultTabWidget->count() > 1) {
delete widget; // remove the tab
m_curResultTree = 0;
delete tmp; // remove the tab
m_curResults = 0;
}
if (m_ui.resultTabWidget->count() == 1) {
m_ui.resultTabWidget->tabBar()->hide();
......@@ -641,6 +653,25 @@ void KatePluginSearchView::searchContextMenu(const QPoint& pos)
}
}
void KatePluginSearchView::replaceChecked()
{
m_curResults =qobject_cast<Results *>(m_ui.resultTabWidget->currentWidget());
if (!m_curResults) {
kWarning() << "Results not found";
return;
}
m_replacer.replaceChecked(m_curResults->tree,
QRegExp()/*FIXME*/,
m_curResults->replaceCombo->currentText());
}
void KatePluginSearchView::replaceDone()
{
m_curResults->buttonStack->setCurrentIndex(0);
m_curResults->replaceCombo->setDisabled(false);
m_curResults = 0;
}
KateSearchCommand::KateSearchCommand(QObject *parent)
: QObject(parent), KTextEditor::Command()
......
......@@ -29,15 +29,25 @@
#include <QTreeWidget>
#include "ui_search.h"
#include "ui_results.h"
#include "search_open_files.h"
#include "search_folder.h"
#include "replace_matches.h"
class KateSearchCommand;
namespace KTextEditor{
class MovingRange;
}
class Results: public QWidget, public Ui::Results
{
Q_OBJECT
public:
Results(QWidget *parent = 0): QWidget(parent), matches(0) { setupUi(this); }
int matches;
};
class KatePluginSearch : public Kate::Plugin
{
Q_OBJECT
......@@ -91,6 +101,10 @@ private Q_SLOTS:
void clearMarks();
void replaceChecked();
void replaceDone();
protected:
bool eventFilter(QObject *obj, QEvent *ev);
......@@ -102,9 +116,10 @@ private:
Kate::Application *m_kateApp;
SearchOpenFiles m_searchOpenFiles;
SearchFolder m_searchFolder;
ReplaceMatches m_replacer;
KAction *m_matchCase;
KAction *m_useRegExp;
QTreeWidget *m_curResultTree;
Results *m_curResults;
QVector<KTextEditor::MovingRange*> m_matchRanges;
};
......
/* Kate search plugin
*
* Copyright (C) 2011 by Kåre Särs <kare.sars@iki.fi>
*
* 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 2 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 in a file called COPYING; if not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include "replace_matches.h"
#include "replace_matches.moc"
ReplaceMatches::ReplaceMatches(QObject *parent) : QObject(parent), m_nextIndex(-1)
{
connect(this, SIGNAL(replaceNextMatch()), this, SLOT(doReplaceNextMatch()), Qt::QueuedConnection);
}
void ReplaceMatches::replaceChecked(QTreeWidget *tree, const QRegExp &regexp, const QString &replace)
{
if (m_nextIndex != -1) return;
m_tree = tree;
m_nextIndex = 0;
m_regExp = regexp;
m_replace = replace;
m_cancelReplace = false;
emit replaceNextMatch();
}
void ReplaceMatches::cancelReplace()
{
m_cancelReplace = true;
}
void ReplaceMatches::doReplaceNextMatch()
{
if (m_cancelReplace) {
m_nextIndex = -1;
emit replaceDone();
return;
}
kDebug();
// int column;
// NOTE The document managers signal documentWillBeDeleted() must be connected to
// cancelReplace(). A closed file could lead to a crash if it is not handled.
// for (int line =0; line < m_docList[m_nextIndex]->lines(); line++) {
// column = m_regExp.indexIn(m_docList[m_nextIndex]->line(line));
// while (column != -1) {
// if (m_docList[m_nextIndex]->url().isLocalFile() ) {
// emit matchFound(m_docList[m_nextIndex]->url().path(), line, column,
// m_docList[m_nextIndex]->line(line), m_regExp.matchedLength());
// }
// else {
// emit matchFound(m_docList[m_nextIndex]->url().prettyUrl(), line, column,
// m_docList[m_nextIndex]->line(line), m_regExp.matchedLength());
// }
// column = m_regExp.indexIn(m_docList[m_nextIndex]->line(line), column + 1);
// }
// }
// m_nextIndex++;
// if (m_nextIndex == m_docList.size()) {
// m_nextIndex = -1;
emit replaceDone();
// }
// else {
// emit replaceNextMatch();
// }
}
/* Kate search plugin
*
* Copyright (C) 2011 by Kåre Särs <kare.sars@iki.fi>
*
* 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 2 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 in a file called COPYING; if not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#ifndef _REPLACE_MATCHES_H_
#define _REPLACE_MATCHES_H_
#include <QObject>
#include <QRegExp>
#include <QTreeWidget>
#include <ktexteditor/document.h>
class ReplaceMatches: public QObject
{
Q_OBJECT
public:
ReplaceMatches(QObject *parent = 0);
void replaceChecked(QTreeWidget *tree, const QRegExp &regexp, const QString &replace);
public Q_SLOTS:
void cancelReplace();
private Q_SLOTS:
void doReplaceNextMatch();
Q_SIGNALS:
void replaceNextMatch();
void replaceDone();
private:
QTreeWidget *m_tree;
int m_nextIndex;
QRegExp m_regExp;
QString m_replace;
bool m_cancelReplace;
};
#endif
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Results</class>
<widget class="QWidget" name="Results">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>443</width>
<height>141</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
<property name="margin">
<number>0</number>
</property>
<item row="1" column="1">
<widget class="KHistoryComboBox" name="replaceCombo">
<property name="editable">
<bool>true</bool>
</property>
<property name="autoCompletion">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QTreeWidget" name="tree">
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="matchLabel">
<property name="text">
<string>Found matches: xxx</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QStackedWidget" name="buttonStack">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="replaceButton">
<property name="text">
<string>Replace checked</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="stopButton">
<property name="text">
<string>stop</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KComboBox</class>
<extends>QComboBox</extends>
<header>kcombobox.h</header>
</customwidget>
<customwidget>
<class>KHistoryComboBox</class>
<extends>KComboBox</extends>
<header>khistorycombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
Markdown is supported
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