Double-click on file in message window -> jump to it in tree?

View: New views
14 Messages — Rating Filter:   Alert me  

Double-click on file in message window -> jump to it in tree?

by Muschick Christian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello!

I always wondered why it isn't possible to jump to a file in the tree
view by double-clicking on it in the message window. Has this ever been
discussed and if so, are there any problems I don't see at the moment?
If not, I would like to implement this feature for practice.

regards,
christian
_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Bugzilla from christian.loose@hamburg.de :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Sunday 16 April 2006 19:32, Muschick Christian wrote:
> Hello!
>
Hi,

Sorry for the late answer!

> I always wondered why it isn't possible to jump to a file in the tree
> view by double-clicking on it in the message window. Has this ever been
> discussed and if so, are there any problems I don't see at the moment?

No, this idea is new and interesting.

The only problem I see ATM is how to visually indicate that the file names
are "clickable". Normally one would probably underline the name like a link
but IMHO this would look ugly. Maybe just underline it on mouse hover?

> If not, I would like to implement this feature for practice.

Please go ahead. I'm eager to try it out.

Bye, Christian
_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Muschick Christian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Hi!

>> I always wondered why it isn't possible to jump to a file in the tree
>> view by double-clicking on it in the message window. Has this ever been
>> discussed and if so, are there any problems I don't see at the moment?
>
> No, this idea is new and interesting.

I'm happy to hear that.

>
> The only problem I see ATM is how to visually indicate that the file names
> are "clickable". Normally one would probably underline the name like a link
> but IMHO this would look ugly. Maybe just underline it on mouse hover?

Well for starters I sticked with the simplest solution and just
underlined the file names. Unfortunately, the QTextEdit widget doesn't
seem to have mouse hover signals. Can you think of an elegant solution
to do this?
I also tried <a></a> tags instead of underline to achieve a change of
the mouse pointer, but the tags don't seem to have any effect.

I attached a patch against the 3.5 SVN branch, produced by "svn diff".
Is this the correct way to do it? Should I diff against trunk?


greetings
christian

Index: cervisia/protocolview.h
===================================================================
--- cervisia/protocolview.h (revision 533149)
+++ cervisia/protocolview.h (working copy)
@@ -51,9 +51,11 @@
 signals:
     void receivedLine(QString line);
     void jobFinished(bool normalExit, int exitStatus);
+    void jumpToFile(QString filepath);
 
 private slots:
     void cancelJob();
+    void clicked(int para, int pos);
 
 private:
     void processOutput();
Index: cervisia/updateview.h
===================================================================
--- cervisia/updateview.h (revision 533149)
+++ cervisia/updateview.h (working copy)
@@ -78,7 +78,8 @@
     void foldTree();
     void finishJob(bool normalExit, int exitStatus);
     void processUpdateLine(QString line);
-
+    void jumpToFile(QString filepath);
+    
 private slots:
     void itemExecuted(QListViewItem *item);
     
Index: cervisia/updateview_items.h
===================================================================
--- cervisia/updateview_items.h (revision 533149)
+++ cervisia/updateview_items.h (working copy)
@@ -59,6 +59,8 @@
 
     virtual void accept(Visitor&) = 0;
 
+    virtual UpdateItem * findItemByFilePath(QString /* path */) const { return NULL; }
+    
 protected:
 
     UpdateView* updateView() const { return static_cast<UpdateView*>(listView()); }
@@ -92,8 +94,10 @@
 
     virtual void accept(Visitor&);
 
+    virtual UpdateItem * findItemByFilePath(QString path) const;
+    
     enum { RTTI = 10000 };
-
+    
 private:
 
     void scanDirectory();
@@ -102,7 +106,7 @@
     UpdateFileItem* createFileItem(const Cervisia::Entry& entry);
 
     UpdateItem* insertItem(UpdateItem* item);
-
+    
     UpdateItem* findItem(const QString& name) const;
 
     typedef QMap<QString, UpdateItem*> TMapItemsByName;
Index: cervisia/updateview.cpp
===================================================================
--- cervisia/updateview.cpp (revision 533149)
+++ cervisia/updateview.cpp (working copy)
@@ -590,6 +590,21 @@
 }
 
 
+void UpdateView::jumpToFile(QString filepath)
+{
+    UpdateItem* rootItem = static_cast<UpdateItem*>(firstChild());
+    if (!rootItem) return;
+    
+    UpdateItem* fileItem = rootItem->findItemByFilePath(filepath);
+    if (!fileItem) return;
+    
+    ensureItemVisible(fileItem);
+    clearSelection();
+    setSelected(fileItem, true);
+}
+
+
+
 void UpdateView::updateItem(const QString& filePath, EntryStatus status, bool isdir)
 {
     if (isdir && filePath == QChar('.'))
Index: cervisia/cervisiapart.cpp
===================================================================
--- cervisia/cervisiapart.cpp (revision 533149)
+++ cervisia/cervisiapart.cpp (working copy)
@@ -145,6 +145,8 @@
 
         protocol = new ProtocolView(appId, splitter);
         protocol->setFocusPolicy( QWidget::StrongFocus );
+        connect( protocol, SIGNAL(jumpToFile(QString)),
+                 update, SLOT(jumpToFile(QString)) );
 
         setWidget(splitter);
     }
Index: cervisia/protocolview.cpp
===================================================================
--- cervisia/protocolview.cpp (revision 533149)
+++ cervisia/protocolview.cpp (working copy)
@@ -64,6 +64,9 @@
                       "slotReceivedOutput(QString)", true);
     connectDCOPSignal(job->app(), job->obj(), "receivedStderr(QString)",
                       "slotReceivedOutput(QString)", true);
+
+    connect( this, SIGNAL(clicked(int, int)),
+             this, SLOT(clicked(int, int)) );
 }
 
 
@@ -110,6 +113,29 @@
 }
 
 
+/**
+ *  If a status line is clicked and it represents a file, we
+ *  want to jump to it in the tree view.
+ */
+void ProtocolView::clicked(int para, int )
+{
+    QString line = text(para);
+    
+    if (line.length() <=2 || line[1] != ' ') return;
+
+    if (!line.startsWith("C") &&
+        !line.startsWith("A") &&
+        !line.startsWith("R") &&
+        !line.startsWith("M") &&
+        !line.startsWith("U") &&
+        !line.startsWith("P") &&
+        !line.startsWith("?")) return;
+
+    emit jumpToFile(line.mid(2));
+}
+
+
+
 void ProtocolView::slotReceivedOutput(QString buffer)
 {
     buf += buffer;
@@ -179,10 +205,35 @@
     else if (line.startsWith("P ") || line.startsWith("U "))
         color = remoteChangeColor;
 
-    append(color.isValid()
-           ? QString("<font color=\"%1\"><b>%2</b></font>").arg(color.name())
-                                                           .arg(escapedLine)
-           : escapedLine);
+
+
+    QString final_line;
+
+    if (color.isValid())
+    {
+        final_line += QString("<font color=\"%1\"><b>").arg(color.name());
+    }
+
+    final_line += escapedLine.mid(0,2);
+    
+    if (color.isValid() || final_line.startsWith("? "))
+    {
+        final_line += QString("<u>");
+    }
+
+    final_line += escapedLine.mid(2);
+
+    if (color.isValid() || final_line.startsWith("? "))
+    {
+        final_line += QString("</u>");
+    }
+
+    if (color.isValid())
+    {
+        final_line += QString("</b></font>");
+    }
+
+    append(final_line);
 }
 
 
Index: cervisia/updateview_items.cpp
===================================================================
--- cervisia/updateview_items.cpp (revision 533149)
+++ cervisia/updateview_items.cpp (working copy)
@@ -390,7 +390,34 @@
     visitor.postVisit(this);
 }
 
+/**
+ *  Returns the child (dir or file) item with the specified path, or
+ *  NULL if no such item exists.
+ */
+UpdateItem * UpdateDirItem::findItemByFilePath(QString path) const
+{
+    int sep = path.find(QDir::separator());
 
+    // Eliminate trailing '/'
+    if (sep == (int)path.length()-1)
+    {
+        path = path.left(path.length()-1);
+        sep = -1;
+    }
+    
+    if (sep == -1)
+    {
+        return findItem(path);
+    } else
+    {
+        UpdateItem * nextItem = findItem(path.mid(0, sep));
+
+        return nextItem ? nextItem->findItemByFilePath(path.mid(sep+1)) :
+                          NULL;
+    }
+}
+
+
 void UpdateDirItem::setOpen(bool open)
 {
     if ( open )

_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Muschick Christian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi!


Please ignore my previous patch and my ramblings about "mouse hover
signals". I'm just getting to know QT (again)...

The way it works now is this:
If the mouse enters the log window, the cursor changes to a pointing
hand indicating that the filenames can be (double)clicked, furthermore
"jump to file" now is an entry in the context menu.

I would have liked to implement underline on mouse hover, but I have a
problem handling mouse move events properly with the QTextEdit widget
(yes I set mouse tracking to on). There is a small boundary around the
text window itself where it works, but as soon as the mouse enters the
text area events stop being generated. I'm at a loss on what to do about
this behaviour. As a workaround, said "pointing hand" cursor is set as
soon as the mouse enters the log window.

greetings
christian

Index: cervisia/protocolview.h
===================================================================
--- cervisia/protocolview.h (revision 533594)
+++ cervisia/protocolview.h (working copy)
@@ -43,6 +43,7 @@
 
 protected:
     virtual QPopupMenu* createPopupMenu(const QPoint &pos);
+    virtual bool event(QEvent * e);
 
 k_dcop:
     void slotReceivedOutput(QString buffer);
@@ -51,13 +52,17 @@
 signals:
     void receivedLine(QString line);
     void jobFinished(bool normalExit, int exitStatus);
+    void jumpToFile(QString filepath);
 
 private slots:
     void cancelJob();
+    void jumpToFile(int para, int pos);
+    void popupJumpToFile();
 
 private:
     void processOutput();
     void appendLine(const QString &line);
+    QString parseFileName(const QString & line) const;
 
     QString buf;
 
@@ -65,6 +70,9 @@
     QColor localChangeColor;
     QColor remoteChangeColor;
 
+    QString popupFile; ///< Used to remember the file name the popup
+                       ///menu was invoked on.
+
     CvsJob_stub* job;
 
     bool   m_isUpdateJob;
Index: cervisia/updateview.h
===================================================================
--- cervisia/updateview.h (revision 533594)
+++ cervisia/updateview.h (working copy)
@@ -78,7 +78,8 @@
     void foldTree();
     void finishJob(bool normalExit, int exitStatus);
     void processUpdateLine(QString line);
-
+    void jumpToFile(QString filepath);
+    
 private slots:
     void itemExecuted(QListViewItem *item);
     
Index: cervisia/updateview_items.h
===================================================================
--- cervisia/updateview_items.h (revision 533594)
+++ cervisia/updateview_items.h (working copy)
@@ -59,6 +59,8 @@
 
     virtual void accept(Visitor&) = 0;
 
+    virtual UpdateItem * findItemByFilePath(QString /* path */) const { return NULL; }
+    
 protected:
 
     UpdateView* updateView() const { return static_cast<UpdateView*>(listView()); }
@@ -92,6 +94,8 @@
 
     virtual void accept(Visitor&);
 
+    virtual UpdateItem * findItemByFilePath(QString path) const;
+    
     enum { RTTI = 10000 };
 
 private:
Index: cervisia/updateview.cpp
===================================================================
--- cervisia/updateview.cpp (revision 533594)
+++ cervisia/updateview.cpp (working copy)
@@ -590,6 +590,24 @@
 }
 
 
+/**
+ *  Makes the entry with the specified path visible and marks it.
+ */
+void UpdateView::jumpToFile(QString filepath)
+{
+    UpdateItem* rootItem = static_cast<UpdateItem*>(firstChild());
+    if (!rootItem) return;
+    
+    UpdateItem* fileItem = rootItem->findItemByFilePath(filepath);
+    if (!fileItem) return;
+    
+    ensureItemVisible(fileItem);
+    clearSelection();
+    setSelected(fileItem, true);
+}
+
+
+
 void UpdateView::updateItem(const QString& filePath, EntryStatus status, bool isdir)
 {
     if (isdir && filePath == QChar('.'))
Index: cervisia/cervisiapart.cpp
===================================================================
--- cervisia/cervisiapart.cpp (revision 533594)
+++ cervisia/cervisiapart.cpp (working copy)
@@ -145,6 +145,8 @@
 
         protocol = new ProtocolView(appId, splitter);
         protocol->setFocusPolicy( QWidget::StrongFocus );
+        connect( protocol, SIGNAL(jumpToFile(QString)),
+                 update, SLOT(jumpToFile(QString)) );
 
         setWidget(splitter);
     }
Index: cervisia/protocolview.cpp
===================================================================
--- cervisia/protocolview.cpp (revision 533594)
+++ cervisia/protocolview.cpp (working copy)
@@ -23,6 +23,8 @@
 
 #include <qdir.h>
 #include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qapplication.h>
 #include <dcopref.h>
 #include <kconfig.h>
 #include <klocale.h>
@@ -64,6 +66,9 @@
                       "slotReceivedOutput(QString)", true);
     connectDCOPSignal(job->app(), job->obj(), "receivedStderr(QString)",
                       "slotReceivedOutput(QString)", true);
+
+    connect( this, SIGNAL(doubleClicked(int, int)),
+             this, SLOT(jumpToFile(int, int)) );
 }
 
 
@@ -99,17 +104,66 @@
 
     if( length() == 0 )
         menu->setItemEnabled(id, false);
+    
+    popupFile = parseFileName(text(paragraphAt(pos)));
+    id = menu->insertItem(QString(i18n("Go to file")) + " " + (popupFile.isEmpty() ? "..." : popupFile),
+                          this, SLOT( popupJumpToFile() ), 0, -1, 0);
 
+    if (popupFile.isEmpty())
+        menu->setItemEnabled(id, false);
+
+    menu->insertSeparator(1);
+    
     return menu;
 }
 
 
+/**
+ *  Since QTextEdit::setCursor doesn't seem to work properly, set a
+ *  "pointing hand cursor" on mouse enter event.
+ */
+bool ProtocolView::event(QEvent * e)
+{
+    switch(e->type())
+    {
+    case QEvent::Enter:
+        QApplication::setOverrideCursor(Qt::PointingHandCursor);
+        break;
+    case QEvent::Leave:
+        QApplication::restoreOverrideCursor();
+        break;
+    default:
+        break;
+    }
+
+    return QTextEdit::event(e);
+}
+
+
 void ProtocolView::cancelJob()
 {
     job->cancel();
 }
 
 
+/**
+ *  If a status line is clicked and it represents a file, we
+ *  want to jump to it in the tree view.
+ */
+void ProtocolView::jumpToFile(int para, int )
+{
+    QString file = parseFileName(text(para));
+
+    if (!file.isEmpty()) emit jumpToFile(file);
+}
+
+
+void ProtocolView::popupJumpToFile()
+{
+    emit jumpToFile(popupFile);
+}
+
+
 void ProtocolView::slotReceivedOutput(QString buffer)
 {
     buf += buffer;
@@ -186,6 +240,26 @@
 }
 
 
+/**
+ *  Parses the file name from a cvs status output line. Returns an
+ *  empty string if the status line doesn't represent a filename.
+ */
+QString ProtocolView::parseFileName(const QString & line) const
+{
+    if (line.length() <=2 || line[1] != ' ') return "";
+
+    if (!line.startsWith("C") &&
+        !line.startsWith("A") &&
+        !line.startsWith("R") &&
+        !line.startsWith("M") &&
+        !line.startsWith("U") &&
+        !line.startsWith("P") &&
+        !line.startsWith("?")) return "";
+
+    return line.mid(2);
+}
+
+
 #include "protocolview.moc"
 
 
Index: cervisia/updateview_items.cpp
===================================================================
--- cervisia/updateview_items.cpp (revision 533594)
+++ cervisia/updateview_items.cpp (working copy)
@@ -390,7 +390,34 @@
     visitor.postVisit(this);
 }
 
+/**
+ *  Returns the child (dir or file) item with the specified path, or
+ *  NULL if no such item exists.
+ */
+UpdateItem * UpdateDirItem::findItemByFilePath(QString path) const
+{
+    int sep = path.find(QDir::separator());
 
+    // Eliminate trailing '/'
+    if (sep == (int)path.length()-1)
+    {
+        path = path.left(path.length()-1);
+        sep = -1;
+    }
+    
+    if (sep == -1)
+    {
+        return findItem(path);
+    } else
+    {
+        UpdateItem * nextItem = findItem(path.mid(0, sep));
+
+        return nextItem ? nextItem->findItemByFilePath(path.mid(sep+1)) :
+                          NULL;
+    }
+}
+
+
 void UpdateDirItem::setOpen(bool open)
 {
     if ( open )

_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Bugzilla from christian.loose@hamburg.de :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tuesday 25 April 2006 12:34, Muschick Christian wrote:

> Hi!
>
>
> Please ignore my previous patch and my ramblings about "mouse hover
> signals". I'm just getting to know QT (again)...
>
> The way it works now is this:
> If the mouse enters the log window, the cursor changes to a pointing
> hand indicating that the filenames can be (double)clicked, furthermore
> "jump to file" now is an entry in the context menu.
>
> I would have liked to implement underline on mouse hover, but I have a
> problem handling mouse move events properly with the QTextEdit widget
> (yes I set mouse tracking to on). There is a small boundary around the
> text window itself where it works, but as soon as the mouse enters the
> text area events stop being generated. I'm at a loss on what to do about
> this behaviour. As a workaround, said "pointing hand" cursor is set as
> soon as the mouse enters the log window.
>

First of all thanks for the patch!!

I could only take a short look at it since I'm very busy atm. It looks good
but I'm wondering why <a></a> tags don't work. Did you try to add those tags
in ProtocolView::appendLine()? That method already adds HTML tags to the
output, so IMHO link tags should work too.

I will take a better look at the patch really soon.

Bye, Christian
_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Muschick Christian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Hi!

> First of all thanks for the patch!!

You're welcome :-)

> I could only take a short look at it since I'm very busy atm. It looks good
> but I'm wondering why <a></a> tags don't work. Did you try to add those tags
> in ProtocolView::appendLine()? That method already adds HTML tags to the
> output, so IMHO link tags should work too.

Yes, this is exactly what I thought & tried. As far as I can see,
<a></a> tags are ignored, and <a href=\"abc\">test</a> even gives the
error message
"QTextEdit::optimParseTags: mismatching right-tag for '<a href="abc">'",
although this functionality is advertised in the docs.

>
> I will take a better look at the patch really soon.

I'm happy to hear that

greetings
cm
_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by André Wöbbeking-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

On Wednesday 26 April 2006 22:16, Muschick Christian wrote:
>
> Yes, this is exactly what I thought & tried. As far as I can see,
> <a></a> tags are ignored, and <a href=\"abc\">test</a> even gives the
> error message
> "QTextEdit::optimParseTags: mismatching right-tag for '<a
> href="abc">'", although this functionality is advertised in the docs.

We use setTextFormat(Qt::LogText) so <a> can't work. Try it with
Qt::RichText.


Cheers,
André
_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Muschick Christian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



> We use setTextFormat(Qt::LogText) so <a> can't work. Try it with
> Qt::RichText.

Thanks for the hint. <a> text is only underlined, however (no mouse
cursor change on hover), so it's of no use here...

I solved the problem with Mouse move events by installing an event
filter for the QScrollView viewport, so in this (probably last) revision
the mouse cursor changes to a pointing hand only when above a filename.
Underline on mouse hover would incorporate deleting and replacing
paragraphs, and I couldn't quickly find out how to do this nicely...

greetings
cm

Index: cervisia/protocolview.h
===================================================================
--- cervisia/protocolview.h (revision 534529)
+++ cervisia/protocolview.h (working copy)
@@ -43,6 +43,7 @@
 
 protected:
     virtual QPopupMenu* createPopupMenu(const QPoint &pos);
+    virtual bool eventFilter(QObject * watched, QEvent * e);
 
 k_dcop:
     void slotReceivedOutput(QString buffer);
@@ -51,20 +52,29 @@
 signals:
     void receivedLine(QString line);
     void jobFinished(bool normalExit, int exitStatus);
+    void jumpToFile(QString filepath);
 
 private slots:
     void cancelJob();
+    void jumpToFile(int para, int pos);
+    void popupJumpToFile();
 
 private:
     void processOutput();
     void appendLine(const QString &line);
-
+    QString parseFileName(const QString & line) const;
+    void handleMouseMove(QMouseEvent * e);
+    
+    
     QString buf;
 
     QColor conflictColor;
     QColor localChangeColor;
     QColor remoteChangeColor;
 
+    QString popupFile; ///< Used to remember the file name the popup
+                       ///menu was invoked on.
+
     CvsJob_stub* job;
 
     bool   m_isUpdateJob;
Index: cervisia/updateview.h
===================================================================
--- cervisia/updateview.h (revision 534529)
+++ cervisia/updateview.h (working copy)
@@ -78,7 +78,8 @@
     void foldTree();
     void finishJob(bool normalExit, int exitStatus);
     void processUpdateLine(QString line);
-
+    void jumpToFile(QString filepath);
+    
 private slots:
     void itemExecuted(QListViewItem *item);
     
Index: cervisia/updateview_items.h
===================================================================
--- cervisia/updateview_items.h (revision 534529)
+++ cervisia/updateview_items.h (working copy)
@@ -59,6 +59,8 @@
 
     virtual void accept(Visitor&) = 0;
 
+    virtual UpdateItem * findItemByFilePath(QString /* path */) const { return NULL; }
+    
 protected:
 
     UpdateView* updateView() const { return static_cast<UpdateView*>(listView()); }
@@ -92,6 +94,8 @@
 
     virtual void accept(Visitor&);
 
+    virtual UpdateItem * findItemByFilePath(QString path) const;
+    
     enum { RTTI = 10000 };
 
 private:
Index: cervisia/updateview.cpp
===================================================================
--- cervisia/updateview.cpp (revision 534529)
+++ cervisia/updateview.cpp (working copy)
@@ -590,6 +590,24 @@
 }
 
 
+/**
+ *  Makes the entry with the specified path visible and marks it.
+ */
+void UpdateView::jumpToFile(QString filepath)
+{
+    UpdateItem* rootItem = static_cast<UpdateItem*>(firstChild());
+    if (!rootItem) return;
+    
+    UpdateItem* fileItem = rootItem->findItemByFilePath(filepath);
+    if (!fileItem) return;
+    
+    ensureItemVisible(fileItem);
+    clearSelection();
+    setSelected(fileItem, true);
+}
+
+
+
 void UpdateView::updateItem(const QString& filePath, EntryStatus status, bool isdir)
 {
     if (isdir && filePath == QChar('.'))
Index: cervisia/cervisiapart.cpp
===================================================================
--- cervisia/cervisiapart.cpp (revision 534529)
+++ cervisia/cervisiapart.cpp (working copy)
@@ -145,6 +145,8 @@
 
         protocol = new ProtocolView(appId, splitter);
         protocol->setFocusPolicy( QWidget::StrongFocus );
+        connect( protocol, SIGNAL(jumpToFile(QString)),
+                 update, SLOT(jumpToFile(QString)) );
 
         setWidget(splitter);
     }
Index: cervisia/protocolview.cpp
===================================================================
--- cervisia/protocolview.cpp (revision 534529)
+++ cervisia/protocolview.cpp (working copy)
@@ -23,6 +23,8 @@
 
 #include <qdir.h>
 #include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qapplication.h>
 #include <dcopref.h>
 #include <kconfig.h>
 #include <klocale.h>
@@ -46,6 +48,9 @@
     config->setGroup("LookAndFeel");
     setFont(config->readFontEntry("ProtocolFont"));
 
+    setMouseTracking(true);
+    viewport()->installEventFilter(this);
+    
     config->setGroup("Colors");
     QColor defaultColor = QColor(255, 130, 130);
     conflictColor=config->readColorEntry("Conflict",&defaultColor);
@@ -64,6 +69,9 @@
                       "slotReceivedOutput(QString)", true);
     connectDCOPSignal(job->app(), job->obj(), "receivedStderr(QString)",
                       "slotReceivedOutput(QString)", true);
+
+    connect( this, SIGNAL(doubleClicked(int, int)),
+             this, SLOT(jumpToFile(int, int)) );
 }
 
 
@@ -99,17 +107,55 @@
 
     if( length() == 0 )
         menu->setItemEnabled(id, false);
+    
+    popupFile = parseFileName(text(paragraphAt(pos)));
+    id = menu->insertItem(QString(i18n("Go to file %1")).arg(popupFile.isEmpty() ? "" : popupFile),
+                          this, SLOT( popupJumpToFile() ), 0, -1, 0);
 
+    if (popupFile.isEmpty())
+        menu->setItemEnabled(id, false);
+
+    menu->insertSeparator(1);
+    
     return menu;
 }
 
 
+bool ProtocolView::eventFilter(QObject * watched, QEvent * e)
+{
+    if (watched == viewport() && e->type() == QEvent::MouseMove)
+    {
+        handleMouseMove(static_cast<QMouseEvent*>(e));
+    }
+    
+    return QTextEdit::eventFilter(watched, e);
+}
+
+
 void ProtocolView::cancelJob()
 {
     job->cancel();
 }
 
 
+/**
+ *  If a status line is clicked and it represents a file, we
+ *  want to jump to it in the tree view.
+ */
+void ProtocolView::jumpToFile(int para, int )
+{
+    QString file = parseFileName(text(para));
+
+    if (!file.isEmpty()) emit jumpToFile(file);
+}
+
+
+void ProtocolView::popupJumpToFile()
+{
+    emit jumpToFile(popupFile);
+}
+
+
 void ProtocolView::slotReceivedOutput(QString buffer)
 {
     buf += buffer;
@@ -186,6 +232,43 @@
 }
 
 
+/**
+ *  Parses the file name from a cvs status output line. Returns an
+ *  empty string if the status line doesn't represent a filename.
+ */
+QString ProtocolView::parseFileName(const QString & line) const
+{
+    if (line.length() <=2 || line[1] != ' ') return "";
+
+    if (!line.startsWith("C") &&
+        !line.startsWith("A") &&
+        !line.startsWith("R") &&
+        !line.startsWith("M") &&
+        !line.startsWith("U") &&
+        !line.startsWith("P") &&
+        !line.startsWith("?")) return "";
+
+    return line.mid(2);
+}
+
+/**
+ *  Set a pointing cursor when the mouse is moved over a filename
+ */
+void ProtocolView::handleMouseMove(QMouseEvent * e)
+{
+    int para;
+    int charPos = charAt(viewportToContents(e->pos()), ¶);
+
+    QString line = text(para);
+    if (parseFileName(line).isEmpty() || charPos == (int)line.length())
+    {
+        viewport()->setCursor(Qt::ArrowCursor);
+    } else
+    {
+        viewport()->setCursor(Qt::PointingHandCursor);
+    }
+}
+
 #include "protocolview.moc"
 
 
Index: cervisia/updateview_items.cpp
===================================================================
--- cervisia/updateview_items.cpp (revision 534529)
+++ cervisia/updateview_items.cpp (working copy)
@@ -390,7 +390,34 @@
     visitor.postVisit(this);
 }
 
+/**
+ *  Returns the child (dir or file) item with the specified path, or
+ *  NULL if no such item exists.
+ */
+UpdateItem * UpdateDirItem::findItemByFilePath(QString path) const
+{
+    int sep = path.find(QDir::separator());
 
+    // Eliminate trailing '/'
+    if (sep == (int)path.length()-1)
+    {
+        path = path.left(path.length()-1);
+        sep = -1;
+    }
+    
+    if (sep == -1)
+    {
+        return findItem(path);
+    } else
+    {
+        UpdateItem * nextItem = findItem(path.mid(0, sep));
+
+        return nextItem ? nextItem->findItemByFilePath(path.mid(sep+1)) :
+                          NULL;
+    }
+}
+
+
 void UpdateDirItem::setOpen(bool open)
 {
     if ( open )

_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Bugzilla from christian.loose@hamburg.de :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thursday 27 April 2006 13:46, Muschick Christian wrote:

> > We use setTextFormat(Qt::LogText) so <a> can't work. Try it with
> > Qt::RichText.
>
> Thanks for the hint. <a> text is only underlined, however (no mouse
> cursor change on hover), so it's of no use here...
>
> I solved the problem with Mouse move events by installing an event
> filter for the QScrollView viewport, so in this (probably last) revision
> the mouse cursor changes to a pointing hand only when above a filename.
> Underline on mouse hover would incorporate deleting and replacing
> paragraphs, and I couldn't quickly find out how to do this nicely...
>

Looks and works pretty good.

But I just now realized that you did the patch against KDE 3.5. This release
is in feature freeze, so we will have a hard time to get this in.

The main development is happening in
branches/cervisia/subversion_support/kdesdk/cervisia at the moment. It would
be great if you could port your patch to that branch. It should be straight
forward since the branch is based on KDE 3.5. The main difference will
probably be your parseFileName() method. This has to move to the
cvs_update_parser.cpp and svn_update_parser.cpp files.

Also please support KDE's single click setting (see
KGlobalSettings::singleClick()).

André: Could you please take a look at the updateview and updateview_items
changes? You know that code much better than I do. Thanks in advance!

Bye, Christian
_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Muschick Christian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Hi!

> But I just now realized that you did the patch against KDE 3.5. This release
> is in feature freeze, so we will have a hard time to get this in.

Well I almost thought so...

> The main development is happening in
> branches/cervisia/subversion_support/kdesdk/cervisia at the moment. It would
> be great if you could port your patch to that branch. It should be straight
> forward since the branch is based on KDE 3.5. The main difference will
> probably be your parseFileName() method. This has to move to the
> cvs_update_parser.cpp and svn_update_parser.cpp files.
>

Here you go. I was a bit invasive with the parse functions to avoid
duplicated code, I hope I broke nothing...

> Also please support KDE's single click setting (see
> KGlobalSettings::singleClick()).

Ok. I hope it's ok how I did it and this cannot change at runtime?


regards
cm


Index: protocolview.h
===================================================================
--- protocolview.h (revision 535315)
+++ protocolview.h (working copy)
@@ -47,10 +47,12 @@
 
 protected:
     virtual QPopupMenu* createPopupMenu(const QPoint &pos);
-
+    virtual bool eventFilter(QObject * watched, QEvent * e);
+    
 signals:                                            //TODO: remove later
     void receivedLine(QString line);
     void jobFinished(bool normalExit, int exitStatus);
+    void jumpToFile(const QString & filepath);
 
 private slots:
     void receivedOutput(const QString& buffer);     //TODO: remove later
@@ -60,14 +62,25 @@
     void jobExited(bool normalExit, int exitStatus);
     void cancelJob();
 
+    void clicked(int para, int charPos);
+    void jumpToFile();
+
 private:
+
+    void setTargetFile(const QPoint & pos);
+    void setTargetFile(int para, int charPos);
+
     QColor conflictColor;
     QColor localChangeColor;
     QColor remoteChangeColor;
 
+    QString targetFile; ///< Used to remember the file jumpToFile()
+                        ///will jump to.
+    
     bool   m_isUpdateJob;
 
     Cervisia::CommandBase* m_currentCmd;
+    Cervisia::PluginBase*  m_currentPlugin;
 };
 
 #endif
Index: updateview.h
===================================================================
--- updateview.h (revision 535315)
+++ updateview.h (working copy)
@@ -79,6 +79,7 @@
     void commandPrepared(Cervisia::CommandBase* cmd);
     void finishJob(bool normalExit, int exitStatus);
     void updateItem(const QString &filename, Cervisia::EntryStatus status, bool isdir);
+    void jumpToFile(const QString & filepath);
 
 private slots:
     void itemExecuted(QListViewItem *item);
Index: cervisiapart.cpp
===================================================================
--- cervisiapart.cpp (revision 535315)
+++ cervisiapart.cpp (working copy)
@@ -146,6 +146,10 @@
         protocol = new ProtocolView(splitter);
         protocol->setFocusPolicy( QWidget::StrongFocus );
 
+        connect( protocol, SIGNAL(jumpToFile(const QString&)),
+                 update, SLOT(jumpToFile(const QString&)) );
+        
+        
         setWidget(splitter);
     }
     else
Index: protocolview.cpp
===================================================================
--- protocolview.cpp (revision 535315)
+++ protocolview.cpp (working copy)
@@ -23,6 +23,8 @@
 
 #include <qdir.h>
 #include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qapplication.h>
 #include <dcopref.h>
 #include <klocale.h>
 #include <kmessagebox.h>
@@ -32,8 +34,8 @@
 #include "cvsjob_stub.h"
 #include "pluginbase.h"
 #include "pluginmanager.h"
+#include "update_parser.h"
 
-
 using namespace Cervisia;
 
 
@@ -52,6 +54,19 @@
     conflictColor = CervisiaSettings::conflictColor();
     localChangeColor = CervisiaSettings::localChangeColor();
     remoteChangeColor = CervisiaSettings::remoteChangeColor();
+
+    setMouseTracking(true);
+    viewport()->installEventFilter(this);
+    
+    if (KGlobalSettings::singleClick())
+    {
+        connect( this, SIGNAL(clicked(int, int)),
+                 this, SLOT(clicked(int, int)) );
+    } else
+    {
+        connect( this, SIGNAL(doubleClicked(int, int)),
+                 this, SLOT(clicked(int, int)) );
+    }
 }
 
 
@@ -70,6 +85,8 @@
 
     connect(plugin, SIGNAL(commandPrepared(Cervisia::CommandBase*)),
             this, SLOT(commandPrepared(Cervisia::CommandBase*)));
+
+    m_currentPlugin = plugin;
 }
 
 
@@ -100,9 +117,30 @@
     if( length() == 0 )
         menu->setItemEnabled(id, false);
 
+
+    // Add "Go to file" entry
+    setTargetFile(pos);
+    id = menu->insertItem(QString(i18n("Go to file %1")).arg(targetFile.isEmpty() ? "" : targetFile),
+                          this, SLOT( jumpToFile() ), 0, -1, 0);
+
+    if (targetFile.isEmpty())
+        menu->setItemEnabled(id, false);
+
+    menu->insertSeparator(1);
+    
     return menu;
 }
 
+bool ProtocolView::eventFilter(QObject * watched, QEvent * e)
+{
+    if (watched == viewport() && e->type() == QEvent::MouseMove)
+    {
+        QMouseEvent * me = static_cast<QMouseEvent*>(e);
+        setTargetFile(viewportToContents(me->pos()));
+    }
+    
+    return QTextEdit::eventFilter(watched, e);
+}
 
 void ProtocolView::cancelJob()
 {
@@ -212,6 +250,59 @@
 }
 
 
+void ProtocolView::clicked(int para, int charPos)
+{
+    // Set this again in case no mouse move has been generated yet
+    // (possible if popup was open)
+    setTargetFile(para, charPos);
+    jumpToFile();
+}
+
+void ProtocolView::jumpToFile()
+{
+    if (!targetFile.isEmpty())
+    {
+        emit jumpToFile(targetFile);
+    }
+}
+
+/**
+ *  Parse the line pointed to by pos and set targetFile if it contains
+ *  a valid file.
+ */
+void ProtocolView::setTargetFile(const QPoint & pos)
+{
+    int para;
+    int charPos = charAt(pos, ¶);
+    setTargetFile(para, charPos);
+}
+
+/**
+ *  Parse specified line set targetFile if it contains a valid
+ *  file. Also change the mouse cursor accordingly.
+ */
+void ProtocolView::setTargetFile(int para, int charPos)
+{
+    QString line = text(para);
+    
+    if (m_currentPlugin && m_currentPlugin->updateParser() &&
+        charPos != (int)line.length())
+    {
+        EntryStatus dummy;
+        m_currentPlugin->updateParser()->parseLine(line, targetFile, dummy);
+    } else targetFile = "";
+
+    if (targetFile.isEmpty())
+    {
+        viewport()->setCursor(Qt::ArrowCursor);
+    } else
+    {
+        viewport()->setCursor(Qt::PointingHandCursor);
+    }
+}
+
+
+
 #include "protocolview.moc"
 
 
Index: update_parser.h
===================================================================
--- update_parser.h (revision 535315)
+++ update_parser.h (working copy)
@@ -38,6 +38,8 @@
     bool isSimulation() const;
     void setSimulation(bool simulation);
 
+    virtual void parseLine(const QString & line, QString & filename, EntryStatus & status) const = 0;
+    
 signals:
     void updateItemStatus(const QString& filePath, Cervisia::EntryStatus status, bool isdir);
 
Index: updateview_items.cpp
===================================================================
--- updateview_items.cpp (revision 535315)
+++ updateview_items.cpp (working copy)
@@ -338,7 +338,34 @@
     visitor.postVisit(this);
 }
 
+/**
+ *  Returns the child (dir or file) item with the specified path, or
+ *  NULL if no such item exists.
+ */
+UpdateItem * UpdateDirItem::findItemByFilePath(QString path) const
+{
+    int sep = path.find(QDir::separator());
+
+    // Eliminate trailing '/'
+    if (sep == (int)path.length()-1)
+    {
+        path = path.left(path.length()-1);
+        sep = -1;
+    }
+    
+    if (sep == -1)
+    {
+        return findItem(path);
+    } else
+    {
+        UpdateItem * nextItem = findItem(path.mid(0, sep));
 
+        return nextItem ? nextItem->findItemByFilePath(path.mid(sep+1)) :
+                          NULL;
+    }
+}
+
+
 void UpdateDirItem::setOpen(bool open)
 {
     if ( open )
Index: updateview_items.h
===================================================================
--- updateview_items.h (revision 535315)
+++ updateview_items.h (working copy)
@@ -57,7 +57,7 @@
     QString filePath() const;
 
     virtual void accept(Visitor&) = 0;
-
+    virtual UpdateItem * findItemByFilePath(QString /* path */) const { return NULL; }
 protected:
 
     UpdateView* updateView() const { return static_cast<UpdateView*>(listView()); }
@@ -91,7 +91,8 @@
     void maybeScanDir(bool recursive);
 
     virtual void accept(Visitor&);
-
+    virtual UpdateItem * findItemByFilePath(QString path) const;
+    
     enum { RTTI = 10000 };
 
 private slots:
Index: plugins/svnplugin/svn_update_parser.cpp
===================================================================
--- plugins/svnplugin/svn_update_parser.cpp (revision 535315)
+++ plugins/svnplugin/svn_update_parser.cpp (working copy)
@@ -34,29 +34,48 @@
 }
 
 
-void SvnUpdateParser::parseLine(const QString& line)
+/**
+ *  Parses the update output line and returns the filename and
+ *  status. If the line cannot be parsed, filename will be set to the
+ *  empty string.
+ */
+void SvnUpdateParser::parseLine(const QString & line, QString & filename, EntryStatus & status) const
 {
     if( isSimulation() )
-        parseStatusLine(line);
+        parseStatusLine(line, filename, status);
     else
-        parseUpdateLine(line);
+        parseUpdateLine(line, filename, status);
 }
 
+/**
+ *  Parses the line and emits an according updateItemStatus signal
+ *  with file name and status.
+ */
+void SvnUpdateParser::parseLine(const QString& line)
+{
+    QString filename;
+    EntryStatus status;
 
-void SvnUpdateParser::parseStatusLine(const QString& line)
+    parseLine(line, filename, status);
+
+    if (!filename.isEmpty())
+    {
+        emit updateItemStatus(filename, status, false);
+    }
+}
+
+
+void SvnUpdateParser::parseStatusLine(const QString& line, QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    status = Cervisia::Unknown;
+    filename = "";
+    
     QRegExp rx(".*Revision.*\\d+");
     rx.setCaseSensitive(false);
     if( line.length() > 2 && rx.search(line) < 0 )
     {
-        QString fileName = line.right(line.length() - 20);
-
-        kdDebug(8050) << k_funcinfo << "fileName = " << fileName
-                      << ", length = " << line.length() << endl;
-
-        EntryStatus status = Cervisia::Unknown;
         switch( line[0].latin1() )
         {
             case 'C':
@@ -76,30 +95,29 @@
                 break;
             default:
                 if( line[7].latin1() == '*' )
+                {
                     status = Cervisia::NeedsUpdate;
-                else
-                    return;
+                } else return;
         }
-
-        emit updateItemStatus(fileName, status, false);
-    }
+        
+        filename = line.right(line.length() - 20);        
+        kdDebug(8050) << k_funcinfo << "fileName = " << filename
+                      << ", length = " << line.length() << endl;
+    }
 }
 
 
-void SvnUpdateParser::parseUpdateLine(const QString& line)
+void SvnUpdateParser::parseUpdateLine(const QString& line, QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    status = Cervisia::Unknown;
+    filename = "";
+    
     QRegExp rx(".*Revision.*\\d+");
     rx.setCaseSensitive(false);
     if( line.length() > 2 && rx.search(line) < 0 )
     {
-        QString fileName = line.right(line.length() - 5);
-
-        kdDebug(8050) << k_funcinfo << "fileName = " << fileName
-                      << ", length = " << line.length() << endl;
-
-        EntryStatus status = Cervisia::Unknown;
         switch( line[0].latin1() )
         {
             case 'C':
@@ -123,7 +141,9 @@
             default:
                 return;
         }
-
-        emit updateItemStatus(fileName, status, false);
-    }
+        
+        filename = line.right(line.length() - 5);
+        kdDebug(8050) << k_funcinfo << "fileName = " << filename
+                      << ", length = " << line.length() << endl;
+    }
 }
Index: plugins/svnplugin/svn_update_parser.h
===================================================================
--- plugins/svnplugin/svn_update_parser.h (revision 535315)
+++ plugins/svnplugin/svn_update_parser.h (working copy)
@@ -32,11 +32,13 @@
     SvnUpdateParser();
     ~SvnUpdateParser();
 
+    virtual void parseLine(const QString & line, QString & filename, EntryStatus & status) const;
+
 private:
     virtual void parseLine(const QString& line);
 
-    void parseStatusLine(const QString& line);
-    void parseUpdateLine(const QString& line);
+    void parseStatusLine(const QString& line, QString & filename, EntryStatus & status) const;
+    void parseUpdateLine(const QString& line, QString & filename, EntryStatus & status) const;
 };
 
 
Index: plugins/cvsplugin/cvs_update_parser.cpp
===================================================================
--- plugins/cvsplugin/cvs_update_parser.cpp (revision 535315)
+++ plugins/cvsplugin/cvs_update_parser.cpp (working copy)
@@ -38,13 +38,15 @@
  * is true, it is assumed that the output is from a command
  * 'cvs update -n', i.e. cvs actually changes no files.
  */
-void CvsUpdateParser::parseLine(const QString& line)
+void CvsUpdateParser::parseLine(const QString & line, QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    filename = "";
+    status = Cervisia::Unknown;
+    
     if( line.length() > 2 && line[1] == ' ' )
     {
-        EntryStatus status = Cervisia::Unknown;
         switch (line[0].latin1())
         {
         case 'C':
@@ -71,18 +73,39 @@
             return;
         }
 
-        emit updateItemStatus(line.mid(2).stripWhiteSpace(), status, false);
+        filename = line.mid(2).stripWhiteSpace();
     }
+}
 
-    const QString removedFileStart(QString::fromLatin1("cvs server: "));
-    const QString removedFileEnd(QString::fromLatin1(" is no longer in the repository"));
-    if (line.startsWith(removedFileStart) && line.endsWith(removedFileEnd))
+
+
+/**
+ *  Parses the line and emits an according updateItemStatus signal
+ *  with file name and status.
+ */
+void CvsUpdateParser::parseLine(const QString& line)
+{
+    EntryStatus status;
+    QString filename;
+
+    parseLine(line, filename, status);
+
+    if (!filename.isEmpty())
     {
-    }
-
+        emit updateItemStatus(filename, status, false);
+    } else
+    {
+        const QString removedFileStart(QString::fromLatin1("cvs server: "));
+        const QString removedFileEnd(QString::fromLatin1(" is no longer in the repository"));
+        if (line.startsWith(removedFileStart) && line.endsWith(removedFileEnd))
+        {
+        }
 #if 0
-    else if (str.left(21) == "cvs server: Updating " ||
-             str.left(21) == "cvs update: Updating ")
-        updateItem(str.right(str.length()-21), Unknown, true);
+        else if (str.left(21) == "cvs server: Updating " ||
+                 str.left(21) == "cvs update: Updating ")
+        {
+            updateItem(str.right(str.length()-21), Unknown, true);
+        }
 #endif
+    }
 }
Index: plugins/cvsplugin/cvs_update_parser.h
===================================================================
--- plugins/cvsplugin/cvs_update_parser.h (revision 535315)
+++ plugins/cvsplugin/cvs_update_parser.h (working copy)
@@ -32,6 +32,8 @@
     CvsUpdateParser();
     ~CvsUpdateParser();
 
+    virtual void parseLine(const QString & line, QString & filename, EntryStatus & status) const;
+    
 private:
     virtual void parseLine(const QString& line);
 };
Index: updateview.cpp
===================================================================
--- updateview.cpp (revision 535315)
+++ updateview.cpp (working copy)
@@ -570,6 +570,23 @@
 }
 
 
+/**
+ *  Makes the entry with the specified path visible and marks it.
+ */
+void UpdateView::jumpToFile(const QString & filepath)
+{
+    UpdateItem* rootItem = static_cast<UpdateItem*>(firstChild());
+    if (!rootItem) return;
+    
+    UpdateItem* fileItem = rootItem->findItemByFilePath(filepath);
+    if (!fileItem) return;
+    
+    ensureItemVisible(fileItem);
+    clearSelection();
+    setSelected(fileItem, true);
+}
+
+
 void UpdateView::itemExecuted(QListViewItem *item)
 {
     if (isFileItem(item))

_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Muschick Christian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi!

I just realized it isn't very smart to depend on isSimulation() when
parsing the svn output for this purpose. Sorry for this flood of
patches, I'll try to think first next time....


cm

Index: protocolview.h
===================================================================
--- protocolview.h (revision 535392)
+++ protocolview.h (working copy)
@@ -47,10 +47,12 @@
 
 protected:
     virtual QPopupMenu* createPopupMenu(const QPoint &pos);
-
+    virtual bool eventFilter(QObject * watched, QEvent * e);
+    
 signals:                                            //TODO: remove later
     void receivedLine(QString line);
     void jobFinished(bool normalExit, int exitStatus);
+    void jumpToFile(const QString & filepath);
 
 private slots:
     void receivedOutput(const QString& buffer);     //TODO: remove later
@@ -60,14 +62,25 @@
     void jobExited(bool normalExit, int exitStatus);
     void cancelJob();
 
+    void clicked(int para, int charPos);
+    void jumpToFile();
+
 private:
+
+    void setTargetFile(const QPoint & pos);
+    void setTargetFile(int para, int charPos);
+
     QColor conflictColor;
     QColor localChangeColor;
     QColor remoteChangeColor;
 
+    QString m_targetFile; ///< Used to remember the file jumpToFile()
+                          ///will jump to.
+    
     bool   m_isUpdateJob;
 
     Cervisia::CommandBase* m_currentCmd;
+    Cervisia::PluginBase*  m_currentPlugin;
 };
 
 #endif
Index: updateview.h
===================================================================
--- updateview.h (revision 535392)
+++ updateview.h (working copy)
@@ -79,6 +79,7 @@
     void commandPrepared(Cervisia::CommandBase* cmd);
     void finishJob(bool normalExit, int exitStatus);
     void updateItem(const QString &filename, Cervisia::EntryStatus status, bool isdir);
+    void jumpToFile(const QString & filepath);
 
 private slots:
     void itemExecuted(QListViewItem *item);
Index: cervisiapart.cpp
===================================================================
--- cervisiapart.cpp (revision 535392)
+++ cervisiapart.cpp (working copy)
@@ -146,6 +146,10 @@
         protocol = new ProtocolView(splitter);
         protocol->setFocusPolicy( QWidget::StrongFocus );
 
+        connect( protocol, SIGNAL(jumpToFile(const QString&)),
+                 update, SLOT(jumpToFile(const QString&)) );
+        
+        
         setWidget(splitter);
     }
     else
Index: protocolview.cpp
===================================================================
--- protocolview.cpp (revision 535392)
+++ protocolview.cpp (working copy)
@@ -23,6 +23,8 @@
 
 #include <qdir.h>
 #include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qapplication.h>
 #include <dcopref.h>
 #include <klocale.h>
 #include <kmessagebox.h>
@@ -32,8 +34,8 @@
 #include "cvsjob_stub.h"
 #include "pluginbase.h"
 #include "pluginmanager.h"
+#include "update_parser.h"
 
-
 using namespace Cervisia;
 
 
@@ -52,6 +54,19 @@
     conflictColor = CervisiaSettings::conflictColor();
     localChangeColor = CervisiaSettings::localChangeColor();
     remoteChangeColor = CervisiaSettings::remoteChangeColor();
+
+    setMouseTracking(true);
+    viewport()->installEventFilter(this);
+    
+    if (KGlobalSettings::singleClick())
+    {
+        connect( this, SIGNAL(clicked(int, int)),
+                 this, SLOT(clicked(int, int)) );
+    } else
+    {
+        connect( this, SIGNAL(doubleClicked(int, int)),
+                 this, SLOT(clicked(int, int)) );
+    }
 }
 
 
@@ -70,6 +85,8 @@
 
     connect(plugin, SIGNAL(commandPrepared(Cervisia::CommandBase*)),
             this, SLOT(commandPrepared(Cervisia::CommandBase*)));
+
+    m_currentPlugin = plugin;
 }
 
 
@@ -100,9 +117,30 @@
     if( length() == 0 )
         menu->setItemEnabled(id, false);
 
+
+    // Add "Go to file" entry
+    setTargetFile(pos);
+    id = menu->insertItem(QString(i18n("Go to file %1")).arg(m_targetFile.isEmpty() ? "" : m_targetFile),
+                          this, SLOT( jumpToFile() ), 0, -1, 0);
+
+    if (m_targetFile.isEmpty())
+        menu->setItemEnabled(id, false);
+
+    menu->insertSeparator(1);
+    
     return menu;
 }
 
+bool ProtocolView::eventFilter(QObject * watched, QEvent * e)
+{
+    if (watched == viewport() && e->type() == QEvent::MouseMove)
+    {
+        QMouseEvent * me = static_cast<QMouseEvent*>(e);
+        setTargetFile(viewportToContents(me->pos()));
+    }
+    
+    return QTextEdit::eventFilter(watched, e);
+}
 
 void ProtocolView::cancelJob()
 {
@@ -212,6 +250,59 @@
 }
 
 
+void ProtocolView::clicked(int para, int charPos)
+{
+    // Set this again in case no mouse move has been generated yet
+    // (possible if popup was open)
+    setTargetFile(para, charPos);
+    jumpToFile();
+}
+
+void ProtocolView::jumpToFile()
+{
+    if (!m_targetFile.isEmpty())
+    {
+        emit jumpToFile(m_targetFile);
+    }
+}
+
+/**
+ *  Parse the line pointed to by pos and set m_targetFile if it contains
+ *  a valid file.
+ */
+void ProtocolView::setTargetFile(const QPoint & pos)
+{
+    int para;
+    int charPos = charAt(pos, ¶);
+    setTargetFile(para, charPos);
+}
+
+/**
+ *  Parse specified line set m_targetFile if it contains a valid
+ *  file. Also change the mouse cursor accordingly.
+ */
+void ProtocolView::setTargetFile(int para, int charPos)
+{
+    QString line = text(para);
+    
+    if (m_currentPlugin && m_currentPlugin->updateParser() &&
+        charPos != (int)line.length())
+    {
+        EntryStatus dummy;
+        m_currentPlugin->updateParser()->parseLine(line, false, m_targetFile, dummy);
+    } else m_targetFile = "";
+
+    if (m_targetFile.isEmpty())
+    {
+        viewport()->setCursor(Qt::ArrowCursor);
+    } else
+    {
+        viewport()->setCursor(Qt::PointingHandCursor);
+    }
+}
+
+
+
 #include "protocolview.moc"
 
 
Index: update_parser.h
===================================================================
--- update_parser.h (revision 535392)
+++ update_parser.h (working copy)
@@ -38,6 +38,9 @@
     bool isSimulation() const;
     void setSimulation(bool simulation);
 
+    virtual void parseLine(const QString & line, bool respectIsSimulation,
+                           QString & filename, EntryStatus & status) const = 0;
+    
 signals:
     void updateItemStatus(const QString& filePath, Cervisia::EntryStatus status, bool isdir);
 
Index: updateview_items.cpp
===================================================================
--- updateview_items.cpp (revision 535392)
+++ updateview_items.cpp (working copy)
@@ -338,7 +338,34 @@
     visitor.postVisit(this);
 }
 
+/**
+ *  Returns the child (dir or file) item with the specified path, or
+ *  NULL if no such item exists.
+ */
+UpdateItem * UpdateDirItem::findItemByFilePath(QString path) const
+{
+    int sep = path.find(QDir::separator());
+
+    // Eliminate trailing '/'
+    if (sep == (int)path.length()-1)
+    {
+        path = path.left(path.length()-1);
+        sep = -1;
+    }
+    
+    if (sep == -1)
+    {
+        return findItem(path);
+    } else
+    {
+        UpdateItem * nextItem = findItem(path.mid(0, sep));
 
+        return nextItem ? nextItem->findItemByFilePath(path.mid(sep+1)) :
+                          NULL;
+    }
+}
+
+
 void UpdateDirItem::setOpen(bool open)
 {
     if ( open )
Index: updateview_items.h
===================================================================
--- updateview_items.h (revision 535392)
+++ updateview_items.h (working copy)
@@ -57,7 +57,7 @@
     QString filePath() const;
 
     virtual void accept(Visitor&) = 0;
-
+    virtual UpdateItem * findItemByFilePath(QString /* path */) const { return NULL; }
 protected:
 
     UpdateView* updateView() const { return static_cast<UpdateView*>(listView()); }
@@ -91,7 +91,8 @@
     void maybeScanDir(bool recursive);
 
     virtual void accept(Visitor&);
-
+    virtual UpdateItem * findItemByFilePath(QString path) const;
+    
     enum { RTTI = 10000 };
 
 private slots:
Index: plugins/svnplugin/svn_update_parser.cpp
===================================================================
--- plugins/svnplugin/svn_update_parser.cpp (revision 535392)
+++ plugins/svnplugin/svn_update_parser.cpp (working copy)
@@ -34,29 +34,59 @@
 }
 
 
+/**
+ *  Parses the update output line and returns the filename and
+ *  status. If the line cannot be parsed, filename will be set to the
+ *  empty string.
+ *
+ *  If respectIsSimulation is false, try to parse line regardless of
+ *  whether isSimulation() yields true.
+ */
+void SvnUpdateParser::parseLine(const QString & line, bool respectIsSimulation,
+                                QString & filename, EntryStatus & status) const
+{
+    if (respectIsSimulation)
+    {
+        if( isSimulation() )
+            parseStatusLine(line, filename, status);
+        else
+            parseUpdateLine(line, filename, status);
+    } else
+    {
+        parseStatusLine(line, filename, status);
+        if (filename.isEmpty()) parseUpdateLine(line, filename, status);
+    }
+}
+
+/**
+ *  Parses the line and emits an according updateItemStatus signal
+ *  with file name and status.
+ */
 void SvnUpdateParser::parseLine(const QString& line)
 {
-    if( isSimulation() )
-        parseStatusLine(line);
-    else
-        parseUpdateLine(line);
+    QString filename;
+    EntryStatus status;
+
+    parseLine(line, true, filename, status);
+
+    if (!filename.isEmpty())
+    {
+        emit updateItemStatus(filename, status, false);
+    }
 }
 
 
-void SvnUpdateParser::parseStatusLine(const QString& line)
+void SvnUpdateParser::parseStatusLine(const QString& line, QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    status = Cervisia::Unknown;
+    filename = "";
+    
     QRegExp rx(".*Revision.*\\d+");
     rx.setCaseSensitive(false);
     if( line.length() > 2 && rx.search(line) < 0 )
     {
-        QString fileName = line.right(line.length() - 20);
-
-        kdDebug(8050) << k_funcinfo << "fileName = " << fileName
-                      << ", length = " << line.length() << endl;
-
-        EntryStatus status = Cervisia::Unknown;
         switch( line[0].latin1() )
         {
             case 'C':
@@ -76,30 +106,29 @@
                 break;
             default:
                 if( line[7].latin1() == '*' )
+                {
                     status = Cervisia::NeedsUpdate;
-                else
-                    return;
+                } else return;
         }
-
-        emit updateItemStatus(fileName, status, false);
-    }
+        
+        filename = line.right(line.length() - 20);        
+        kdDebug(8050) << k_funcinfo << "fileName = " << filename
+                      << ", length = " << line.length() << endl;
+    }
 }
 
 
-void SvnUpdateParser::parseUpdateLine(const QString& line)
+void SvnUpdateParser::parseUpdateLine(const QString& line, QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    status = Cervisia::Unknown;
+    filename = "";
+    
     QRegExp rx(".*Revision.*\\d+");
     rx.setCaseSensitive(false);
     if( line.length() > 2 && rx.search(line) < 0 )
     {
-        QString fileName = line.right(line.length() - 5);
-
-        kdDebug(8050) << k_funcinfo << "fileName = " << fileName
-                      << ", length = " << line.length() << endl;
-
-        EntryStatus status = Cervisia::Unknown;
         switch( line[0].latin1() )
         {
             case 'C':
@@ -123,7 +152,9 @@
             default:
                 return;
         }
-
-        emit updateItemStatus(fileName, status, false);
-    }
+        
+        filename = line.right(line.length() - 5);
+        kdDebug(8050) << k_funcinfo << "fileName = " << filename
+                      << ", length = " << line.length() << endl;
+    }
 }
Index: plugins/svnplugin/svn_update_parser.h
===================================================================
--- plugins/svnplugin/svn_update_parser.h (revision 535392)
+++ plugins/svnplugin/svn_update_parser.h (working copy)
@@ -32,11 +32,14 @@
     SvnUpdateParser();
     ~SvnUpdateParser();
 
+    virtual void parseLine(const QString & line, bool respectIsSimulation,
+                           QString & filename, EntryStatus & status) const;
+
 private:
     virtual void parseLine(const QString& line);
 
-    void parseStatusLine(const QString& line);
-    void parseUpdateLine(const QString& line);
+    void parseStatusLine(const QString& line, QString & filename, EntryStatus & status) const;
+    void parseUpdateLine(const QString& line, QString & filename, EntryStatus & status) const;
 };
 
 
Index: plugins/cvsplugin/cvs_update_parser.cpp
===================================================================
--- plugins/cvsplugin/cvs_update_parser.cpp (revision 535392)
+++ plugins/cvsplugin/cvs_update_parser.cpp (working copy)
@@ -38,13 +38,16 @@
  * is true, it is assumed that the output is from a command
  * 'cvs update -n', i.e. cvs actually changes no files.
  */
-void CvsUpdateParser::parseLine(const QString& line)
+void CvsUpdateParser::parseLine(const QString & line, bool,
+                                QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    filename = "";
+    status = Cervisia::Unknown;
+    
     if( line.length() > 2 && line[1] == ' ' )
     {
-        EntryStatus status = Cervisia::Unknown;
         switch (line[0].latin1())
         {
         case 'C':
@@ -71,18 +74,39 @@
             return;
         }
 
-        emit updateItemStatus(line.mid(2).stripWhiteSpace(), status, false);
+        filename = line.mid(2).stripWhiteSpace();
     }
+}
 
-    const QString removedFileStart(QString::fromLatin1("cvs server: "));
-    const QString removedFileEnd(QString::fromLatin1(" is no longer in the repository"));
-    if (line.startsWith(removedFileStart) && line.endsWith(removedFileEnd))
+
+
+/**
+ *  Parses the line and emits an according updateItemStatus signal
+ *  with file name and status.
+ */
+void CvsUpdateParser::parseLine(const QString& line)
+{
+    EntryStatus status;
+    QString filename;
+
+    parseLine(line, true, filename, status);
+
+    if (!filename.isEmpty())
     {
-    }
-
+        emit updateItemStatus(filename, status, false);
+    } else
+    {
+        const QString removedFileStart(QString::fromLatin1("cvs server: "));
+        const QString removedFileEnd(QString::fromLatin1(" is no longer in the repository"));
+        if (line.startsWith(removedFileStart) && line.endsWith(removedFileEnd))
+        {
+        }
 #if 0
-    else if (str.left(21) == "cvs server: Updating " ||
-             str.left(21) == "cvs update: Updating ")
-        updateItem(str.right(str.length()-21), Unknown, true);
+        else if (str.left(21) == "cvs server: Updating " ||
+                 str.left(21) == "cvs update: Updating ")
+        {
+            updateItem(str.right(str.length()-21), Unknown, true);
+        }
 #endif
+    }
 }
Index: plugins/cvsplugin/cvs_update_parser.h
===================================================================
--- plugins/cvsplugin/cvs_update_parser.h (revision 535392)
+++ plugins/cvsplugin/cvs_update_parser.h (working copy)
@@ -32,6 +32,9 @@
     CvsUpdateParser();
     ~CvsUpdateParser();
 
+    virtual void parseLine(const QString & line, bool respectIsSimulation,
+                           QString & filename, EntryStatus & status) const;
+    
 private:
     virtual void parseLine(const QString& line);
 };
Index: updateview.cpp
===================================================================
--- updateview.cpp (revision 535392)
+++ updateview.cpp (working copy)
@@ -570,6 +570,23 @@
 }
 
 
+/**
+ *  Makes the entry with the specified path visible and marks it.
+ */
+void UpdateView::jumpToFile(const QString & filepath)
+{
+    UpdateItem* rootItem = static_cast<UpdateItem*>(firstChild());
+    if (!rootItem) return;
+    
+    UpdateItem* fileItem = rootItem->findItemByFilePath(filepath);
+    if (!fileItem) return;
+    
+    ensureItemVisible(fileItem);
+    clearSelection();
+    setSelected(fileItem, true);
+}
+
+
 void UpdateView::itemExecuted(QListViewItem *item)
 {
     if (isFileItem(item))

_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by André Wöbbeking-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Friday 28 April 2006 20:13, Christian Loose wrote:

> André: Could you please take a look at the updateview and
> updateview_items changes? You know that code much better than I do.
> Thanks in advance!

I had only a short look but you should

1) implement findItemByFilePath() as free function like
findOrCreateDirItem() and not as member.

2) pass QStrings by const&

BTW, after my last change only top level items are guaranteed to exist
all other items are created on demand (when the parent folder is
opened).


Cheers,
André
_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by Muschick Christian :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Hi!

> I had only a short look but you should
>
> 1) implement findItemByFilePath() as free function like
> findOrCreateDirItem() and not as member.

Not exactly to my taste, friend and static_casts, but here you go ;-)

>
> 2) pass QStrings by const&

Ok, changed the function so it doesn't need to change the input string...

>
> BTW, after my last change only top level items are guaranteed to exist
> all other items are created on demand (when the parent folder is
> opened).

What exactly does that mean for me? I now call maybeScanDir() while
traversing the nodes in findItemByPath(), is this ok?


As additional change in this patch, I modified
Protocolview::appendLine() to use the new parseLine function in order to
colourize the output lines (currently doesn't work because m_isUpdateJob
is always false).

regards
christian

Index: protocolview.h
===================================================================
--- protocolview.h (revision 538390)
+++ protocolview.h (working copy)
@@ -47,10 +47,12 @@
 
 protected:
     virtual QPopupMenu* createPopupMenu(const QPoint &pos);
-
+    virtual bool eventFilter(QObject * watched, QEvent * e);
+    
 signals:                                            //TODO: remove later
     void receivedLine(QString line);
     void jobFinished(bool normalExit, int exitStatus);
+    void jumpToFile(const QString & filepath);
 
 private slots:
     void receivedOutput(const QString& buffer);     //TODO: remove later
@@ -60,14 +62,25 @@
     void jobExited(bool normalExit, int exitStatus);
     void cancelJob();
 
+    void clicked(int para, int charPos);
+    void jumpToFile();
+
 private:
+
+    void setTargetFile(const QPoint & pos);
+    void setTargetFile(int para, int charPos);
+
     QColor conflictColor;
     QColor localChangeColor;
     QColor remoteChangeColor;
 
+    QString m_targetFile; ///< Used to remember the file jumpToFile()
+                          ///will jump to.
+    
     bool   m_isUpdateJob;
 
     Cervisia::CommandBase* m_currentCmd;
+    Cervisia::PluginBase*  m_currentPlugin;
 };
 
 #endif
Index: updateview.h
===================================================================
--- updateview.h (revision 538390)
+++ updateview.h (working copy)
@@ -79,6 +79,7 @@
     void commandPrepared(Cervisia::CommandBase* cmd);
     void finishJob(bool normalExit, int exitStatus);
     void updateItem(const QString &filename, Cervisia::EntryStatus status, bool isdir);
+    void jumpToFile(const QString & filepath);
 
 private slots:
     void itemExecuted(QListViewItem *item);
Index: cervisiapart.cpp
===================================================================
--- cervisiapart.cpp (revision 538390)
+++ cervisiapart.cpp (working copy)
@@ -146,6 +146,10 @@
         protocol = new ProtocolView(splitter);
         protocol->setFocusPolicy( QWidget::StrongFocus );
 
+        connect( protocol, SIGNAL(jumpToFile(const QString&)),
+                 update, SLOT(jumpToFile(const QString&)) );
+        
+        
         setWidget(splitter);
     }
     else
Index: protocolview.cpp
===================================================================
--- protocolview.cpp (revision 538390)
+++ protocolview.cpp (working copy)
@@ -23,6 +23,8 @@
 
 #include <qdir.h>
 #include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qapplication.h>
 #include <dcopref.h>
 #include <klocale.h>
 #include <kmessagebox.h>
@@ -32,8 +34,8 @@
 #include "cvsjob_stub.h"
 #include "pluginbase.h"
 #include "pluginmanager.h"
+#include "update_parser.h"
 
-
 using namespace Cervisia;
 
 
@@ -52,6 +54,19 @@
     conflictColor = CervisiaSettings::conflictColor();
     localChangeColor = CervisiaSettings::localChangeColor();
     remoteChangeColor = CervisiaSettings::remoteChangeColor();
+
+    setMouseTracking(true);
+    viewport()->installEventFilter(this);
+    
+    if (KGlobalSettings::singleClick())
+    {
+        connect( this, SIGNAL(clicked(int, int)),
+                 this, SLOT(clicked(int, int)) );
+    } else
+    {
+        connect( this, SIGNAL(doubleClicked(int, int)),
+                 this, SLOT(clicked(int, int)) );
+    }
 }
 
 
@@ -70,6 +85,8 @@
 
     connect(plugin, SIGNAL(commandPrepared(Cervisia::CommandBase*)),
             this, SLOT(commandPrepared(Cervisia::CommandBase*)));
+
+    m_currentPlugin = plugin;
 }
 
 
@@ -100,9 +117,30 @@
     if( length() == 0 )
         menu->setItemEnabled(id, false);
 
+
+    // Add "Go to file" entry
+    setTargetFile(pos);
+    id = menu->insertItem(QString(i18n("Go to file %1")).arg(m_targetFile.isEmpty() ? "" : m_targetFile),
+                          this, SLOT( jumpToFile() ), 0, -1, 0);
+
+    if (m_targetFile.isEmpty())
+        menu->setItemEnabled(id, false);
+
+    menu->insertSeparator(1);
+    
     return menu;
 }
 
+bool ProtocolView::eventFilter(QObject * watched, QEvent * e)
+{
+    if (watched == viewport() && e->type() == QEvent::MouseMove)
+    {
+        QMouseEvent * me = static_cast<QMouseEvent*>(e);
+        setTargetFile(viewportToContents(me->pos()));
+    }
+    
+    return QTextEdit::eventFilter(watched, e);
+}
 
 void ProtocolView::cancelJob()
 {
@@ -195,16 +233,41 @@
         return;
     }
 
+    QString filename;
+    EntryStatus status;
+    m_currentPlugin->updateParser()->parseLine(line, false, filename, status);
+
     QColor color;
     // Colors are the same as in UpdateViewItem::paintCell()
-    if (line.startsWith("C "))
+    switch (status)
+    {
+    case Cervisia::Conflict:
         color = conflictColor;
-    else if (line.startsWith("M ")
-             || line.startsWith("A ") || line.startsWith("R "))
+        break;
+
+    case Cervisia::LocallyModified:
+    case Cervisia::LocallyAdded:
+    case Cervisia::LocallyRemoved:
         color = localChangeColor;
-    else if (line.startsWith("P ") || line.startsWith("U "))
+        break;
+
+    case Cervisia::NeedsUpdate:
+    case Cervisia::Updated:
+    case Cervisia::NeedsPatch:
+    case Cervisia::Patched:
         color = remoteChangeColor;
+        break;
 
+    case Cervisia::NotInCVS:
+    case Cervisia::NeedsMerge:
+    case Cervisia::UpToDate:
+    case Cervisia::Merged:
+    case Cervisia::Removed:
+    case Cervisia::Unknown:
+        // Default font color
+        break;
+    }
+
     append(color.isValid()
            ? QString("<font color=\"%1\"><b>%2</b></font>").arg(color.name())
                                                            .arg(escapedLine)
@@ -212,6 +275,60 @@
 }
 
 
+void ProtocolView::clicked(int para, int charPos)
+{
+    // Set taregt file again in case no mouse move has been generated
+    // yet (possible if popup menu was open)
+    setTargetFile(para, charPos);
+    jumpToFile();
+}
+
+void ProtocolView::jumpToFile()
+{
+    if (!m_targetFile.isEmpty())
+    {
+        emit jumpToFile(m_targetFile);
+    }
+}
+
+/**
+ *  Parse the line pointed to by pos and set m_targetFile if it contains
+ *  a valid file.
+ */
+void ProtocolView::setTargetFile(const QPoint & pos)
+{
+    int para;
+    int charPos = charAt(pos, ¶);
+    setTargetFile(para, charPos);
+}
+
+/**
+ *  Parse specified line set m_targetFile if it contains a valid
+ *  file. Also change the mouse cursor accordingly (pointing hand if
+ *  hovering over a valid filename)
+ */
+void ProtocolView::setTargetFile(int para, int charPos)
+{
+    QString line = text(para);
+    
+    if (m_currentPlugin && m_currentPlugin->updateParser() &&
+        charPos != (int)line.length())
+    {
+        EntryStatus dummy;
+        m_currentPlugin->updateParser()->parseLine(line, false, m_targetFile, dummy);
+    } else m_targetFile = "";
+
+    if (m_targetFile.isEmpty())
+    {
+        viewport()->setCursor(Qt::ArrowCursor);
+    } else
+    {
+        viewport()->setCursor(Qt::PointingHandCursor);
+    }
+}
+
+
+
 #include "protocolview.moc"
 
 
Index: update_parser.h
===================================================================
--- update_parser.h (revision 538390)
+++ update_parser.h (working copy)
@@ -38,6 +38,9 @@
     bool isSimulation() const;
     void setSimulation(bool simulation);
 
+    virtual void parseLine(const QString & line, bool respectIsSimulation,
+                           QString & filename, EntryStatus & status) const = 0;
+    
 signals:
     void updateItemStatus(const QString& filePath, Cervisia::EntryStatus status, bool isdir);
 
Index: updateview_items.cpp
===================================================================
--- updateview_items.cpp (revision 538390)
+++ updateview_items.cpp (working copy)
@@ -715,4 +715,39 @@
     return dirItem;
 }
 
+
+/**
+ *  Returns the child (dir or file) item with the specified relative
+ *  path to parent, or NULL if no such item exists.
+ */
+UpdateItem* findItemByPath(const QString & path, UpdateDirItem* parent)
+{
+    int sep = path.find(QDir::separator());
+
+    // Eliminate trailing '/'
+    if (sep == (int)path.length()-1)
+    {
+        return parent->findItem(path.left(path.length()-1));
+    }
+    
+    if (sep == -1)
+    {
+        return parent->findItem(path);
+    } else
+    {
+        UpdateItem * nextItem = parent->findItem(path.mid(0, sep));
+
+        if (isDirItem(nextItem))
+        {
+            UpdateDirItem * dirItem = static_cast<UpdateDirItem*>(nextItem);
+
+            dirItem->maybeScanDir(false);
+            
+            return findItemByPath(path.mid(sep+1), dirItem);
+        } else return NULL;
+    }
+}
+
+
+
 #include "updateview_items.moc"
Index: updateview_items.h
===================================================================
--- updateview_items.h (revision 538390)
+++ updateview_items.h (working copy)
@@ -31,10 +31,12 @@
 
 class UpdateDirItem;
 class UpdateFileItem;
+class UpdateItem;
 class Visitor;
 
 
-UpdateDirItem* findOrCreateDirItem(const QString&, UpdateDirItem*);
+UpdateDirItem* findOrCreateDirItem(const QString&,       UpdateDirItem*);
+UpdateItem   * findItemByPath     (const QString & path, UpdateDirItem* parent);
 
 
 class UpdateItem : public QListViewItem
@@ -57,7 +59,7 @@
     QString filePath() const;
 
     virtual void accept(Visitor&) = 0;
-
+    
 protected:
 
     UpdateView* updateView() const { return static_cast<UpdateView*>(listView()); }
@@ -90,7 +92,7 @@
 
     void maybeScanDir(bool recursive);
 
-    virtual void accept(Visitor&);
+    virtual void accept(Visitor&);    
 
     enum { RTTI = 10000 };
 
@@ -115,6 +117,7 @@
     bool m_opened;
 
     friend UpdateDirItem* findOrCreateDirItem(const QString&, UpdateDirItem*);
+    friend UpdateItem   * findItemByPath     (const QString&, UpdateDirItem*);
 };
 
 
Index: plugins/svnplugin/svn_update_parser.cpp
===================================================================
--- plugins/svnplugin/svn_update_parser.cpp (revision 538390)
+++ plugins/svnplugin/svn_update_parser.cpp (working copy)
@@ -34,29 +34,59 @@
 }
 
 
+/**
+ *  Parses the update output line and returns the filename and
+ *  status. If the line cannot be parsed, filename will be set to the
+ *  empty string.
+ *
+ *  If respectIsSimulation is false, try to parse line regardless of
+ *  whether isSimulation() yields true.
+ */
+void SvnUpdateParser::parseLine(const QString & line, bool respectIsSimulation,
+                                QString & filename, EntryStatus & status) const
+{
+    if (respectIsSimulation)
+    {
+        if( isSimulation() )
+            parseStatusLine(line, filename, status);
+        else
+            parseUpdateLine(line, filename, status);
+    } else
+    {
+        parseStatusLine(line, filename, status);
+        if (filename.isEmpty()) parseUpdateLine(line, filename, status);
+    }
+}
+
+/**
+ *  Parses the line and emits an according updateItemStatus signal
+ *  with file name and status.
+ */
 void SvnUpdateParser::parseLine(const QString& line)
 {
-    if( isSimulation() )
-        parseStatusLine(line);
-    else
-        parseUpdateLine(line);
+    QString filename;
+    EntryStatus status;
+
+    parseLine(line, true, filename, status);
+
+    if (!filename.isEmpty())
+    {
+        emit updateItemStatus(filename, status, false);
+    }
 }
 
 
-void SvnUpdateParser::parseStatusLine(const QString& line)
+void SvnUpdateParser::parseStatusLine(const QString& line, QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    status = Cervisia::Unknown;
+    filename = "";
+    
     QRegExp rx(".*Revision.*\\d+");
     rx.setCaseSensitive(false);
     if( line.length() > 2 && rx.search(line) < 0 )
     {
-        QString fileName = line.right(line.length() - 20);
-
-        kdDebug(8050) << k_funcinfo << "fileName = " << fileName
-                      << ", length = " << line.length() << endl;
-
-        EntryStatus status = Cervisia::Unknown;
         switch( line[0].latin1() )
         {
             case 'C':
@@ -76,30 +106,29 @@
                 break;
             default:
                 if( line[7].latin1() == '*' )
+                {
                     status = Cervisia::NeedsUpdate;
-                else
-                    return;
+                } else return;
         }
-
-        emit updateItemStatus(fileName, status, false);
-    }
+        
+        filename = line.right(line.length() - 20);        
+        kdDebug(8050) << k_funcinfo << "fileName = " << filename
+                      << ", length = " << line.length() << endl;
+    }
 }
 
 
-void SvnUpdateParser::parseUpdateLine(const QString& line)
+void SvnUpdateParser::parseUpdateLine(const QString& line, QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    status = Cervisia::Unknown;
+    filename = "";
+    
     QRegExp rx(".*Revision.*\\d+");
     rx.setCaseSensitive(false);
     if( line.length() > 2 && rx.search(line) < 0 )
     {
-        QString fileName = line.right(line.length() - 5);
-
-        kdDebug(8050) << k_funcinfo << "fileName = " << fileName
-                      << ", length = " << line.length() << endl;
-
-        EntryStatus status = Cervisia::Unknown;
         switch( line[0].latin1() )
         {
             case 'C':
@@ -123,7 +152,9 @@
             default:
                 return;
         }
-
-        emit updateItemStatus(fileName, status, false);
-    }
+        
+        filename = line.right(line.length() - 5);
+        kdDebug(8050) << k_funcinfo << "fileName = " << filename
+                      << ", length = " << line.length() << endl;
+    }
 }
Index: plugins/svnplugin/svn_update_parser.h
===================================================================
--- plugins/svnplugin/svn_update_parser.h (revision 538390)
+++ plugins/svnplugin/svn_update_parser.h (working copy)
@@ -32,11 +32,14 @@
     SvnUpdateParser();
     ~SvnUpdateParser();
 
+    virtual void parseLine(const QString & line, bool respectIsSimulation,
+                           QString & filename, EntryStatus & status) const;
+
 private:
     virtual void parseLine(const QString& line);
 
-    void parseStatusLine(const QString& line);
-    void parseUpdateLine(const QString& line);
+    void parseStatusLine(const QString& line, QString & filename, EntryStatus & status) const;
+    void parseUpdateLine(const QString& line, QString & filename, EntryStatus & status) const;
 };
 
 
Index: plugins/cvsplugin/cvs_update_parser.cpp
===================================================================
--- plugins/cvsplugin/cvs_update_parser.cpp (revision 538390)
+++ plugins/cvsplugin/cvs_update_parser.cpp (working copy)
@@ -38,13 +38,16 @@
  * is true, it is assumed that the output is from a command
  * 'cvs update -n', i.e. cvs actually changes no files.
  */
-void CvsUpdateParser::parseLine(const QString& line)
+void CvsUpdateParser::parseLine(const QString & line, bool,
+                                QString & filename, EntryStatus & status) const
 {
     kdDebug(8050) << k_funcinfo << "line = " << line << endl;
 
+    filename = "";
+    status = Cervisia::Unknown;
+    
     if( line.length() > 2 && line[1] == ' ' )
     {
-        EntryStatus status = Cervisia::Unknown;
         switch (line[0].latin1())
         {
         case 'C':
@@ -71,18 +74,39 @@
             return;
         }
 
-        emit updateItemStatus(line.mid(2).stripWhiteSpace(), status, false);
+        filename = line.mid(2).stripWhiteSpace();
     }
+}
 
-    const QString removedFileStart(QString::fromLatin1("cvs server: "));
-    const QString removedFileEnd(QString::fromLatin1(" is no longer in the repository"));
-    if (line.startsWith(removedFileStart) && line.endsWith(removedFileEnd))
+
+
+/**
+ *  Parses the line and emits an according updateItemStatus signal
+ *  with file name and status.
+ */
+void CvsUpdateParser::parseLine(const QString& line)
+{
+    EntryStatus status;
+    QString filename;
+
+    parseLine(line, true, filename, status);
+
+    if (!filename.isEmpty())
     {
-    }
-
+        emit updateItemStatus(filename, status, false);
+    } else
+    {
+        const QString removedFileStart(QString::fromLatin1("cvs server: "));
+        const QString removedFileEnd(QString::fromLatin1(" is no longer in the repository"));
+        if (line.startsWith(removedFileStart) && line.endsWith(removedFileEnd))
+        {
+        }
 #if 0
-    else if (str.left(21) == "cvs server: Updating " ||
-             str.left(21) == "cvs update: Updating ")
-        updateItem(str.right(str.length()-21), Unknown, true);
+        else if (str.left(21) == "cvs server: Updating " ||
+                 str.left(21) == "cvs update: Updating ")
+        {
+            updateItem(str.right(str.length()-21), Unknown, true);
+        }
 #endif
+    }
 }
Index: plugins/cvsplugin/cvs_update_parser.h
===================================================================
--- plugins/cvsplugin/cvs_update_parser.h (revision 538390)
+++ plugins/cvsplugin/cvs_update_parser.h (working copy)
@@ -32,6 +32,9 @@
     CvsUpdateParser();
     ~CvsUpdateParser();
 
+    virtual void parseLine(const QString & line, bool respectIsSimulation,
+                           QString & filename, EntryStatus & status) const;
+    
 private:
     virtual void parseLine(const QString& line);
 };
Index: updateview.cpp
===================================================================
--- updateview.cpp (revision 538390)
+++ updateview.cpp (working copy)
@@ -570,6 +570,24 @@
 }
 
 
+/**
+ *  Makes the entry with the specified path visible and marks it.
+ */
+void UpdateView::jumpToFile(const QString & filepath)
+{
+    UpdateItem* rootItem = static_cast<UpdateItem*>(firstChild());
+    if (!rootItem) return;
+    if (!isDirItem(rootItem)) return;
+    
+    UpdateItem* fileItem = findItemByPath(filepath, static_cast<UpdateDirItem*>(rootItem));
+    if (!fileItem) return;
+    
+    ensureItemVisible(fileItem);
+    clearSelection();
+    setSelected(fileItem, true);
+}
+
+
 void UpdateView::itemExecuted(QListViewItem *item)
 {
     if (isFileItem(item))

_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia

Re: Double-click on file in message window -> jump to it in tree?

by André Wöbbeking-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

On Sunday 07 May 2006 22:06, Muschick Christian wrote:
> Hi!

sorry, again a bit late :-(

> > I had only a short look but you should
> >
> > 1) implement findItemByFilePath() as free function like
> > findOrCreateDirItem() and not as member.
>
> Not exactly to my taste, friend and static_casts, but here you go ;-)

Thanks, but it's much easier:

UpdateItem* findItemByPath(const QString& path,
                           UpdateDirItem* rootItem)
{
    const QFileInfo fileInfo(path);

    UpdateDirItem* dirItem = findOrCreateDirItem(fileInfo.dirPath(),
rootItem);

    return dirItem->findItem(fileInfo.fileName());
}

you only have to make UpdateDirItem::findItem() public.

> > 2) pass QStrings by const&
>
> Ok, changed the function so it doesn't need to change the input
> string...

Ah, didn't see that.

> > BTW, after my last change only top level items are guaranteed to
> > exist all other items are created on demand (when the parent folder
> > is opened).
>
> What exactly does that mean for me? I now call maybeScanDir() while
> traversing the nodes in findItemByPath(), is this ok?

This should be unnecessary. As you call ensureItemVisible() which opens
each parent if necessary via setOpen() which calls maybeScanDir() if
needed.

> As additional change in this patch, I modified
> Protocolview::appendLine() to use the new parseLine function in order
> to colourize the output lines (currently doesn't work because
> m_isUpdateJob is always false).

This is a regression due to the subversion support, thanks.


Cheers,
André
_______________________________________________
Cervisia mailing list
Cervisia@...
https://mail.kde.org/mailman/listinfo/cervisia