Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 274469da authored by Pino Toscano's avatar Pino Toscano

Almost complete support for inverse search within okular.

THe system generally works; what is missing is a good activating strategy (added in TODO - our usability expert is working on that), and a GUI to configure the editor.
The DVI backend was adapted to use this new feature.
(The PDF backend will use it soon.)

svn path=/trunk/playground/graphics/okular/; revision=605708
parent 02664703
......@@ -20,6 +20,9 @@ Bugs and wishes to close when moving okular to kdegraphics:
-> WISH 131361: mouse hovering on an external link can produce a tooltip of the URI, as in acroread and evince
In progress [working on]:
-> inverse search (BR113191)
find with an usability expert the "best" way to activate such a link
provide a configuration widget to choose the editor and configure a custom one
-> toc: highlight the row of the current page (BR127358)
(check if there's a better way to do the highlighting - in case just edit TOCItem::setCurrent())
-> thumbnailslist: show Viewport in(blended/contour)
......
......@@ -141,6 +141,17 @@
<entry key="WatchFile" type="Bool" >
<default>true</default>
</entry>
<entry key="ExternalEditor" type="Enum" >
<default>Kate</default>
<choices>
<choice name="Kate" />
<choice name="Scite" />
<choice name="Custom" />
</choices>
</entry>
<entry key="ExternalEditorCommand" type="String">
<default>kate --use --line %l --column %c</default>
</entry>
</group>
<group name="Main View" >
<entry key="ShowLeftPanel" type="Bool" >
......
......@@ -14,6 +14,7 @@
#include "annotations.h"
#include "area.h"
#include "generator.h"
#include "link.h"
using namespace Okular;
......@@ -188,6 +189,8 @@ ObjectRect::~ObjectRect()
if ( m_objectType == Link )
delete static_cast<Okular::Link*>( m_pointer );
else if ( m_objectType == SourceRef )
delete static_cast<Okular::SourceReference*>( m_pointer );
else
kDebug() << "Object deletion not implemented for type '" << m_objectType << "' ." << endl;
}
......@@ -220,3 +223,20 @@ AnnotationObjectRect::~AnnotationObjectRect()
m_pointer = 0;
}
/** class SourceRefObjectRect **/
SourceRefObjectRect::SourceRefObjectRect( const NormalizedPoint& point, void * srcRef )
: ObjectRect( point.x, point.y, .0, .0, false, SourceRef, srcRef ), m_point( point )
{
}
QRect SourceRefObjectRect::boundingRect( double /*xScale*/, double /*yScale*/ ) const
{
return QRect();
}
bool SourceRefObjectRect::contains( double x, double y, double xScale, double yScale ) const
{
return ( pow( x - m_point.x, 2 ) + pow( y - m_point.y, 2 ) ) < ( pow( (double)7/xScale, 2 ) + pow( (double)7/yScale, 2 ) );
}
......@@ -84,7 +84,7 @@ class OKULAR_EXPORT ObjectRect
{
public:
// definition of the types of storable objects
enum ObjectType { Link, Image, OAnnotation };
enum ObjectType { Link, Image, OAnnotation, SourceRef };
// default constructor: initialize all parameters
ObjectRect( double l, double t, double r, double b, bool ellipse, ObjectType typ, void * obj );
......@@ -119,6 +119,18 @@ class OKULAR_EXPORT AnnotationObjectRect : public ObjectRect
Annotation * m_ann;
};
class OKULAR_EXPORT SourceRefObjectRect : public ObjectRect
{
public:
SourceRefObjectRect( const NormalizedPoint& point, void * scrRef );
virtual QRect boundingRect( double xScale, double yScale ) const;
virtual bool contains( double x, double y, double xScale, double yScale ) const;
private:
NormalizedPoint m_point;
};
/**
* Internal Storage: normalized colored highlight owned by id
*/
......
......@@ -13,6 +13,7 @@
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QMap>
#include <QtCore/QProcess>
#include <QtCore/QTextStream>
#include <QtCore/QTimer>
#include <QtGui/QApplication>
......@@ -1429,6 +1430,46 @@ void Document::processLink( const Link * link )
}
}
void Document::processSourceReference( const SourceReference * ref )
{
if ( !ref )
return;
static QHash< int, QString > editors;
// init the editors table if empty (on first run, usually)
if ( editors.isEmpty() )
{
editors[ Settings::EnumExternalEditor::Kate ] =
QLatin1String( "kate --use --line %l --column %c" );
editors[ Settings::EnumExternalEditor::Scite ] =
QLatin1String( "scite %f \"-goto:%l,%c\"" );
}
QHash< int, QString >::iterator it = editors.find( Settings::externalEditor() );
QString p;
if ( it != editors.end() )
p = *it;
else
p = Settings::externalEditorCommand();
// custom editor not yet configured
if ( p.isEmpty() )
return;
// replacing the placeholders
p.replace( QLatin1String( "%l" ), QString::number( ref->row() ) );
p.replace( QLatin1String( "%c" ), QString::number( ref->column() ) );
if ( p.indexOf( QLatin1String( "%f" ) ) > -1 )
p.replace( QLatin1String( "%f" ), ref->fileName() );
else
p.append( QLatin1String( " " ) + ref->fileName() );
// paranoic checks
if ( p.isEmpty() || p.trimmed() == ref->fileName() )
return;
QProcess::startDetached( p );
}
bool Document::print( KPrinter &printer )
{
return generator ? generator->print( printer ) : false;
......
......@@ -44,6 +44,7 @@ class Link;
class NotifyRequest;
class Page;
class PixmapRequest;
class SourceReference;
class VisiblePageRect;
/** IDs for seaches. Globally defined here. **/
......@@ -148,6 +149,7 @@ class OKULAR_EXPORT Document : public QObject
void toggleBookmark( int page );
void processLink( const Link * link );
void processSourceReference( const SourceReference * ref );
bool canConfigurePrinter() const;
bool print( KPrinter &printer );
// notifications sent by generator
......
......@@ -310,6 +310,47 @@ KIcon ExportFormat::icon() const
return d->mIcon;
}
class SourceReference::Private
{
public:
Private()
: row( 0 ), column( 0 )
{
}
QString filename;
int row;
int column;
};
SourceReference::SourceReference( const QString &fileName, int row, int column )
: d( new Private )
{
d->filename = fileName;
d->row = row;
d->column = column;
}
SourceReference::~SourceReference()
{
delete d;
}
QString SourceReference::fileName() const
{
return d->filename;
}
int SourceReference::row() const
{
return d->row;
}
int SourceReference::column() const
{
return d->column;
}
kdbgstream& operator<<( kdbgstream &str, const Okular::PixmapRequest &req )
{
QString s = QString( "%1 PixmapRequest (id: %2) (%3x%4), prio %5, pageNo %6" )
......
......@@ -440,6 +440,43 @@ class OKULAR_EXPORT PixmapRequest
Private* const d;
};
/**
* @short Defines a source reference
*
* A source reference is a reference to one of the source(s) of the loaded
* document.
*/
class OKULAR_EXPORT SourceReference
{
public:
/**
* Creates a reference to the row @p row and column @p column of the
* source @p fileName
*/
SourceReference( const QString &fileName, int row, int column = 0 );
~SourceReference();
/**
* Returns the filename of the source.
*/
QString fileName() const;
/**
* Returns the row of the position in the source file.
*/
int row() const;
/**
* Returns the column of the position in the source file.
*/
int column() const;
private:
class Private;
Private* const d;
};
}
kdbgstream& operator<<( kdbgstream &str, const Okular::PixmapRequest &req );
......
......@@ -69,6 +69,7 @@ Page::~Page()
deleteHighlights();
deleteAnnotations();
deleteTextSelections();
deleteSourceReferences();
delete m_text;
delete m_transition;
}
......@@ -334,6 +335,13 @@ void Page::setTextSelections( RegularAreaRect *r, const QColor & color )
m_textSelections = hr;
}
void Page::setSourceReferences( const QLinkedList< SourceRefObjectRect * > refRects )
{
deleteSourceReferences();
foreach( SourceRefObjectRect * rect, refRects )
m_rects << rect;
}
void Page::addAnnotation( Annotation * annotation )
{
//uniqueName: okular-PAGENUM-ID
......@@ -469,6 +477,11 @@ void Page::deleteTextSelections()
}
}
void Page::deleteSourceReferences()
{
deleteObjectRects( m_rects, QSet<ObjectRect::ObjectType>() << ObjectRect::SourceRef );
}
void Page::deleteAnnotations()
{
// delete ObjectRects of type Annotation
......
......@@ -28,6 +28,7 @@ namespace Okular {
class Annotation;
class PageTransition;
class SourceReference;
class TextPage;
class TextSelection;
......@@ -95,6 +96,7 @@ class OKULAR_EXPORT Page : public QObject
void setObjectRects( const QLinkedList< ObjectRect * > rects );
void setHighlight( int s_id, RegularAreaRect *r, const QColor & color );
void setTextSelections( RegularAreaRect *r, const QColor & color );
void setSourceReferences( const QLinkedList< SourceRefObjectRect * > refRects );
void addAnnotation( Annotation * annotation );
void modifyAnnotation( Annotation * newannotation );
bool removeAnnotation( Annotation * annotation );
......@@ -106,6 +108,7 @@ class OKULAR_EXPORT Page : public QObject
void deleteRects();
void deleteHighlights( int s_id = -1 );
void deleteTextSelections();
void deleteSourceReferences();
void deleteAnnotations();
// operations to save/restore page state (by Document)
......
......@@ -172,6 +172,8 @@ public slots:
QVector<PreBookmark> getPrebookmarks() const { return prebookmarks; }
const QVector<DVI_SourceFileAnchor>& sourceAnchors() { return sourceHyperLinkAnchors; }
private slots:
/** This method shows a dialog that tells the user that source
information is present, and gives the opportunity to open the
......
......@@ -415,6 +415,22 @@ void DviGenerator::loadPages( QVector< Okular::Page * > &pagesVector, int orient
pagesVector[i] = page;
}
kDebug() << "pagesVector successfully inizialized ! " << endl;
// filling the pages with the source references rects
const QVector<DVI_SourceFileAnchor>& sourceAnchors = m_dviRenderer->sourceAnchors();
QVector< QLinkedList< Okular::SourceRefObjectRect * > > refRects( numofpages );
foreach ( const DVI_SourceFileAnchor& sfa, sourceAnchors )
{
if ( sfa.page < 1 || (int)sfa.page > numofpages )
continue;
Okular::NormalizedPoint p( 0.5, (double)sfa.distance_from_top.getLength_in_pixel( Okular::Utils::getDpiY() ) / (double)pageRequiredSize.height() );
Okular::SourceReference * sourceRef = new Okular::SourceReference( sfa.fileName, sfa.line );
refRects[ sfa.page - 1 ].append( new Okular::SourceRefObjectRect( p, sourceRef ) );
}
for ( int i = 0; i < refRects.size(); ++i )
if ( !refRects.at(i).isEmpty() )
pagesVector[i]->setSourceReferences( refRects.at(i) );
}
#include "generator_dvi.moc"
......@@ -114,7 +114,7 @@ class Length
/** @returns the length in pixel. The parameter @param res is the resolution of the
used device in DPI. */
int getLength_in_pixel(double res) { return int(getLength_in_inch() * res); }
int getLength_in_pixel(double res) const { return int(getLength_in_inch() * res); }
/** @returns true is lengths differ by no more than 2mm */
bool isNearlyEqual(const Length &o) const {return fabs(length_in_mm-o.getLength_in_mm()) <= 2.0;}
......
......@@ -1420,6 +1420,15 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e )
}
else
{
// TODO: find a better way to activate the source reference "links"
// for the moment they are activated with Shift + left click
rect = e->modifiers() == Qt::ShiftModifier ? pageItem->page()->getObjectRect( Okular::ObjectRect::SourceRef, nX, nY, pageItem->width(), pageItem->height() ) : 0;
if ( rect )
{
const Okular::SourceReference * ref = static_cast< const Okular::SourceReference * >( rect->pointer() );
d->document->processSourceReference( ref );
}
#if 0
// a link can move us to another page or even to another document, there's no point in trying to
// process the click on the image once we have processes the click on the link
rect = pageItem->page()->getObjectRect( Okular::ObjectRect::Image, nX, nY, pageItem->width(), pageItem->height() );
......@@ -1434,6 +1443,7 @@ void PageView::contentsMouseReleaseEvent( QMouseEvent * e )
// if ( pageItem->pageNumber() != (int)d->document->currentPage() )
d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID );
}*/
#endif
}
}
else if ( rightButton )
......
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