- GIGANTIC 2700 line diff with LOTS OF FEATURES!

- 1. editor-like text selection, and I do mean it, its not pseudo-editor 
  (like the ones acroread and kviewshell have) it doesnt intersect the 
  selection area with words under it, no, it does a lot more, including 
  work on cursors and searching for the text area closest to the given
  cursor
- 2. rotation support, change the orientation of the documents if 
  you need too :)
- 3. the kfaxview backend works beautifully, porting kviewshell backends
  is damn easy ! djvu and dvi will be next!
- 4. Hardware Blending of selection rectangles! We now use XRender 
  instead of KImageEffect, makes a damn faster blend!
- 5. Overview mode - as seen in Kviewshell, but quite a bit extended, 
  the kviewshell is only one state, while we support it in both 
  continous and non-continous form
- BTW. I coded all those features myself, (apart from kfaxview backend library)
  it is an impressive bit right? but oKular cant be run by only one person, 
  join in on the fun! i can introduce you into the code just mail niedakh@gmail.com


svn path=/trunk/playground/graphics/oKular/kpdf/; revision=509871
This commit is contained in:
Piotr Szymanski 2006-02-15 18:54:49 +00:00
parent efd05b1ea5
commit 4387e1489e
28 changed files with 1120 additions and 385 deletions

View file

@ -8,149 +8,80 @@
<rect>
<x>0</x>
<y>0</y>
<width>351</width>
<height>416</height>
<width>340</width>
<height>554</height>
</rect>
</property>
<property name="caption">
<string>DlgGeneral</string>
</property>
<spacer>
<property name="name">
<cstring>spacer3</cstring>
</property>
<property name="orientation">
<enum>Vertical</enum>
</property>
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
<property name="geometry">
<rect>
<x>90</x>
<y>510</y>
<width>20</width>
<height>40</height>
</rect>
</property>
</spacer>
<spacer>
<property name="name">
<cstring>spacer4</cstring>
</property>
<property name="orientation">
<enum>Horizontal</enum>
</property>
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
<property name="geometry">
<rect>
<x>300</x>
<y>180</y>
<width>40</width>
<height>20</height>
</rect>
</property>
</spacer>
<widget class="QLayoutWidget">
<property name="name">
<cstring>layout7</cstring>
<cstring>layout13</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>1</y>
<width>348</width>
<height>408</height>
<y>0</y>
<width>295</width>
<height>501</height>
</rect>
</property>
<grid>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QGroupBox" row="2" column="0">
<property name="name">
<cstring>groupBox2_2</cstring>
</property>
<property name="title">
<string>Temporary DEBUG Options</string>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_DebugDrawBoundaries</cstring>
</property>
<property name="text">
<string>DebugDrawBoundaries</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_DebugDrawAnnotationRect</cstring>
</property>
<property name="text">
<string>DebugDrawAnnotationRect</string>
</property>
</widget>
</vbox>
</widget>
<widget class="QGroupBox" row="1" column="0">
<property name="name">
<cstring>groupBox3</cstring>
</property>
<property name="title">
<string>Program Features</string>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLayoutWidget" row="0" column="1">
<property name="name">
<cstring>layout3_2_2</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLabel">
<property name="name">
<cstring>pixmapLabel1_2_2</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="pixmap">
<pixmap>"exec", 32</pixmap>
</property>
</widget>
<spacer>
<property name="name">
<cstring>spacerV1_2</cstring>
</property>
<property name="orientation">
<enum>Vertical</enum>
</property>
<property name="sizeType">
<enum>Minimum</enum>
</property>
<property name="sizeHint">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</vbox>
</widget>
<widget class="QLayoutWidget" row="0" column="0">
<property name="name">
<cstring>layout5</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_ObeyDRM</cstring>
</property>
<property name="text">
<string>&amp;Obey DRM limitations</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_WatchFile</cstring>
</property>
<property name="text">
<string>&amp;Watch file</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_ChooseGenerators</cstring>
</property>
<property name="text">
<string>Show generator selection dialog</string>
</property>
<property name="accel">
<string></string>
</property>
</widget>
</vbox>
</widget>
</grid>
</widget>
<widget class="QGroupBox" row="0" column="0">
<widget class="QGroupBox">
<property name="name">
<cstring>groupBox2</cstring>
</property>
@ -176,6 +107,9 @@
<property name="text">
<string>Show scroll&amp;bars</string>
</property>
<property name="accel">
<string>Alt+B</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
@ -262,33 +196,216 @@
</widget>
</hbox>
</widget>
</grid>
<widget class="QGroupBox">
<property name="name">
<cstring>groupBox3</cstring>
</property>
<property name="title">
<string>Program Features</string>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLayoutWidget" row="0" column="1">
<property name="name">
<cstring>layout3_2_2</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLabel">
<property name="name">
<cstring>pixmapLabel1_2_2</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="pixmap">
<pixmap>"exec", 32</pixmap>
</property>
</widget>
<spacer>
<property name="name">
<cstring>spacerV1_2</cstring>
</property>
<property name="orientation">
<enum>Vertical</enum>
</property>
<property name="sizeType">
<enum>Minimum</enum>
</property>
<property name="sizeHint">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</vbox>
</widget>
<widget class="QLayoutWidget" row="0" column="0">
<property name="name">
<cstring>layout5</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_ObeyDRM</cstring>
</property>
<property name="text">
<string>&amp;Obey DRM limitations</string>
</property>
<property name="accel">
<string>Alt+O</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_WatchFile</cstring>
</property>
<property name="text">
<string>&amp;Watch file</string>
</property>
<property name="accel">
<string>Alt+W</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_ChooseGenerators</cstring>
</property>
<property name="text">
<string>Show generator selection dialog</string>
</property>
<property name="accel">
<string></string>
</property>
</widget>
</vbox>
</widget>
</grid>
</widget>
<widget class="QGroupBox">
<property name="name">
<cstring>groupBox2_2_2</cstring>
</property>
<property name="title">
<string>Rendering options</string>
</property>
<widget class="QLayoutWidget">
<property name="name">
<cstring>layout12</cstring>
</property>
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>230</width>
<height>58</height>
</rect>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLabel" row="1" column="0">
<property name="name">
<cstring>columnLabel</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>4</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Overview columns:</string>
</property>
</widget>
<widget class="QLabel" row="0" column="0">
<property name="name">
<cstring>rowLabel</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>4</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Overview rows:</string>
</property>
</widget>
<widget class="QSpinBox" row="1" column="1">
<property name="name">
<cstring>kcfg_ViewColumns</cstring>
</property>
<property name="maxValue">
<number>10</number>
</property>
<property name="minValue">
<number>3</number>
</property>
</widget>
<widget class="QSpinBox" row="0" column="1">
<property name="name">
<cstring>kcfg_ViewRows</cstring>
</property>
<property name="maxValue">
<number>6</number>
</property>
<property name="minValue">
<number>1</number>
</property>
</widget>
</grid>
</widget>
</widget>
<widget class="QGroupBox">
<property name="name">
<cstring>groupBox2_2</cstring>
</property>
<property name="title">
<string>Temporary DEBUG Options</string>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_DebugDrawBoundaries</cstring>
</property>
<property name="text">
<string>DebugDrawBoundaries</string>
</property>
</widget>
<widget class="QCheckBox">
<property name="name">
<cstring>kcfg_DebugDrawAnnotationRect</cstring>
</property>
<property name="text">
<string>DebugDrawAnnotationRect</string>
</property>
</widget>
</vbox>
</widget>
</vbox>
</widget>
<spacer>
<property name="name">
<cstring>spacer3</cstring>
</property>
<property name="orientation">
<enum>Vertical</enum>
</property>
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
<property name="geometry">
<rect>
<x>160</x>
<y>410</y>
<width>20</width>
<height>40</height>
</rect>
</property>
</spacer>
</widget>
<includes>
<include location="global" impldecl="in implementation">kdialog.h</include>

View file

@ -184,6 +184,11 @@
<min>1</min>
<max>8</max>
</entry>
<entry key="ViewRows" type="UInt" >
<default>1</default>
<min>1</min>
<max>5</max>
</entry>
<entry key="ViewContinuous" type="Bool" >
<default>true</default>
</entry>

View file

@ -145,10 +145,10 @@ Annotation::Annotation( const QDomNode & annNode )
// parse boundary
if ( ee.tagName() == "boundary" )
{
boundary.left = ee.attribute( "l" ).toDouble();
boundary.top = ee.attribute( "t" ).toDouble();
boundary.right = ee.attribute( "r" ).toDouble();
boundary.bottom = ee.attribute( "b" ).toDouble();
boundary=NormalizedRect(ee.attribute( "l" ).toDouble(),
ee.attribute( "t" ).toDouble(),
ee.attribute( "r" ).toDouble(),
ee.attribute( "b" ).toDouble());
}
// parse penStyle if not default
else if ( ee.tagName() == "penStyle" )

View file

@ -37,7 +37,7 @@ NormalizedRect::NormalizedRect( const QRect & r, double xScale, double yScale )
bool NormalizedRect::isNull() const
{
return left == 0 && top == 0 && right == 0 && bottom == 0;
return left == 0 && top== 0 && right == 0 && bottom == 0;
}
bool NormalizedRect::contains( double x, double y ) const
@ -60,6 +60,28 @@ bool NormalizedRect::intersects( double l, double t, double r, double b ) const
return (l <= right) && (r >= left) && (t <= bottom) && (b >= top);
}
NormalizedRect NormalizedRect::operator| (const NormalizedRect & r) const
{
NormalizedRect ret;
// todo !
ret.left=QMIN(left,r.left);
ret.top=QMIN(top,r.top);
ret.bottom=QMAX(bottom,r.bottom);
ret.right=QMAX(right,r.right);
return ret;
}
NormalizedRect& NormalizedRect::operator|= (const NormalizedRect & r)
{
return ((*this) = (*this) | r );
}
/*
kdbgstream& operator << (kdbgstream& str , const NormalizedRect &r)
{
str << "[" <<r.left() << "," << r.top() << "] x "<< "[" <<r.right() << "," << r.bottom() << "]";
return str;
}*/
QRect NormalizedRect::geometry( int xScale, int yScale ) const
{
int l = (int)( left * xScale ),

View file

@ -11,6 +11,7 @@
#define _KPDF_AREA_H_
#include <qvaluelist.h>
#include <qcolor.h>
#include <kdebug.h>
class QRect;
class KPDFLink;
@ -44,8 +45,11 @@ class NormalizedRect
bool intersects( double l, double t, double r, double b ) const;
bool intersects( const NormalizedRect * r ) const;
QRect geometry( int xScale, int yScale ) const;
NormalizedRect operator| (const NormalizedRect & r) const;
NormalizedRect& operator|= (const NormalizedRect & r);
};
// kdbgstream& operator << (kdbgstream &, const NormalizedRect &);
/**
* @short NormalizedRect that contains a reference to an object.
@ -98,6 +102,7 @@ struct HighlightRect : public NormalizedRect
* intersects(NormalizedShape)
* isNull()
* geometry(int,int)
* operator | and |= which unite two NormalizedShapes
*/
template <class NormalizedShape, class Shape> class RegularArea :
@ -109,13 +114,43 @@ public QValueList<NormalizedShape*>
// RegularArea<NormalizedShape,Shape> (NormalizedShape* x) { QValueList(x) ; } ;
// class Iterator : public QValueListIterator<NormalizedShape*> {};
bool contains( double x, double y ) const;
bool contains( NormalizedShape * ) const;
bool intersects (const RegularArea<NormalizedShape,Shape> * area) const;
bool intersects (const NormalizedShape * shape) const;
void appendArea (const RegularArea<NormalizedShape,Shape> *area);
void simplify ();
bool isNull() const;
QValueList<Shape>* geometry( int xScale, int yScale ) const;
QValueList<Shape>* geometry( int xScale, int yScale, int dx=0,int dy=0 ) const;
};
template <class NormalizedShape, class Shape>
void RegularArea<NormalizedShape, Shape>::simplify()
{
int end=this->count(),i=0,x=0;
QValueList <NormalizedShape*> m_remove;
for (;i<end;i++)
{
if ( i < (end-1) )
{
if ( (*this)[x]->intersects( (*this)[i+1] ) )
{
*((*this)[x]) |= *((*this)[i+1]);
m_remove.append( (*this)[i+1] );
}
else
{
x=i+1;
}
}
}
while (!m_remove.isEmpty())
{
this->remove( m_remove.last() );
m_remove.pop_back();
}
kdDebug() << "from " << end << " to " << this->count() << endl;
}
template <class NormalizedShape, class Shape>
bool RegularArea<NormalizedShape, Shape>::isNull() const
{
@ -204,9 +239,21 @@ bool RegularArea<NormalizedShape, Shape>::contains (double x, double y) const
return false;
}
template <class NormalizedShape, class Shape>
bool RegularArea<NormalizedShape, Shape>::contains (NormalizedShape * shape) const
{
if (!this)
return false;
if (this->isEmpty())
return false;
const QValueList<NormalizedShape*> * const lista=dynamic_cast<const QValueList<NormalizedShape*> * const >(this);
return lista->contains(shape);
}
template <class NormalizedShape, class Shape>
QValueList<Shape> *
RegularArea<NormalizedShape, Shape>::geometry( int xScale, int yScale ) const
RegularArea<NormalizedShape, Shape>::geometry( int xScale, int yScale, int dx, int dy ) const
{
if (!this)
return false;
@ -214,11 +261,13 @@ RegularArea<NormalizedShape, Shape>::geometry( int xScale, int yScale ) const
return 0;
ConstIterator i;
QValueList<Shape>* ret=0;
QValueList<Shape>* ret=new QValueList<Shape>;
Shape t;
for (i=this->begin();i!=this->end();++i)
{
ret.append((*i)->geometry(xScale,yScale));
t=(*i)->geometry(xScale,yScale);
t.moveBy(dx,dy);
ret->append(t);
}
return ret;

View file

@ -526,6 +526,16 @@ bool KPDFDocument::supportsRotation() const
return generator ? generator->supportsRotation() : false;
}
bool KPDFDocument::supportsPaperSizes() const
{
return generator ? generator->supportsPaperSizes() : false;
}
QStringList KPDFDocument::paperSizes() const
{
return generator ? generator->paperSizes() : QStringList();
}
bool KPDFDocument::historyAtBegin() const
{
return d->viewportIterator == d->viewportHistory.begin();
@ -575,6 +585,7 @@ void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & request
{
// set the 'page field' (see PixmapRequest) and check if it is valid
PixmapRequest * request = *rIt;
kdWarning() << "request id=" << request->id << " " <<request->width << "x" << request->height << "@" << request->pageNumber << endl;
if ( !(request->page = pages_vector[ request->pageNumber ]) )
{
// skip requests referencing an invalid page (must not happen)
@ -1294,6 +1305,7 @@ void KPDFDocument::sendGeneratorRequest()
// submit the request to the generator
if ( generator->canGeneratePixmap( request->async ) )
{
kdWarning() << "sending request id=" << request->id << " " <<request->width << "x" << request->height << "@" << request->pageNumber << " async == " << request->async << endl;
d->pixmapRequestsStack.remove ( request );
generator->generatePixmap ( request );
}
@ -1593,14 +1605,27 @@ void KPDFDocument::slotTimedMemoryCheck()
void KPDFDocument::slotOrientation( int orientation )
{
if (generator->supportsRotation())
if ( generator->supportsRotation() )
{
generator->setOrientation(pages_vector,orientation);
foreachObserver( notifySetup( pages_vector, true ) );
foreachObserver( notifyContentsCleared (DocumentObserver::Pixmap | DocumentObserver::Highlights | DocumentObserver::Annotations));
// foreachObserver( notifyViewportChanged( false /*disables smoothMove*/ ));
// foreachObserver( notifyPageChanged( ) );
kdDebug() << "Oreint: " << orientation << endl;
}
}
void KPDFDocument::slotPaperSizes( int newsize )
{
if (generator->supportsPaperSizes())
{
generator->setPaperSize(pages_vector,newsize);
foreachObserver( notifySetup( pages_vector, true ) );
kdDebug() << "PaperSize no: " << newsize << endl;
}
}
/** DocumentViewport **/
DocumentViewport::DocumentViewport( int n )

View file

@ -14,6 +14,7 @@
#include <qobject.h>
#include <qvaluevector.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qdom.h>
#include <qdict.h>
#include <kmimetype.h>
@ -86,6 +87,8 @@ class KPDFDocument : public QObject
bool isAllowed( int /*Document::Permisison(s)*/ ) const;
bool supportsSearching() const;
bool supportsRotation() const;
bool supportsPaperSizes() const;
QStringList paperSizes() const;
// might be useful later
// bool hasFonts() const;
bool historyAtBegin() const;
@ -122,6 +125,7 @@ class KPDFDocument : public QObject
public slots:
void slotOrientation( int orientation );
void slotPaperSizes( int );
signals:
void close();

View file

@ -85,6 +85,9 @@ class Generator : public QObject
// rotation
virtual bool supportsRotation() { return false; };
virtual void setOrientation(QValueVector<KPDFPage*> & /*pagesVector*/, int /*orientation*/) { ; };
virtual bool supportsPaperSizes () { return false; }
virtual QStringList paperSizes () { return QStringList(); }
virtual void setPaperSize (QValueVector<KPDFPage*> & /*pagesVector*/, int /*newsize*/) { ; }
// internal search and gettext
virtual RegularAreaRect * findText( const QString & /*text*/, SearchDir /*dir*/, const bool /*strictCase*/,

56
core/misc.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef _KPDF_MISC_H_
#define _KPDF_MISC_H_
#include "area.h"
/**
@short Wrapper around the information needed to generate the selection area
There are two assumptions inside this class:
1. the start never changes, one instance of this class is used for one selection,
therefore the start of the selection will not change, only end and direction of
the selection will change.
By direction we mean the direction in which the end moves in relation to the start,
forward selection is when end is after the start, backward when its before.
2. The following changes might appear during selection:
a. the end moves without changing the direction (it can move up and down but not past the start):
only itE will be updated
b. the end moves with changing the direction then itB becomes itE if the previous direction was forward
or itE becomes itB
3. Internally it that is related to the start cursor is always at it[0] while it related to end is it[1],
transition between meanings (itB/itE) is done with dir modifier;
*/
class TextSelection
{
public:
TextSelection (NormalizedPoint &a, NormalizedPoint &b)
{
if (b.y-a.y<0 || (b.y-a.y==0 && b.x-a.x <0))
direction=1;
else
direction=0;
cur[0]=a,cur[1]=b;
it[direction%2]=-1,it[(direction+1)%2]=-1;
};
void end (NormalizedPoint & p)
{
// changing direction as in 2b , assuming the bool->int conversion is correct
int dir1=direction;
direction = (p.y-cur[0].y<0 || (p.y-cur[0].y==0 && p.x-cur[0].x <0));
if (direction!=dir1)
kdDebug() << "changing direction in selection\n";
cur[1]=p;
}
void itE (int p) { it[(direction+1)%2]=p; }
void itB (int p) { it[(direction)%2]=p; }
int dir () { return direction; }
const NormalizedPoint * start() {return &cur[direction%2];};
const NormalizedPoint * end() {return &cur[(direction+1)%2];};
int itB() {return it[direction%2];}
int itE() {return it[(direction+1)%2];}
private:
int direction;
int it[2];
NormalizedPoint cur[2];
};
#endif

View file

@ -24,7 +24,7 @@
// temp includes
#include <sys/time.h>
class TextSelection;
/** class KPDFPage **/
@ -75,6 +75,13 @@ bool KPDFPage::hasBookmark() const
return m_bookmarked;
}
RegularAreaRect * KPDFPage::getTextArea ( TextSelection * sel ) const
{
if (m_text)
return m_text->getTextArea (sel);
return 0;
}
bool KPDFPage::hasObjectRect( double x, double y ) const
{
if ( m_rects.count() < 1 )

View file

@ -21,7 +21,7 @@ class QDomDocument;
class KPDFPageTransition;
class Annotation;
class KPDFTextPage;
class TextSelection;
// didnt work with forward declarations
#include "area.h"
#include "textpage.h"
@ -34,6 +34,7 @@ class HighlightAreaRect;
class ObjectRect;
*/
/**
* @short Collector for all the data belonging to a page.
*
@ -68,6 +69,7 @@ class KPDFPage
RegularAreaRect * findText( const QString & text, SearchDir dir, bool strictCase, const RegularAreaRect * lastRect=0) const;
QString * getText( const RegularAreaRect * rect ) const;
RegularAreaRect * getTextArea ( TextSelection * ) const;
// const ObjectRect * getObjectRect( double x, double y ) const;
const ObjectRect * getObjectRect( ObjectRect::ObjectType type, double x, double y ) const;
//const Annotation * getAnnotation( double x, double y ) const;

View file

@ -8,6 +8,7 @@
***************************************************************************/
#include "textpage.h"
#include "area.h"
#include "misc.h"
#include <kdebug.h>
KPDFTextPage::~KPDFTextPage()
@ -19,6 +20,122 @@ KPDFTextPage::~KPDFTextPage()
}
}
RegularAreaRect * KPDFTextPage::getTextArea ( TextSelection * sel) const
{
/**
It works like this:
There are two cursors, we need to select all the text between them. The coordinates are normalised, leftTop is (0,0)
rightBottom is (1,1), so for cursors start (sx,sy) and end (ex,ey) we start with finding text rectangles under those
points, if not we search for the first that is to the right to it in the same baseline, if none found, then we search
for the first rectangle with a baseline under the cursor, having two points that are the best rectangles to both
of the cursors: (rx,ry)x(tx,ty) for start and (ux,uy)x(vx,vy) for end, we do a
1. (rx,ry)x(1,ty)
2. (0,ty)x(1,uy)
3. (0,uy)x(vx,vy)
To find the closest rectangle to cursor (cx,cy) we search for a rectangle that either contains the cursor
or that has a left border >= cx and bottom border >= cy.
*/
RegularAreaRect * ret= new RegularAreaRect;
int it=-1,itB=-1,itE=-1;
// if (sel->itB==-1)
// ending cursor is higher then start cursor, we need to find positions in reverse
NormalizedRect *tmp=0,*start=0,*end=0;
const NormalizedPoint * startC=sel->start();
const NormalizedPoint * endC=sel->end();
if (sel->dir() == 1 || (sel->itB()==-1 && sel->dir()==0))
{
kdWarning() << "running first loop\n";
for (it=0;it<m_words.count();it++)
{
tmp=m_words[it]->area;
if (tmp->contains(startC->x,startC->y)
|| ( tmp->top <= startC->y && tmp->bottom >= startC->y && tmp->left >= startC->x )
|| ( tmp->top >= startC->y))
{
/// we have found the (rx,ry)x(tx,ty)
itB=it;
kdWarning() << "start is " << itB << " count is " << m_words.count() << endl;
break;
}
}
sel->itB(itB);
}
itB=sel->itB();
kdWarning() << "direction is " << sel->dir() << endl;
kdWarning() << "reloaded start is " << itB << " against " << sel->itB() << endl;
if (sel->dir() == 0 || (sel->itE() == -1 && sel->dir()==1))
{
kdWarning() << "running second loop\n";
for (it=m_words.count()-1; it>=itB;it--)
{
tmp=m_words[it]->area;
if (tmp->contains(endC->x,endC->y)
|| ( tmp->top <= endC->y && tmp->bottom >= endC->y && tmp->right <= endC->x )
|| ( tmp->bottom <= endC->y))
{
/// we have found the (ux,uy)x(vx,vy)
itE=it;
kdWarning() << "ending is " << itE << " count is " << m_words.count() << endl;
kdWarning () << "conditions " << tmp->contains(endC->x,endC->y) << " "
<< ( tmp->top <= endC->y && tmp->bottom >= endC->y && tmp->right <= endC->x ) << " " <<
( tmp->top >= endC->y) << endl;
break;
}
}
sel->itE(itE);
}
kdWarning() << "reloaded ending is " << itE << " against " << sel->itE() << endl;
if (sel->itB()!=-1 && sel->itE()!=-1)
{
start=m_words[sel->itB()]->area;
end=m_words[sel->itE()]->area;
NormalizedRect first,second,third;/*
first.right=1;
/// if (rx,ry)x(1,ty) intersects the end cursor, there is only one line
bool sameBaseline=end->intersects(first);
kdWarning() << "sameBaseline : " << sameBaseline << endl;
if (sameBaseline)
{
first=*start;
first.right=end->right;
first.bottom=end->bottom;
for (it=QMIN(sel->itB(),sel->itE()); it<=QMAX(sel->itB(),sel->itE());it++)
{
tmp=m_words[it]->area;
if (tmp->intersects(&first))
ret->append(tmp);
}
}
else*/
/// finding out if there are more then one baseline between them is a hard and discussable task
/// we will create a rectangle (rx,0)x(tx,1) and will check how many times does it intersect the
/// areas, if more than one -> we have a three or over line selection
// {
first=*start;
second.top=start->bottom;
first.right=second.right=1;
third=*end;
third.left=second.left=0;
second.bottom=end->top;
for (it=QMIN(sel->itB(),sel->itE()); it<=QMAX(sel->itB(),sel->itE());it++)
{
tmp=m_words[it]->area;
if (tmp->intersects(&first) || tmp->intersects(&second) || tmp->intersects(&third))
ret->append(tmp);
}
// }
}
ret->simplify();
return ret;
}
RegularAreaRect* KPDFTextPage::findText(const QString &query, SearchDir & direct,
@ -173,36 +290,13 @@ RegularAreaRect* KPDFTextPage::findTextInternal(const QString &query, bool forwa
queryLeft-=min;
}
}
if (haveMatch && queryLeft==0 && j==query.length())
if (haveMatch && queryLeft==0 && j==query.length())
{
// RegularAreaRect::ConstIterator i=ret->begin(), end=ret->end;
int end=ret->count(),i=0,x=0;
QValueList <NormalizedRect*> m_remove;
for (;i<end;i++)
{
if ( i < (end-1) )
{
if ( (*ret)[x]->intersects( (*ret)[i+1] ) )
{
(*ret)[x]->left=(QMIN((*ret)[x]->left,(*ret)[i+1]->left));
(*ret)[x]->top=(QMIN((*ret)[x]->top,(*ret)[i+1]->top));
(*ret)[x]->bottom=(QMAX((*ret)[x]->bottom,(*ret)[i+1]->bottom));
(*ret)[x]->right=(QMAX((*ret)[x]->right,(*ret)[i+1]->right));
m_remove.append( (*ret)[i+1] );
}
else
{
x=i;
}
}
}
while (!m_remove.isEmpty())
{
ret->remove( m_remove.last() );
m_remove.pop_back();
}
ret->simplify();
return ret;
}
}
return 0;
}
@ -220,6 +314,7 @@ QString * KPDFTextPage::getText(const RegularAreaRect *area)
// provide the string FIXME?: newline handling
if (area->intersects((*it)->area))
{
// kdDebug()<< "[" << (*it)->area->left << "," << (*it)->area->top << "]x["<< (*it)->area->right << "," << (*it)->area->bottom << "]\n";
*ret += ((*it)->txt);
last=*it;
}

View file

@ -14,6 +14,7 @@
#include <qvaluelist.h>
#include <qstringlist.h>
#include "area.h"
class TextSelection;
/*! @enum SearchDir
* The enum holding the direction of searching.
@ -52,8 +53,7 @@ struct KPDFTextEntity
//
QString txt;
NormalizedRect* area;
int rotation;
KPDFTextEntity(QString text, NormalizedRect* ar, int rot) : txt(text), rotation(rot)
KPDFTextEntity(QString text, NormalizedRect* ar) : txt(text)
{ area=ar; };
~KPDFTextEntity() { delete area; };
};
@ -63,10 +63,11 @@ class KPDFTextPage {
RegularAreaRect* findText(const QString &query, SearchDir & direct,
const bool &strictCase, const RegularAreaRect *area);
QString * getText(const RegularAreaRect *rect);
RegularAreaRect * getTextArea ( TextSelection* ) const;
KPDFTextPage(QValueList<KPDFTextEntity*> words) : m_words(words) {};
KPDFTextPage() : m_words() {};
void append(QString txt, NormalizedRect* area, int rot)
{ m_words.append(new KPDFTextEntity(txt,area,rot) ); };
void append(QString txt, NormalizedRect* area)
{ m_words.append(new KPDFTextEntity(txt,area) ); };
~KPDFTextPage();
private:
RegularAreaRect * findTextInternal(const QString &query, bool forward,
@ -74,4 +75,6 @@ class KPDFTextPage {
QValueList<KPDFTextEntity*> m_words;
};
#endif

View file

@ -23,6 +23,7 @@
#include <klocale.h>
#include <qfileinfo.h>
#include <qpainter.h>
#include <qpaintdevice.h>
#include "faxrenderer.h"
#include "core/page.h"
@ -33,7 +34,7 @@ KPDF_EXPORT_PLUGIN(FaxRenderer)
FaxRenderer::FaxRenderer(KPDFDocument * doc)
: Generator( doc )
{
;
kdWarning() << "fax generator has landed" <<endl;
}
void FaxRenderer::generatePixmap( PixmapRequest * request )
@ -49,9 +50,10 @@ void FaxRenderer::generatePixmap( PixmapRequest * request )
// Wait for all access to this documentRenderer to finish
QPixmap* pix = new QPixmap();
QPixmap* pix = new QPixmap(request->width,request->height);
pix->fill();
QPainter p(pix);
QImage img = fax.page(request->pageNumber-1);
QImage img = fax.page(request->pageNumber).smoothScale(request->width,request->height);
p.drawImage( 0,0, img, 0,0,img.width(),img.height());
/*
SimplePageSize psize = pageSizes[page->getPageNumber() - 1];
@ -94,12 +96,12 @@ bool FaxRenderer::loadDocument( const QString & fileName, QValueVector< KPDFPage
#endif
// Wait for all access to this documentRenderer to finish
mutex.lock();
// mutex.lock();
// Now we assume that the file is fine and load the file into the
// fax member. We abort on error and give an error message.
bool ok = fax.loadImage(fileName);
kdWarning(1000) << "fax " << fileName << " loaded ok: " << ok <<endl;
// It can happen that fax.loadImage() returns with 'ok == true', but
// still the file could NOT be loaded. This happens, e.g. for TIFF
// file that do NOT contain FAX, but other image formats. We handle
@ -119,7 +121,7 @@ bool FaxRenderer::loadDocument( const QString & fileName, QValueVector< KPDFPage
temp=i18n("Error while opening file: %1.").arg(fax.errorString());
emit error (temp,-1);
}
mutex.unlock();
// mutex.unlock();
return false;
}
@ -131,8 +133,7 @@ bool FaxRenderer::loadDocument( const QString & fileName, QValueVector< KPDFPage
{
QSize pageSize = fax.page_size(pg);
// how about rotation?
pagesVector[pg] = new KPDFPage(pg, pageSize.width(), pageSize.height(),0);
/*
QPoint dpi = fax.page_dpi(pg);
double dpix = dpi.x();
double dpiy = dpi.y();
@ -141,14 +142,12 @@ bool FaxRenderer::loadDocument( const QString & fileName, QValueVector< KPDFPage
kdError() << "File invalid resolutions, dpi x = " << dpix << ", dpi y = " << dpiy << ". This information will be ignored and 75 DPI assumed." << endl;
dpix = dpiy = 75.0;
}
w.setLength_in_inch(pageSize.width() / dpix);
h.setLength_in_inch(pageSize.height() / dpiy);
pageSizes[pg].setPageSize(w, h);*/
pagesVector[pg] = new KPDFPage(pg, QPaintDevice::x11AppDpiX () * pageSize.width() / dpix,
QPaintDevice::x11AppDpiX () * pageSize.height()/dpiy,0);
}
// the return value 'true' indicates that this operation was not successful.
mutex.unlock();
// mutex.unlock();
return true;
}

View file

@ -6,6 +6,6 @@ Comment=Fax backend for oKular
ServiceTypes=oKular/Generator
MimeType=image/fax-g3;image/tiff;
X-KDE-Library=libokularGenerator_fax.la
X-KDE-Priority=1
X-KDE-Priority=4
X-KDE-oKularAPIVersion=1
X-KDE-oKularHasInternalSettings=false

View file

@ -11,6 +11,7 @@
#include <qfile.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qsize.h>
#include <qtoolbox.h>
@ -182,8 +183,8 @@ bool GSGenerator::loadDocument( const QString & fileName, QValueVector< KPDFPage
if( !pixGenerator )
{
pixGenerator = new GSInterpreterLib ();
connect (pixGenerator, SIGNAL (Finished(const QImage* img)),
this, SLOT(slotPixmapGenerated (const QImage* img)));
connect (pixGenerator, SIGNAL (Finished(const QImage*)),
this, SLOT(slotPixmapGenerated (const QImage*)));
if ( GSSettings::messages() )
{
@ -216,17 +217,22 @@ bool GSGenerator::loadDocument( const QString & fileName, QValueVector< KPDFPage
void GSGenerator::slotPixmapGenerated(const QImage* img)
{
QPixmap *pix=new QPixmap(m_sRequest->width, m_asRequest->height);
QPainter p(pix);
syncLock.unlock();
kdWarning() << "SlotSyncGenerated! - finished m_sRequest id=" << m_sRequest->id << " " <<m_sRequest->width << "x" << m_sRequest->height << "@" << m_sRequest->pageNumber << " async == " << m_sRequest->async << endl;
QPixmap * rPix;
rPix = new QPixmap(img->size());
rPix->fill();
QPainter p(rPix);
p.drawImage(0,0,*img,0,0,img->width(),img->height());
docLock.unlock();
m_sRequest->page->setPixmap( m_sRequest->id, pix );
p.end();
m_sRequest->page->setPixmap( m_sRequest->id, rPix );
signalRequestDone( m_sRequest );
}
void GSGenerator::slotAsyncPixmapGenerated(QPixmap * pix)
{
docLock.unlock();
kdWarning() << "SlotASyncGenerated!\n";
m_asRequest->page->setPixmap( m_asRequest->id, pix );
signalRequestDone( m_asRequest );
}
@ -324,6 +330,7 @@ bool GSGenerator::initInterpreter()
{
if( pixGenerator->start() && internalDoc->dsc()->isStructured() )
{
// this 0 is ok here, we will not be getting a PAGE anwser from those
pixGenerator->run ( internalDoc->file() , internalDoc->prolog(), false);
pixGenerator->unlock();
@ -344,51 +351,69 @@ bool GSGenerator::loadDocumentWithDSC( QString & name, QValueVector< KPDFPage *
void GSGenerator::generatePixmap( PixmapRequest * req )
{
kdDebug() << req << endl;
kdWarning() << "receiving req id=" << req->id << " " <<req->width << "x" << req->height << "@" << req->pageNumber << " async == " << req->async << endl;
int pgNo=req->pageNumber;
if ( req->async )
if ( false )
{
docLock.lock();
return ;
m_asRequest=req;
kdWarning() << "setOrientation\n";
asyncGenerator->setOrientation(rotation (internalDoc->orientation(pgNo)));
// asyncGenerator->setBoundingBox( internalDoc->boundingBox(i));
kdWarning() << "setSize\n";
asyncGenerator->setSize(req->width ,req->height);
kdWarning() << "setMedia\n";
asyncGenerator->setMedia( internalDoc -> getPaperSize ( internalDoc -> pageMedia( pgNo )) );
kdWarning() << "setMagnify\n";
asyncGenerator->setMagnify(QMAX(static_cast<double>(req->width)/req->page->width() ,
static_cast<double>(req->height)/req->page->height()));
GSInterpreterLib::Position u=internalDoc->pagePos(pgNo);
kdDebug() << "Page pos is " << pgNo << ":"<< u.first << "/" << u.second << endl;
// kdWarning () << "Page pos is " << pgNo << ":"<< u.first << "/" << u.second << endl;
if (!asyncGenerator->running())
{
if ( internalDoc->dsc()->isStructured() )
{
kdWarning() << "setStructure\n";
asyncGenerator->setStructure( internalDoc->prolog() , internalDoc->setup() );
kdDebug () << "sending init" << endl;
}
asyncGenerator->start();
if (!asyncGenerator->running())
{
kdWarning() << "start after structure\n";
asyncGenerator->startInterpreter();
}
}
kdWarning() << "run pagepos\n";
asyncGenerator->run (internalDoc->pagePos(pgNo));
return;
}
m_sRequest=req;
pixGenerator->setOrientation(rotation (internalDoc->orientation(pgNo)));
// pixGenerator->setBoundingBox( internalDoc->boundingBox(i));
pixGenerator->setSize(req->width ,req->height);
pixGenerator->setMedia( internalDoc -> getPaperSize ( internalDoc -> pageMedia( pgNo )) );
pixGenerator->setMagnify(QMAX(static_cast<double>(req->width)/req->page->width() ,
static_cast<double>(req->height)/req->page->height()));
if (!pixGenerator->running())
else
{
syncLock.lock();
disconnect (pixGenerator, SIGNAL (Finished(const QImage*)),
this, SLOT(slotPixmapGenerated (const QImage*)));
m_sRequest=req;
pixGenerator->setOrientation(rotation (internalDoc->orientation(pgNo)));
// pixGenerator->setBoundingBox( internalDoc->boundingBox(i));
pixGenerator->setSize(req->width ,req->height);
pixGenerator->setMedia( internalDoc -> getPaperSize ( internalDoc -> pageMedia( pgNo )) );
pixGenerator->setMagnify(QMAX(static_cast<double>(req->width)/req->page->width() ,
static_cast<double>(req->height)/req->page->height()));
if (!pixGenerator->running())
{
initInterpreter();
pixGenerator->run ( internalDoc->file() , internalDoc->pagePos(pgNo));
}
connect (pixGenerator, SIGNAL (Finished(const QImage*)),
this, SLOT(slotPixmapGenerated (const QImage*)));
pixGenerator->run ( internalDoc->file() , internalDoc->pagePos(pgNo));
}
}
bool GSGenerator::canGeneratePixmap( bool async )
{
if (async) return ! docLock.locked();
return ( pixGenerator ) ? pixGenerator->ready() : true;
// kdWarning () << "ready Async/Sync " << (! docLock.locked()) << "/ " << (( pixGenerator ) ? !syncLock.locked() : true) << " asking for async: " << async << endl;
// if (async) return false;
return ( pixGenerator ) ? ! syncLock.locked() : true;
}
const DocumentInfo * GSGenerator::generateDocumentInfo()

View file

@ -94,6 +94,7 @@ class GSGenerator : public Generator
int angle( CDSC_ORIENTATION_ENUM orientation );
CDSC_ORIENTATION_ENUM orientation( int rot );
QMutex docLock;
QMutex syncLock;
bool m_asyncBusy;
// pixmap requests

View file

@ -184,7 +184,7 @@ bool GSInterpreterCMD::stop(bool async)
return true;
}
bool GSInterpreterCMD::start()
bool GSInterpreterCMD::startInterpreter()
{
kdDebug(4655) << "start()" << endl;
if ( m_process && m_process->isRunning() )
@ -335,6 +335,7 @@ bool GSInterpreterCMD::run( GSInterpreterLib::Position pos)
}
// the pixmap to which the generated image will be copied
m_pixmap = new QPixmap (m_width, m_height);
m_pixmap -> fill();
m_info.pos=pos;
m_info.sync=true;
@ -389,12 +390,17 @@ void GSInterpreterCMD::run()
}
}
#include <qdialog.h>
#include <qpainter.h>
void GSInterpreterCMD::customEvent( QCustomEvent * e )
{
if (e->type() == GS_DATAREADY_ID )
{
kdDebug(4655) << "emitting signal" << endl;
emit Finished(m_pixmap);
QPixmap *pix=takePixmap();
emit Finished(pix);
}
}

View file

@ -44,7 +44,7 @@ class GSInterpreterCMD : public QObject , public QThread
GSInterpreterCMD( const QString & fileName);
~GSInterpreterCMD();
QPixmap* takePixmap();
bool start();
bool startInterpreter();
bool stop(bool async=true);
bool ready() { return !interpreterLock.locked() ; } ;
bool running ();

View file

@ -25,7 +25,7 @@
#include <X11/Xlib.h>
#include <fixx11h.h>
// #include <qdialog.h>
GSInterpreterLib *interpreter;
int mem;
@ -35,12 +35,17 @@ FILE * f;
void PixHandler::slotPixmap(const QImage* img)
{
QPixmap *pix=new QPixmap(img->size(), img->depth());
kdDebug() << "Handles: " << pix->handle() << " " << pData.handle <<endl;
QPainter p;
p.begin(pix);
p.drawImage(0,0,*img, 0,0,img->width(),img->height());
p.end();
QPixmap *pix=new QPixmap();
kdWarning() << "img size/depth " << img->size() << "/" <<img->depth() << endl;
bool done=pix->convertFromImage(*img);
kdWarning () << "Conversion from qimage " << done << endl;
// QDialog t;
// t.resize(pix->width(),pix->height());
// t.setBackgroundPixmap(*pix);
// t.update();
// t.exec();
XCopyArea
(qt_xdisplay(),
pix->handle(),
@ -62,7 +67,7 @@ void process()
{
read ( mem, &pData, sizeof(pData) );
if ( !interpreter->running() )
if ( ! ( interpreter->running() ) )
interpreter->start(false);
// kdDebug() << "Processing: " << pData.sync << endl;
@ -76,6 +81,7 @@ void process()
int main (int argc, char* argv[])
{
KApplication app(argc,argv,QCString("kpdflibgsasyncgenerator"));
// Order of argv: fileName, msgQueueId, media type, magnify, orientation
for (int i=0;i<argc;i++)
@ -89,10 +95,12 @@ int main (int argc, char* argv[])
interpreter->setSize ( QString(argv[7]).toInt(), QString(argv[8]).toInt() );
interpreter->setPlatformFonts ( QString(argv[9]).toInt() !=0 );
interpreter->setAABits(QString(argv[10]).toInt(), QString(argv[11]).toInt() );
KApplication app(argc,argv,QCString("kpdflibgsasyncgenerator"));
interpreter->setProgressive(false);
interpreter->start(false);
PixHandler pxHandler;
QObject::connect(interpreter,SIGNAL(Finished(const QImage* img)),&pxHandler,SLOT(slotPixmap(const QImage* img)));
QObject::connect(interpreter,SIGNAL(Finished(const QImage* )),&pxHandler,SLOT(slotPixmap(const QImage* )));
int request;
anwser = open( argv[3] , O_RDWR );

View file

@ -7,7 +7,7 @@ INCLUDES = -I$(srcdir)/../.. -I$(srcdir)/xpdf -I$(srcdir)/xpdf/goo -I$(srcdir)/x
libokularGenerator_xpdf_la_LIBADD = $(top_builddir)/kpdf/core/liboKularcore.la $(top_builddir)/kpdf/conf/liboKularconf.la \
$(top_builddir)/kpdf/generators/xpdf/xpdf/xpdf/libxpdf.la \
$(LIB_KDEPRINT) $(LIB_KDEUI)
$(LIB_KDEPRINT) $(LIB_KDEUI) -lm
libokularGenerator_xpdf_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
libokularGenerator_xpdf_la_SOURCES = generator_pdf.cpp gp_outputdev.cpp

View file

@ -15,6 +15,7 @@
#include <qapplication.h>
#include <qpaintdevicemetrics.h>
#include <qregexp.h>
#include <qpoint.h>
#include <kapplication.h>
#include <klocale.h>
#include <kpassdlg.h>
@ -204,16 +205,19 @@ void PDFGenerator::loadPages(QValueVector<KPDFPage*> &pagesVector, int rotation,
{
// TODO XPDF 3.01 check
// KPDFTextDev td;
int count=pagesVector.count();
int count=pagesVector.count(),w=0,h=0;
for ( int i = 0; i < count ; i++ )
{
// get xpdf page
Page * p = pdfdoc->getCatalog()->getPage( i + 1 );
w=pdfdoc->getPageCropWidth(i+1);
h=pdfdoc->getPageCropHeight(i+1);
if (rotation==-1)
rotation=pdfdoc->getPageRotate(i+1)/90;
if (rotation%2==1)
qSwap(w,h);
// init a kpdfpage, add transition and annotations informations
KPDFPage * page = new KPDFPage( i, pdfdoc->getPageCropWidth(i+1),
pdfdoc->getPageCropHeight(i+1),
(rotation==-1) ? pdfdoc->getPageRotate(i+1) : 0 );
KPDFPage * page = new KPDFPage( i, w, h, rotation );
addTransition( p, page );
if ( true ) //TODO real check
addAnnotations( p, page );
@ -239,11 +243,11 @@ TextPage * PDFGenerator::fastTextPage (KPDFPage * page)
// fetch ourselves a textpage
TextOutputDev td(NULL, gTrue, gFalse, gFalse);
docLock.lock();
pdfdoc->displayPage( &td, page->number()+1, 72, 72, page->rotation(), false, true, false );
pdfdoc->displayPage( &td, page->number()+1, 72, 72, page->rotation()*90, false, true, false );
// ..and attach it to the page
TextPage *p=td.takeText();
if (prefersInternalSearching())
page->setSearchPage( abstractTextPage(p, page->height(), page->width()) );
page->setSearchPage( abstractTextPage(p, page->height(), page->width(),page->rotation()) );
docLock.unlock();
return p;
}
@ -252,15 +256,11 @@ QString * PDFGenerator::getText( const RegularAreaRect * area, KPDFPage * page
{
TextPage* textPage=fastTextPage (page);
int left,right,bottom,top;
// int left,right,bottom,top;
QString * text = new QString;
// when using internal stuff we just have
NormalizedRect * rect = area->first();
left = (int)( rect->left * page->width() );
top = (int)( rect->top * page->height() );
right = (int)( rect->right * page->width() );
bottom = (int)( rect->bottom * page->height() );
*text= textPage->getText( left, top, right, bottom )->getCString();
QRect rect = area->first()->geometry(page->width(),page->height());
*text= textPage->getText( rect.left(), rect.top(), rect.right(), rect.bottom() )->getCString();
return text;
}
@ -496,7 +496,7 @@ void PDFGenerator::generatePixmap( PixmapRequest * request )
// note: thread safety is set on 'false' for the GUI (this) thread
kpdfOutputDev->setParams( request->width, request->height, genObjectRects, genObjectRects, false );
// TODO: check if this should not get a rotation parameter
pdfdoc->displayPage( kpdfOutputDev, page->number() + 1, fakeDpiX, fakeDpiY, page->rotation(),
pdfdoc->displayPage( kpdfOutputDev, page->number() + 1, fakeDpiX, fakeDpiY, page->rotation()*90,
false, true, genObjectRects );
// 2. Take data from outputdev and attach it to the Page
@ -510,7 +510,7 @@ void PDFGenerator::generatePixmap( PixmapRequest * request )
if ( genTextPage )
{
TextOutputDev td(NULL, gTrue, gFalse, gFalse);
page->setSearchPage( abstractTextPage(td.takeText(), page->height(), page->width()) );
page->setSearchPage( abstractTextPage(td.takeText(), page->height(), page->width(),page->rotation()) );
}
// update ready state
ready = true;
@ -529,9 +529,9 @@ void PDFGenerator::generateSyncTextPage( KPDFPage * page )
// build a TextPage...
TextOutputDev td(NULL, gTrue, gFalse, gFalse);
docLock.lock();
pdfdoc->displayPage( &td, page->number()+1, 72, 72, page->rotation(), false, true, false );
pdfdoc->displayPage( &td, page->number()+1, 72, 72, page->rotation()*90, false, true, false );
// ..and attach it to the page
page->setSearchPage( abstractTextPage(td.takeText(), page->height(), page->width()) );
page->setSearchPage( abstractTextPage(td.takeText(), page->height(), page->width(),page->rotation()) );
docLock.unlock();
}
@ -672,43 +672,36 @@ static QString unicodeToQString(const Unicode* u, int len) {
}
inline void append (KPDFTextPage* ktp,
QString s, double l, double b, double r, double t, double rot)
QString s, double l, double b, double r, double t)
{
// kdWarning() << "text: " << s << " at (" << l << "," << t << ")x(" << r <<","<<b<<")" << endl;
ktp->append( s ,
new NormalizedRect(
l,
b,
r,
t
),
static_cast<int>(rot));
));
}
KPDFTextPage * PDFGenerator::abstractTextPage(TextPage *tp, double height, double width)
{
KPDFTextPage * PDFGenerator::abstractTextPage(TextPage *tp, double height, double width,int rot)
{
KPDFTextPage* ktp=new KPDFTextPage;
TextWordList *list = tp->makeWordList(true);
TextWord * word, *next;
int wordCount=list->getLength();
kdWarning() << "getting text page in generator pdf - rotation: " << rot << endl;
int charCount=0;
int i,j,rot;
QString s,t;
int i,j;
QString s;
NormalizedRect * wordRect = new NormalizedRect;
for (i=0;i<wordCount;i++)
{
word=list->get(i);
word->getBBox(&wordRect->left,&wordRect->bottom,&wordRect->right,&wordRect->top);
charCount=word->getLength();
rot=word->getRotation();
next=word->nextWord();
if ( word->hasSpaceAfter() == gTrue && next )
t=" ";
else if ( !next )
t="\n";
else
t="";
switch (rot)
{
case 0:
@ -717,15 +710,23 @@ KPDFTextPage * PDFGenerator::abstractTextPage(TextPage *tp, double height, doubl
for (j=0;j<charCount;j++)
{
s=unicodeToQString( word->getChar(j),1);
append(ktp, s+t,
append(ktp, (j==charCount-1 && !next ) ? (s + "\n") : s,
// this letters boundary
word->getEdge(j)/width,
wordRect->bottom/height,
// next letters boundary
word->getEdge(j+1)/width,
wordRect->top/height,
rot);
wordRect->top/height);
}
if ( word->hasSpaceAfter() == gTrue && next )
append(ktp, " ",
// this letters boundary
word->getEdge(charCount)/width,
wordRect->bottom/height,
// next letters boundary
next->getEdge(0)/width,
wordRect->top/height);
break;
case 1:
@ -734,13 +735,21 @@ KPDFTextPage * PDFGenerator::abstractTextPage(TextPage *tp, double height, doubl
for (j=0;j<charCount;j++)
{
s=unicodeToQString( word->getChar(j),1);
append(ktp, s+t,
append(ktp, (j==charCount-1 && !next ) ? (s + "\n") : s,
wordRect->left/width,
word->getEdge(j)/height,
wordRect->right/width,
word->getEdge(j+1)/height,
rot);
word->getEdge(j+1)/height);
}
if ( word->hasSpaceAfter() == gTrue && next )
append(ktp, " ",
// this letters boundary
wordRect->left/width,
word->getEdge(charCount)/height,
// next letters boundary
wordRect->right/width,
next->getEdge(0)/height);
break;
case 2:
@ -748,27 +757,44 @@ KPDFTextPage * PDFGenerator::abstractTextPage(TextPage *tp, double height, doubl
for (j=0;j<charCount;j++)
{
s=unicodeToQString( word->getChar(j),1);
append(ktp, s+t,
append(ktp, (j==charCount-1 && !next ) ? (s + "\n") : s,
word->getEdge(j+1)/width,
wordRect->bottom/height,
word->getEdge(j)/width,
wordRect->top/height,
rot);
wordRect->top/height);
}
if ( word->hasSpaceAfter() == gTrue && next )
append(ktp, " ",
// this letters boundary
next->getEdge(0)/width,
wordRect->bottom/height,
// next letters boundary
word->getEdge(charCount)/width,
wordRect->top/height);
break;
case 3:
for (j=0;j<charCount;j++)
{
s=unicodeToQString( word->getChar(j),1);
append(ktp, s+t,
append(ktp, (j==charCount-1 && !next ) ? (s + "\n") : s,
wordRect->left/width,
word->getEdge(j+1)/height,
wordRect->right/width,
word->getEdge(j)/height,
rot);
word->getEdge(j)/height);
}
if ( word->hasSpaceAfter() == gTrue && next )
append(ktp, " ",
// this letters boundary
wordRect->left/width,
next->getEdge(0)/height,
// next letters boundary
wordRect->right/width,
word->getEdge(charCount)/height);
break;
}
}
@ -2084,7 +2110,7 @@ void PDFGenerator::customEvent( QCustomEvent * event )
delete outImage;
if ( outTextPage )
request->page->setSearchPage( abstractTextPage( outTextPage ,
request->page->height(), request->page->width()));
request->page->height(), request->page->width(),request->page->rotation()));
if ( !outRects.isEmpty() )
request->page->setObjectRects( outRects );
@ -2229,7 +2255,7 @@ void PDFPixmapGeneratorThread::run()
d->generator->kpdfOutputDev->setParams( width, height,
genObjectRects, genObjectRects, TRUE /*thread safety*/ );
d->generator->pdfdoc->displayPage( d->generator->kpdfOutputDev, page->number() + 1,
fakeDpiX, fakeDpiY, d->currentRequest->rotation , false,true, genObjectRects );
fakeDpiX, fakeDpiY, d->currentRequest->rotation*90 , false,true, genObjectRects );
// 2. grab data from the OutputDev and store it locally (note takeIMAGE)
#ifndef NDEBUG
@ -2245,7 +2271,7 @@ void PDFPixmapGeneratorThread::run()
if ( genTextPage )
{
TextOutputDev td(NULL, gTrue, gFalse, gFalse);
d->generator->pdfdoc->displayPage( &td, page->number()+1, 72, 72, page->rotation(), false, true, false );
d->generator->pdfdoc->displayPage( &td, page->number()+1, 72, 72, page->rotation()*90, false, true, false );
// ..and attach it to the page
d->m_textPage = td.takeText();
}

View file

@ -115,7 +115,7 @@ class PDFGenerator : public Generator
// fetch the transition information and add it to the page
void addTransition( Page * xpdfPage, KPDFPage * page );
static KPDFTextPage * abstractTextPage(TextPage *tp, double height, double width);
static KPDFTextPage * abstractTextPage(TextPage *tp, double height, double width, int rot);
TextPage * fastTextPage (KPDFPage * page);
// (async related) receive data from the generator thread

1
part.h
View file

@ -170,6 +170,7 @@ private:
KToggleAction* m_showMenuBarAction;
KToggleAction* m_showLeftPanel;
KToggleAction* m_showFullScreenAction;
bool m_actionsSearched;
bool m_searchStarted;
BrowserExtension *m_bExtension;

View file

@ -24,7 +24,10 @@
<Action name="zoom_fit_rect"/>
<Separator/>
<Action name="view_continuous"/>
<Action name="view_twopages"/>
<Action name="view_render_mode"/>
<Separator/>
<Action name="view_orientation"/>
<Action name="view_papersizes"/>
</Menu>
<Menu name="go"><text>&amp;Go</text>
<Action name="previous_page"/>

View file

@ -16,6 +16,10 @@
* (at your option) any later version. *
***************************************************************************/
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
#include <fixx11h.h>
// qt/kde includes
#include <qcursor.h>
#include <qpainter.h>
@ -50,6 +54,7 @@
#include "pageviewannotator.h"
#include "core/document.h"
#include "core/page.h"
#include "core/misc.h"
#include "core/link.h"
#include "core/generator.h"
#include "conf/settings.h"
@ -74,13 +79,19 @@ public:
PageView::MouseMode mouseMode;
QPoint mouseGrabPos;
QPoint mousePressPos;
QPoint mouseSelectPos;
bool mouseMidZooming;
int mouseMidLastY;
bool mouseSelecting;
QRect mouseSelectionRect;
QColor mouseSelectionColor;
bool mouseTextSelecting;
bool mouseTextSelectionPainted;
QValueList<QRect>* mouseTextSelectionRect;
QColor mouseTextSelectionColor;
TextSelection * mouseTextSelectionInfo;
bool mouseOnRect;
// type ahead find
bool typeAheadActive;
QString typeAheadString;
@ -104,6 +115,7 @@ public:
// actions
KSelectAction * aOrientation;
KSelectAction * aPaperSizes;
KToggleAction * aMouseNormal;
KToggleAction * aMouseSelect;
KToggleAction * aToggleAnnotator;
@ -111,7 +123,7 @@ public:
KToggleAction * aZoomFitWidth;
KToggleAction * aZoomFitPage;
KToggleAction * aZoomFitText;
KToggleAction * aViewTwoPages;
KSelectAction * aRenderMode;
KToggleAction * aViewContinuous;
KAction * aPrevAction;
};
@ -135,11 +147,13 @@ PageView::PageView( QWidget *parent, KPDFDocument *document )
d = new PageViewPrivate();
d->document = document;
d->aOrientation = 0;
d->aRenderMode = 0;
d->zoomMode = (PageView::ZoomMode) KpdfSettings::zoomMode();
d->zoomFactor = KpdfSettings::zoomFactor();
d->mouseMode = MouseNormal;
d->mouseMidZooming = false;
d->mouseSelecting = false;
d->mouseTextSelecting = false;
d->mouseOnRect = false;
d->typeAheadActive = false;
d->findTimeoutTimer = 0;
@ -154,6 +168,10 @@ PageView::PageView( QWidget *parent, KPDFDocument *document )
d->blockPixmapsRequest = false;
d->messageWindow = new PageViewMessage(this);
d->aPrevAction = 0;
d->mouseTextSelectionRect=0;
d->mouseTextSelectionInfo=0;
d->mouseTextSelectionPainted=0;
d->aPaperSizes=0;
// widget setup: setup focus, accept drops and track mouse
viewport()->setFocusProxy( this );
@ -187,8 +205,8 @@ PageView::~PageView()
void PageView::setupActions( KActionCollection * ac )
{
d->aOrientation=new KSelectAction( i18n( "&Orientation" ), 0, this, 0, ac, "orientation_menu" );
d->aOrientation=new KSelectAction( i18n( "&Orientation" ), 0, this, 0, ac, "view_orientation" );
d->aPaperSizes=new KSelectAction( i18n( "&Paper sizes" ), 0, this, 0, ac, "view_papersizes" );
QStringList orientations;
orientations.append( i18n( "Portrait" ) );
orientations.append( i18n( "Landscape" ) );
@ -198,8 +216,14 @@ void PageView::setupActions( KActionCollection * ac )
connect( d->aOrientation , SIGNAL( activated( int ) ),
d->document , SLOT( slotOrientation( int ) ) );
connect( d->aPaperSizes , SIGNAL( activated( int ) ),
d->document , SLOT( slotPaperSizes( int ) ) );
d->aOrientation->setEnabled(d->document->supportsRotation());
bool paperSizes=d->document->supportsPaperSizes();
d->aPaperSizes->setEnabled(paperSizes);
if (paperSizes)
d->aPaperSizes->setItems(d->document->paperSizes());
// Zoom actions ( higher scales takes lots of memory! )
d->aZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, this, SLOT( slotZoom() ), ac, "zoom_to" );
@ -223,9 +247,15 @@ void PageView::setupActions( KActionCollection * ac )
connect( d->aZoomFitText, SIGNAL( toggled( bool ) ), SLOT( slotFitToTextToggled( bool ) ) );
// View-Layout actions
d->aViewTwoPages = new KToggleAction( i18n("&Two Pages"), "view_left_right", 0, ac, "view_twopages" );
connect( d->aViewTwoPages, SIGNAL( toggled( bool ) ), SLOT( slotTwoPagesToggled( bool ) ) );
d->aViewTwoPages->setChecked( KpdfSettings::viewColumns() > 1 );
QStringList renderModes;
renderModes.append( i18n( "Single" ) );
renderModes.append( i18n( "Facing" ) );
renderModes.append( i18n( "Overview" ) );
d->aRenderMode = new KSelectAction( i18n("&Render Mode"), "view_left_right", 0, ac, "view_render_mode" );
connect( d->aRenderMode, SIGNAL( activated( int ) ), SLOT( slotRenderMode( int ) ) );
d->aRenderMode->setItems( renderModes );
d->aRenderMode->setCurrentItem( KpdfSettings::renderMode() );
d->aViewContinuous = new KToggleAction( i18n("&Continuous"), "view_text", 0, ac, "view_continuous" );
connect( d->aViewContinuous, SIGNAL( toggled( bool ) ), SLOT( slotContinuousToggled( bool ) ) );
@ -256,18 +286,18 @@ void PageView::setupActions( KActionCollection * ac )
bool PageView::canFitPageWidth()
{
return KpdfSettings::viewColumns() != 1 || d->zoomMode != ZoomFitWidth;
return KpdfSettings::renderMode() != 0 || d->zoomMode != ZoomFitWidth;
}
void PageView::fitPageWidth( int page )
{
// zoom: Fit Width, columns: 1. setActions + relayout + setPage + update
d->zoomMode = ZoomFitWidth;
KpdfSettings::setViewColumns( 1 );
KpdfSettings::setRenderMode( 0 );
d->aZoomFitWidth->setChecked( true );
d->aZoomFitPage->setChecked( false );
d->aZoomFitText->setChecked( false );
d->aViewTwoPages->setChecked( false );
d->aRenderMode->setCurrentItem( 0 );
viewport()->setUpdatesEnabled( false );
slotRelayoutPages();
viewport()->setUpdatesEnabled( true );
@ -309,7 +339,7 @@ void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool doc
if ( !documentChanged )
return;
}
// delete all widgets (one for each page in pageSet)
QValueVector< PageViewItem * >::iterator dIt = d->items.begin(), dEnd = d->items.end();
for ( ; dIt != dEnd; ++dIt )
@ -320,7 +350,12 @@ void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool doc
// create children widgets
QValueVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end();
for ( ; setIt != setEnd; ++setIt )
{
d->items.push_back( new PageViewItem( *setIt ) );
#ifdef PAGEVIEW_DEBUG
kdDebug() << "geom for " << d->items.last()->pageNumber() << " is " << d->items.last()->geometry() << endl;
#endif
}
// invalidate layout so relayout/repaint will happen on next viewport change
if ( pageSet.count() > 0 )
@ -329,7 +364,7 @@ void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool doc
// Need slotRelayoutPages() here instead of d->dirtyLayout = true
// because opening a pdf from another pdf will not trigger a viewportchange
// so pages are never relayouted
QTimer::singleShot(0, this, SLOT(slotRelayoutPages()));
QTimer::singleShot(0, this, SLOT(slotRelayoutPages())); // was used
else
{
// update the mouse cursor when closing because we may have close through a link and
@ -347,6 +382,10 @@ void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool doc
PageViewMessage::Info, 4000 );
d->aOrientation->setEnabled(d->document->supportsRotation());
bool paperSizes=d->document->supportsPaperSizes();
d->aPaperSizes->setEnabled(paperSizes);
if (paperSizes)
d->aPaperSizes->setItems(d->document->paperSizes());
}
void PageView::notifyViewportChanged( bool smoothMove )
@ -374,7 +413,9 @@ void PageView::notifyViewportChanged( bool smoothMove )
d->blockViewport = false;
return;
}
#ifdef PAGEVIEW_DEBUG
kdDebug() << "document viewport changed\n";
#endif
// relayout in "Single Pages" mode or if a relayout is pending
d->blockPixmapsRequest = true;
if ( !KpdfSettings::viewContinuous() || d->dirtyLayout )
@ -542,7 +583,8 @@ if ( d->document->handleEvent( pe ) )
}
// note: this check will take care of all things requiring alpha blending (not only selection)
bool wantCompositing = !selectionRect.isNull() && contentsRect.intersects( selectionRect );
bool wantCompositing = ( !selectionRect.isNull() && contentsRect.intersects( selectionRect ) )
|| d->mouseTextSelecting;
if ( wantCompositing && KpdfSettings::enableCompositing() )
{
@ -551,9 +593,18 @@ if ( d->document->handleEvent( pe ) )
QPainter pixmapPainter( &doubleBuffer );
pixmapPainter.translate( -contentsRect.left(), -contentsRect.top() );
// calculate the color
XRenderColor col;
float alpha=0.2f;
QColor blCol=selBlendColor.dark(140);
col.red=( (blCol.red() << 8) | blCol.red() ) * alpha;
col.green=( (blCol.green() << 8) | blCol.green() )*alpha;
col.blue=( (blCol.blue() << 8) | blCol.blue())*alpha;
col.alpha=alpha*0xffff;
// 1) Layer 0: paint items and clear bg on unpainted rects
drawDocumentOnPainter( contentsRect, &pixmapPainter );
// 2) Layer 1: paint (blend) transparent selection
// 2) Layer 1a: paint (blend) transparent selection
if ( !selectionRect.isNull() && selectionRect.intersects( contentsRect ) &&
!selectionRectInternal.contains( contentsRect ) )
{
@ -567,14 +618,55 @@ if ( d->document->handleEvent( pe ) )
blendRect.left() - contentsRect.left(), blendRect.top() - contentsRect.top(),
blendRect.width(), blendRect.height() );
// blend selBlendColor into the background pixmap
QImage blendedImage = blendedPixmap.convertToImage();
KImageEffect::blend( selBlendColor.dark(140), blendedImage, 0.2 );
// QImage blendedImage = blendedPixmap.convertToImage();
// KImageEffect::blend( selBlendColor.dark(140), blendedImage, 0.2 );
XRenderFillRectangle(x11Display(), PictOpOver, blendedPixmap.x11RenderHandle(), &col,
0,0, blendRect.width(), blendRect.height());
// copy the blended pixmap back to its place
pixmapPainter.drawPixmap( blendRect.left(), blendRect.top(), blendedImage );
pixmapPainter.drawPixmap( blendRect.left(), blendRect.top(), blendedPixmap );
}
// draw border (red if the selection is too small)
pixmapPainter.setPen( selBlendColor );
pixmapPainter.drawRect( selectionRect );
}
if ( d->mouseTextSelecting )
{
QRect blendRect;
QValueList<QRect>::iterator it=d->mouseTextSelectionRect->begin(),
end=d->mouseTextSelectionRect->end();
XRenderColor col;
float alpha=0.2f;
QColor blCol=d->mouseTextSelectionColor.dark(140);
col.red=( (blCol.red() << 8) | blCol.red() ) * alpha;
col.green=( (blCol.green() << 8) | blCol.green() )*alpha;
col.blue=( (blCol.blue() << 8) | blCol.blue())*alpha;
col.alpha=alpha*0xffff;
for (;it!=end;++it)
{
if (! ((*it).intersects( contentsRect )))
continue;
blendRect = (*it).intersect(contentsRect);
QPixmap blendedPixmap( blendRect.width(), blendRect.height() );
copyBlt( &blendedPixmap, 0,0, &doubleBuffer,
blendRect.left() - contentsRect.left(), blendRect.top() - contentsRect.top(),
blendRect.width(), blendRect.height() );
// blend selBlendColor into the background pixmap
// QImage blendedImage = blendedPixmap.convertToImage();
XRenderFillRectangle(x11Display(), PictOpOver, blendedPixmap.x11RenderHandle(), &col,
0,0, blendRect.width(), blendRect.height());
// KImageEffect::blend( d->mouseTextSelectionColor.dark(140), blendedImage, 0.2 );
// copy the blended pixmap back to its place
pixmapPainter.drawPixmap( blendRect.left(), blendRect.top(), blendedPixmap );
// draw border (red if the selection is too small)
pixmapPainter.setPen( d->mouseTextSelectionColor );
pixmapPainter.drawRect( selectionRect );
}
}
// 3) Layer 1: give annotator painting control
if ( d->annotator && d->annotator->routePaints( contentsRect ) )
@ -735,7 +827,7 @@ if (d->document->handleEvent( e ) )
{
case Key_Up:
case Key_PageUp:
// if in single page mode and at the top of the screen, go to previous page
// if in single page mode and at the top of the screen, go to \ page
if ( KpdfSettings::viewContinuous() || verticalScrollBar()->value() > verticalScrollBar()->minValue() )
{
if ( e->key() == Key_Up )
@ -747,7 +839,7 @@ if (d->document->handleEvent( e ) )
{
// more optimized than document->setPrevPage and then move view to bottom
DocumentViewport newViewport = d->document->viewport();
newViewport.pageNumber -= KpdfSettings::viewColumns();
newViewport.pageNumber -= viewColumns();
if ( newViewport.pageNumber < 0 )
newViewport.pageNumber = 0;
newViewport.rePos.enabled = true;
@ -769,7 +861,7 @@ if (d->document->handleEvent( e ) )
{
// more optimized than document->setNextPage and then move view to top
DocumentViewport newViewport = d->document->viewport();
newViewport.pageNumber += d->document->currentPage() ? KpdfSettings::viewColumns() : 1;
newViewport.pageNumber += d->document->currentPage() ? viewColumns() : 1;
if ( newViewport.pageNumber >= (int)d->items.count() )
newViewport.pageNumber = d->items.count() - 1;
newViewport.rePos.enabled = true;
@ -897,16 +989,49 @@ if (d->document->handleEvent( e ) )
}
else if ( rightButton && !d->mousePressPos.isNull() )
{
// if mouse moves 5 px away from the press point, switch to 'selection'
int deltaX = d->mousePressPos.x() - e->globalPos().x(),
deltaY = d->mousePressPos.y() - e->globalPos().y();
if ( deltaX > 5 || deltaX < -5 || deltaY > 5 || deltaY < -5 )
// if mouse moves 5 px away from the press point, do 'textselection'
int deltaX = e->x() - d->mouseSelectPos.x(),
deltaY = e->y() - d->mouseSelectPos.y();
if ( d->document->supportsSearching() && ( deltaX > 5 || deltaX < -5 || deltaY > 5 || deltaY < -5 ) )
{
d->aPrevAction = d->aMouseNormal;
d->aMouseSelect->activate();
QColor selColor = palette().active().highlight().light( 120 );
selectionStart( e->x() + deltaX, e->y() + deltaY, selColor, false );
selectionEndPoint( e->x(), e->y() );
PageViewItem * currentItem = d->items[ QMAX( 0, (int)d->document->currentPage() ) ];
// PageViewItem* item=pickItemOnPoint(e->x(),e->y());
const KPDFPage * kpdfPage = currentItem->page();
// build a proper rectangle (make sure left/top is to the left of right/bottom)
// QRect rect (d->mouseSelectPos,e->pos());
// rect=rect.normalize();
//
QRect vRect = currentItem->geometry();
// kdDebug() << "viewport " << vRect << endl;
// kdDebug() << "selection (UN) " << rect << endl;
// // move selection area over to relevant viewport
// rect.moveBy(-vRect.left(),-vRect.top());
// kdDebug() << "selection (MV) " << rect << endl;
// clip to viewport
// rect &= vRect;
// kdDebug() << "selection (CL) " << rect << endl;
// FIXME: width and height are greater by 1 then the selection.
// rect.addCoords(1,1,-1,-1);
if ( !kpdfPage->hasSearchPage() )
d->document->requestTextPage( kpdfPage->number() );
NormalizedPoint startCursor(d->mouseSelectPos.x()-vRect.left(),d->mouseSelectPos.y()-vRect.top(),
vRect.width(), vRect.height());
NormalizedPoint endCursor(e->x()-vRect.left(),e->y()-vRect.top(),vRect.width(), vRect.height());
if ( ! d->mouseTextSelectionInfo )
d->mouseTextSelectionInfo=new TextSelection(startCursor,endCursor);
else
d->mouseTextSelectionInfo->end(endCursor);
RegularAreaRect * selectionArea=kpdfPage->getTextArea(d->mouseTextSelectionInfo);
kdWarning () << "text areas: " << selectionArea->count() << endl;
if ( selectionArea->count() > 0 )
{
QColor selColor = palette().active().highlight();
textSelection(selectionArea->geometry(vRect.width(),vRect.height(),vRect.left(),vRect.top())
,selColor);
}
delete selectionArea;
break;
}
}
@ -920,7 +1045,8 @@ if (d->document->handleEvent( e ) )
case MouseZoom:
case MouseSelect:
// set second corner of selection
if ( d->mouseSelecting && (leftButton || d->aPrevAction) )
// TODO: does this condition make sense?
if ( d->mouseSelecting || (d->mouseSelecting && d->aPrevAction) )
selectionEndPoint( e->x(), e->y() );
break;
}
@ -929,7 +1055,7 @@ if (d->document->handleEvent( e ) )
void PageView::contentsMousePressEvent( QMouseEvent * e )
{
if (d->document->handleEvent( e ) )
if ( d->document->handleEvent( e ) )
{
// don't perform any mouse action when no document is shown
if ( d->items.isEmpty() )
@ -969,6 +1095,11 @@ if (d->document->handleEvent( e ) )
// handle mode dependant mouse press actions
bool leftButton = e->button() & LeftButton,
rightButton = e->button() & RightButton;
// Not sure we should erase the selection when clicking with left.
// if ( !(rightButton && d->mouseMode==MouseNormal) && d->mouseTextSelectionPainted )
// textSelectionClear();
switch ( d->mouseMode )
{
case MouseNormal: // drag start / click / link following
@ -978,6 +1109,8 @@ if (d->document->handleEvent( e ) )
if ( !d->mouseOnRect )
setCursor( sizeAllCursor );
}
else if (rightButton)
d->mouseSelectPos=e->pos() ; // just check
break;
case MouseZoom: // set first corner of the zoom rect
@ -988,11 +1121,11 @@ if (d->document->handleEvent( e ) )
break;
case MouseSelect: // set first corner of the selection rect
if ( leftButton )
{
// if ( leftButton )
// {
QColor selColor = palette().active().highlight().light( 120 );
selectionStart( e->x(), e->y(), selColor, false );
}
// }
break;
}
}
@ -1078,6 +1211,15 @@ if (d->document->handleEvent( e ) )
}
else if ( rightButton )
{
if ( d->mouseTextSelecting )
{
d->mouseTextSelecting = false;
delete d->mouseTextSelectionInfo;
d->mouseTextSelectionInfo=0;
textSelectionClear();
// textSelectionToClipboard();
}
else
// right click (if not within 5 px of the press point, the mode
// had been already changed to 'Selection' instead of 'Normal')
emit rightClick( pageItem ? pageItem->page() : 0, e->globalPos() );
@ -1148,7 +1290,7 @@ if (d->document->handleEvent( e ) )
QString* selectedText=0;
if (d->document->supportsSearching())
{
// grab text in selection by extracting it from all intersected pages
RegularAreaRect * rects=new RegularAreaRect;
const KPDFPage * kpdfPage=0;
@ -1161,6 +1303,7 @@ if (d->document->handleEvent( e ) )
{
// request the textpage if there isn't one
kpdfPage= item->page();
kdWarning() << "checking if page " << item->pageNumber() << " has text " << kpdfPage->hasSearchPage() << endl;
if ( !kpdfPage->hasSearchPage() )
d->document->requestTextPage( kpdfPage->number() );
// grab text in the rect that intersects itemRect
@ -1314,7 +1457,7 @@ if (d->document->handleEvent( e ) )
{
// more optimized than document->setNextPage and then move view to top
DocumentViewport newViewport = d->document->viewport();
newViewport.pageNumber += d->document->currentPage() ? KpdfSettings::viewColumns() : 1;
newViewport.pageNumber += d->document->currentPage() ? viewColumns() : 1;
if ( newViewport.pageNumber >= (int)d->items.count() )
newViewport.pageNumber = d->items.count() - 1;
newViewport.rePos.enabled = true;
@ -1329,7 +1472,7 @@ if (d->document->handleEvent( e ) )
{
// more optimized than document->setPrevPage and then move view to bottom
DocumentViewport newViewport = d->document->viewport();
newViewport.pageNumber -= KpdfSettings::viewColumns();
newViewport.pageNumber -= viewColumns();
if ( newViewport.pageNumber < 0 )
newViewport.pageNumber = 0;
newViewport.rePos.enabled = true;
@ -1493,6 +1636,50 @@ PageViewItem * PageView::pickItemOnPoint( int x, int y )
return item;
}
void PageView::textSelection( QValueList<QRect> * area, const QColor & color )
{
setCursor( Qt::IbeamCursor );
QValueList<QRect> toUpdate;
if ( d->mouseTextSelectionRect && d->mouseTextSelectionRect )
{
toUpdate+=*(d->mouseTextSelectionRect);
delete d->mouseTextSelectionRect;
d->mouseTextSelectionRect=0;
}
if (area)
toUpdate+=*(area);
d->mouseTextSelecting = true;
d->mouseTextSelectionRect = area;
d->mouseTextSelectionColor = color;
// ensures page doesn't scroll
if ( d->autoScrollTimer )
{
d->scrollIncrement = 0;
d->autoScrollTimer->stop();
}
QValueList<QRect>::Iterator it=toUpdate.begin(), end=toUpdate.end();
for (;it!=end;++it)
{
updateContents( *it );
}
d->mouseTextSelectionPainted=true;
}
void PageView::textSelectionClear()
{
setCursor( Qt::ArrowCursor );
QValueList<QRect>::iterator it=d->mouseTextSelectionRect->begin(),
end=d->mouseTextSelectionRect->end();
for (;it!=end;++it)
{
updateContents( *it );
}
delete d->mouseTextSelectionRect;
d->mouseTextSelectionRect=0;
}
void PageView::selectionStart( int x, int y, const QColor & color, bool /*aboveAll*/ )
{
d->mouseSelecting = true;
@ -1624,7 +1811,7 @@ void PageView::updateZoomText()
// add items that describe fit actions
QStringList translated;
translated << i18n("Fit Width") << i18n("Fit Page"); // << i18n("Fit Text");
translated << i18n("Fit Width") << i18n("Fit Page") /*<< i18n("Fit Text")*/;
// add percent items
QString double_oh( "00" );
@ -1684,9 +1871,24 @@ void PageView::updateCursor( const QPoint &p )
}
}
int PageView::viewColumns()
{
int nr=KpdfSettings::renderMode();
if (nr<2)
return nr+1;
return KpdfSettings::viewColumns();
}
int PageView::viewRows()
{
if (KpdfSettings::renderMode()<2)
return 1;
return KpdfSettings::viewRows();
}
//BEGIN private SLOTS
void PageView::slotRelayoutPages()
// called by: notifySetup, viewportResizeEvent, slotTwoPagesToggled, slotContinuousToggled, updateZoom
// called by: notifySetup, viewportResizeEvent, slotRenderMode, slotContinuousToggled, updateZoom
{
// set an empty container if we have no pages
int pageCount = d->items.count();
@ -1714,7 +1916,7 @@ void PageView::slotRelayoutPages()
QRect viewportRect( contentsX(), contentsY(), viewportWidth, viewportHeight );
// handle the 'center first page in row' stuff
int nCols = KpdfSettings::viewColumns();
int nCols = viewColumns();
bool centerFirstPage = KpdfSettings::centerFirstPageInRow() && nCols > 1;
// set all items geometry and resize contents. handle 'continuous' and 'single' modes separately
@ -1725,8 +1927,15 @@ void PageView::slotRelayoutPages()
pageCount += nCols - 1;
// Here we find out column's width and row's height to compute a table
// so we can place widgets 'centered in virtual cells'.
int nRows = (int)ceil( (float)pageCount / (float)nCols ),
* colWidth = new int[ nCols ],
int nRows;
// if ( KpdfSettings::renderMode() < 2 )
nRows = (int)ceil( (float)pageCount / (float)nCols );
// nRows=(int)ceil( (float)pageCount / (float) KpdfSettings::viewRows() );
// else
// nRows = KpdfSettings::viewRows();
int * colWidth = new int[ nCols ],
* rowHeight = new int[ nRows ],
cIdx = 0,
rIdx = 0;
@ -1799,6 +2008,9 @@ void PageView::slotRelayoutPages()
insertX = 0;
insertY += rHeight;
}
#ifdef PAGEVIEW_DEBUG
kdWarning() << "updating size for pageno " << item->pageNumber() << " to " << item->geometry() << endl;
#endif
}
delete [] colWidth;
@ -1807,31 +2019,51 @@ void PageView::slotRelayoutPages()
else // viewContinuous is FALSE
{
PageViewItem * currentItem = d->items[ QMAX( 0, (int)d->document->currentPage() ) ];
int nRows=viewRows();
// handle the 'centering on first row' stuff
if ( centerFirstPage && d->document->currentPage() < 1 )
nCols = 1;
// setup varialbles for a 1(row) x N(columns) grid
if ( centerFirstPage && d->document->currentPage() < 1 && KpdfSettings::renderMode() == 1 )
nCols = 1, nRows=1;
// setup varialbles for a M(row) x N(columns) grid
int * colWidth = new int[ nCols ],
cIdx = 0;
fullHeight = viewportHeight;
int * rowHeight = new int[ nRows ],
rIdx = 0;
for ( int i = 0; i < nCols; i++ )
colWidth[ i ] = viewportWidth / nCols;
for ( int i = 0; i < nRows; i++ )
rowHeight[ i ] = viewportHeight / nRows;
// 1) find out maximum area extension for the pages
bool wasCurrent = false;
for ( iIt = d->items.begin(); iIt != iEnd; ++iIt )
{
PageViewItem * item = *iIt;
if ( item == currentItem || (cIdx > 0 && cIdx < nCols) )
if ( rIdx >= 0 && rIdx < nRows )
{
// update internal page size (leaving a little margin in case of Fit* modes)
updateItemSize( item, colWidth[ cIdx ] - 6, viewportHeight - 12 );
// find row's maximum height and column's max width
if ( item->width() + 6 > colWidth[ cIdx ] )
colWidth[ cIdx ] = item->width() + 6;
if ( item->height() + 12 > fullHeight )
fullHeight = item->height() + 12;
cIdx++;
if ( item == currentItem )
wasCurrent=true;
if ( wasCurrent && cIdx >= 0 && cIdx < nCols )
{
// update internal page size (leaving a little margin in case of Fit* modes)
updateItemSize( item, colWidth[ cIdx ] - 6, rowHeight[ rIdx ] - 12 );
// find row's maximum height and column's max width
if ( item->width() + 6 > colWidth[ cIdx ] )
colWidth[ cIdx ] = item->width() + 6;
if ( item->height() + 12 > rowHeight[ rIdx ] )
rowHeight[ rIdx ] = item->height() + 12;
cIdx++;
}
if( cIdx>=nCols )
{
rIdx++;
cIdx=0;
}
}
}
@ -1839,25 +2071,47 @@ void PageView::slotRelayoutPages()
for ( int i = 0; i < nCols; i++ )
fullWidth += colWidth[ i ];
for ( int i = 0; i < nRows; i++ )
fullHeight += rowHeight[ i ];
// 3) hide all widgets except the displayable ones and dispose those
int insertX = 0;
int insertY = 0;
cIdx = 0;
rIdx = 0;
wasCurrent=false;
for ( iIt = d->items.begin(); iIt != iEnd; ++iIt )
{
PageViewItem * item = *iIt;
if ( item == currentItem || (cIdx > 0 && cIdx < nCols) )
if ( rIdx >= 0 && rIdx < nRows )
{
// center widget inside 'cells'
item->moveTo( insertX + (colWidth[ cIdx ] - item->width()) / 2,
(fullHeight - item->height()) / 2 );
// advance col index
insertX += colWidth[ cIdx ];
cIdx++;
} else
item->setGeometry( 0, 0, -1, -1 );
if ( item == currentItem )
wasCurrent=true;
if ( wasCurrent && cIdx >= 0 && cIdx < nCols )
{
// center widget inside 'cells'
item->moveTo( insertX + (colWidth[ cIdx ] - item->width()) / 2,
insertY + ( rowHeight[ rIdx ] - item->height() ) / 2 );
// advance col index
insertX += colWidth[ cIdx ];
cIdx++;
} else
item->setGeometry( 0, 0, -1, -1 );
if( cIdx>=nCols)
{
insertY += rowHeight[ rIdx ];
rIdx++;
insertX = 0;
cIdx=0;
}
}
else
item->setGeometry( 0, 0, -1, -1 );
}
delete [] colWidth;
delete [] rowHeight;
}
// 3) reset dirty state
@ -1929,17 +2183,26 @@ void PageView::slotRequestVisiblePixmaps( int newLeft, int newTop )
for ( ; iIt != iEnd; ++iIt )
{
PageViewItem * i = *iIt;
#ifdef PAGEVIEW_DEBUG
kdWarning() << "checking page " << i->pageNumber() << endl;
kdWarning() << "viewportRect is " << viewportRect << ", page item is " << i->geometry() << " intersect : " << viewportRect.intersects( i->geometry() ) << endl;
#endif
// if the item doesn't intersect the viewport, skip it
if ( !viewportRect.intersects( i->geometry() ) )
continue;
// add the item to the 'visible list'
d->visibleItems.push_back( i );
#ifdef PAGEVIEW_DEBUG
kdWarning() << "checking for pixmap for page " << i->pageNumber() << " = " << i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) << "\n";
#endif
kdWarning() << "checking for text for page " << i->pageNumber() << " = " << i->page()->hasSearchPage() << "\n";
// if the item has not the right pixmap, add a request for it
if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) )
{
#ifdef PAGEVIEW_DEBUG
kdWarning() << "rerequesting visible pixmaps for page " << i->pageNumber() << " !\n";
#endif
PixmapRequest * p = new PixmapRequest(
PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), i->rotation(), PAGEVIEW_PRIO, true );
requestedPixmaps.push_back( p );
@ -1995,8 +2258,9 @@ void PageView::slotRequestVisiblePixmaps( int newLeft, int newTop )
// send requests to the document
if ( !requestedPixmaps.isEmpty() )
{
d->document->requestPixmaps( requestedPixmaps );
}
// if this functions was invoked by viewport events, send update to document
if ( isEvent && nearPageNumber != -1 )
{
@ -2102,12 +2366,17 @@ void PageView::slotFitToTextToggled( bool on )
if ( on ) updateZoom( ZoomFitText );
}
void PageView::slotTwoPagesToggled( bool on )
void PageView::slotRenderMode( int nr )
{
uint newColumns = on ? 2 : 1;
if ( KpdfSettings::viewColumns() != newColumns )
uint newColumns;
if (nr<2)
newColumns = nr+1;
else
newColumns = KpdfSettings::viewColumns();
if ( KpdfSettings::renderMode() != nr )
{
KpdfSettings::setViewColumns( newColumns );
KpdfSettings::setRenderMode( nr );
KpdfSettings::writeConfig();
if ( d->document->pages() > 0 )
slotRelayoutPages();

View file

@ -21,6 +21,7 @@
#include <qscrollview.h>
#include <qvaluevector.h>
#include <qvaluelist.h>
#include "ui/pageviewutils.h"
#include "core/observer.h"
@ -116,8 +117,12 @@ class PageView : public QScrollView, public DocumentObserver
void updateZoom( ZoomMode newZm );
// update the text on the label using global zoom value or current page's one
void updateZoomText();
void textSelection( QValueList<QRect> * , const QColor & );
void textSelectionClear();
// updates cursor
void updateCursor( const QPoint &p );
int viewColumns();
int viewRows();
// don't want to expose classes in here
class PageViewPrivate * d;
@ -141,7 +146,7 @@ class PageView : public QScrollView, public DocumentObserver
void slotFitToWidthToggled( bool );
void slotFitToPageToggled( bool );
void slotFitToTextToggled( bool );
void slotTwoPagesToggled( bool );
void slotRenderMode( int );
void slotContinuousToggled( bool );
void slotSetMouseNormal();
void slotSetMouseZoom();

View file

@ -86,8 +86,10 @@ class SmoothPathEngine : public AnnotatorEngine
// start operation
if ( type == Press && points.isEmpty() )
{
totalRect.left = totalRect.right = lastPoint.x = nX;
totalRect.top = totalRect.bottom = lastPoint.y = nY;
lastPoint.x = nX;
lastPoint.y = nY;
totalRect.left = totalRect.right = lastPoint.x;
totalRect.top = totalRect.bottom = lastPoint.y;
points.append( lastPoint );
}
// add a point to the path
@ -248,10 +250,10 @@ class PickPointEngine : public AnnotatorEngine
// update variables and extents (zoom invariant rect)
point.x = nX;
point.y = nY;
rect.left = nX - (16.0 / (double)xScale);
rect.right = nX + (17.0 / (double)xScale);
rect.top = nY - (16.0 / (double)yScale);
rect.bottom = nY + (17.0 / (double)yScale);
rect.left = nX - (16.0 / (double)xScale) ;
rect.right = nX + (17.0 / (double)xScale) ;
rect.top = nY - (16.0 / (double)yScale) ;
rect.bottom = nY + (17.0 / (double)yScale) ;
return rect.geometry( (int)xScale, (int)yScale );
}
@ -296,8 +298,10 @@ class TwoPointsEngine : public AnnotatorEngine
if ( type == Press && points.isEmpty() )
{
NormalizedPoint newPoint;
rect.left = rect.right = newPoint.x = nX;
rect.top = rect.bottom = newPoint.y = nY;
newPoint.x = nX;
newPoint.y = nY;
rect.left = rect.right =newPoint.x;
rect.top = rect.bottom =newPoint.y;
points.append( newPoint );
return QRect();
}
@ -366,7 +370,7 @@ PageViewAnnotator::PageViewAnnotator( PageView * parent, KPDFDocument * storage
m_toolBar( 0 ), m_engine( 0 ), m_lastToolID( -1 ), m_lockedItem( 0 )
{
// load the tools from the 'xml tools definition' file. store the tree internally.
QFile infoFile( locate("data", "kpdf/tools.xml") );
QFile infoFile( locate("data", "oKular/tools.xml") );
if ( infoFile.exists() && infoFile.open( IO_ReadOnly ) )
{
QDomDocument doc( "annotatingTools" );