kpdf_part.cpp 15.6 KB
Newer Older
1 2 3 4
#include "kpdf_part.h"

#include <math.h>

Christophe Devriese's avatar
Christophe Devriese committed
5 6
#include <qwidget.h>
#include <qlistbox.h>
7
#include <qfile.h>
Christophe Devriese's avatar
Christophe Devriese committed
8
#include <qtimer.h>
9 10 11 12

#include <kaction.h>
#include <kdebug.h>
#include <kinstance.h>
13
#include <kprinter.h>
14
#include <kstdaction.h>
Laurent Montel's avatar
Laurent Montel committed
15
#include <kconfig.h>
16
#include <kparts/genericfactory.h>
17
#include <kdebug.h>
Laurent Montel's avatar
Laurent Montel committed
18
#include <kurldrag.h>
Laurent Montel's avatar
Laurent Montel committed
19
#include <kinputdialog.h>
20

21 22
#include "part.h"

Christophe Devriese's avatar
Christophe Devriese committed
23

24 25 26 27 28 29
#include "GString.h"

#include "GlobalParams.h"
#include "PDFDoc.h"
#include "XOutputDev.h"

Christophe Devriese's avatar
Christophe Devriese committed
30
// #include "kpdf_canvas.h"
31
#include "kpdf_pagewidget.h"
Christophe Devriese's avatar
Christophe Devriese committed
32

33 34

typedef KParts::GenericFactory<KPDF::Part> KPDFPartFactory;
35
K_EXPORT_COMPONENT_FACTORY(libkpdfpart, KPDFPartFactory)
36 37 38 39 40 41 42

using namespace KPDF;

Part::Part(QWidget *parentWidget, const char *widgetName,
           QObject *parent, const char *name,
           const QStringList & /*args*/ )
  : KParts::ReadOnlyPart(parent, name),
43
    m_doc(0),
44
    m_currentPage(0),
45
    m_zoomMode(FixedFactor),
46 47
    m_zoomFactor(1.0)
{
Wilco Greven's avatar
Wilco Greven committed
48 49
  new BrowserExtension(this);

50 51 52 53 54
  globalParams = new GlobalParams("");

  // we need an instance
  setInstance(KPDFPartFactory::instance());

Daniel Molkentin's avatar
Daniel Molkentin committed
55
  pdfpartview = new PDFPartView(parentWidget, widgetName);
Christophe Devriese's avatar
Christophe Devriese committed
56

Daniel Molkentin's avatar
Daniel Molkentin committed
57 58
  connect(pdfpartview->pagesListBox, SIGNAL( clicked ( QListBoxItem * ) ),
          this, SLOT( pageClicked ( QListBoxItem * ) ));
59

Christophe Devriese's avatar
Christophe Devriese committed
60
  m_outputDev = pdfpartview->outputdev;
Laurent Montel's avatar
Laurent Montel committed
61
  m_outputDev->setAcceptDrops( true );
62 63


Christophe Devriese's avatar
Christophe Devriese committed
64
  setWidget(pdfpartview);
65

66 67 68 69 70 71 72 73 74
  m_showScrollBars = new KToggleAction( i18n( "Show &Scrollbars" ), 0,
                                       actionCollection(), "show_scrollbars" );
  m_showPageList   = new KToggleAction( i18n( "Show &Page List" ), 0,
                                       actionCollection(), "show_page_list" );
  connect( m_showScrollBars, SIGNAL( toggled( bool ) ),
             SLOT( showScrollBars( bool ) ) );
  connect( m_showPageList, SIGNAL( toggled( bool ) ),
             SLOT( showMarkList( bool ) ) );

75
  // create our actions
76
  KStdAction::find    (this, SLOT(find()),
77
                       actionCollection(), "find");
78
  KStdAction::findNext(this, SLOT(findNext()),
79
                       actionCollection(), "find_next");
Malcolm Hunter's avatar
Malcolm Hunter committed
80
  m_fitToWidth = new KToggleAction(i18n("Fit to Page &Width"), 0,
81 82
                       this, SLOT(slotFitToWidthToggled()),
                       actionCollection(), "fit_to_width");
83
  KStdAction::zoomIn  (m_outputDev, SLOT(zoomIn()),
84
                       actionCollection(), "zoom_in");
85
  KStdAction::zoomOut (m_outputDev, SLOT(zoomOut()),
86 87 88 89 90 91
                       actionCollection(), "zoom_out");

  KStdAction::back    (this, SLOT(back()),
                       actionCollection(), "back");
  KStdAction::forward (this, SLOT(forward()),
                       actionCollection(), "forward");
92 93

  m_prevPage = KStdAction::prior(this, SLOT(slotPreviousPage()),
94
                       actionCollection(), "previous_page");
95 96 97
  m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );

  m_nextPage = KStdAction::next(this, SLOT(slotNextPage()),
98
                       actionCollection(), "next_page" );
99 100
  m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );

Laurent Montel's avatar
Laurent Montel committed
101 102 103 104 105 106 107
  m_firstPage = KStdAction::firstPage( this, SLOT( slotGotoStart() ),
                                      actionCollection(), "goToStart" );
  m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) );

  m_lastPage  = KStdAction::lastPage( this, SLOT( slotGotoEnd() ),
                                     actionCollection(), "goToEnd" );
  m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) );
108

Laurent Montel's avatar
Laurent Montel committed
109 110
  m_gotoPage = KStdAction::gotoPage( this, SLOT( slotGoToPage() ),
                                    actionCollection(), "goToPage" );
111 112
  // set our XML-UI resource file
  setXMLFile("kpdf_part.rc");
Laurent Montel's avatar
Laurent Montel committed
113 114
  connect( m_outputDev, SIGNAL( ZoomIn() ), SLOT( zoomIn() ));
  connect( m_outputDev, SIGNAL( ZoomOut() ), SLOT( zoomOut() ));
115 116
  connect( m_outputDev, SIGNAL( ReadUp() ), SLOT( slotReadUp() ));
  connect( m_outputDev, SIGNAL( ReadDown() ), SLOT( slotReadDown() ));
Laurent Montel's avatar
Laurent Montel committed
117 118
  connect( m_outputDev, SIGNAL( urlDropped( const KURL& ) ), SLOT( slotOpenUrlDropped( const KURL & )));

Laurent Montel's avatar
Laurent Montel committed
119
  readSettings();
Laurent Montel's avatar
Laurent Montel committed
120
  updateActionPage();
121 122 123 124
}

Part::~Part()
{
Laurent Montel's avatar
Laurent Montel committed
125
    delete globalParams;
Laurent Montel's avatar
Laurent Montel committed
126 127 128
    writeSettings();
}

Laurent Montel's avatar
Laurent Montel committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
void Part::slotGoToPage()
{
    if ( m_doc )
    {
        bool ok = false;
        int num = KInputDialog::getInteger(i18n("Go to Page"), i18n("Page:"), 1,
                                           1, m_doc->getNumPages(), 1, 10, &ok/*, _part->widget()*/);
        if (ok)
            goToPage( num -1 );
    }
}

void Part::goToPage( int page )
{
    m_currentPage = page;
    pdfpartview->pagesListBox->setCurrentItem(m_currentPage);
    m_outputDev->setPage(m_currentPage);
    updateActionPage();
}

Laurent Montel's avatar
Laurent Montel committed
149 150 151 152 153
void Part::slotOpenUrlDropped( const KURL &url )
{
    openURL(url );
}

154 155 156 157 158 159 160 161 162
void Part::setFullScreen( bool fs )
{
    if ( !fs )
        pdfpartview->pagesListBox->show();
    else
        pdfpartview->pagesListBox->hide();
}


Laurent Montel's avatar
Laurent Montel committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
void Part::updateActionPage()
{
    if ( m_doc )
    {
        m_firstPage->setEnabled(m_currentPage!=0);
        m_lastPage->setEnabled(m_currentPage!=m_doc->getNumPages());
        m_prevPage->setEnabled(m_currentPage!=0);
        m_nextPage->setEnabled(m_currentPage!=m_doc->getNumPages());
    }
    else
    {
        m_firstPage->setEnabled(false);
        m_lastPage->setEnabled(false);
        m_prevPage->setEnabled(false);
        m_nextPage->setEnabled(false);
    }
}

181 182 183 184 185 186
void Part::slotReadUp()
{
    if( !m_doc )
	return;

    if( !m_outputDev->readUp() ) {
187 188
        if ( previousPage() )
            m_outputDev->scrollBottom();
189 190
    }
}
Laurent Montel's avatar
Laurent Montel committed
191

192 193 194 195 196 197
void Part::slotReadDown()
{
    if( !m_doc )
	return;

    if( !m_outputDev->readDown() ) {
198 199
        if ( nextPage() )
            m_outputDev->scrollTop();
200 201
    }
}
Laurent Montel's avatar
Laurent Montel committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217

void Part::writeSettings()
{
    KConfigGroup general( KPDFPartFactory::instance()->config(), "General" );
    general.writeEntry( "ShowScrollBars", m_showScrollBars->isChecked() );
    general.writeEntry( "ShowPageList", m_showPageList->isChecked() );
    general.sync();
}

void Part::readSettings()
{
    KConfigGroup general( KPDFPartFactory::instance()->config(), "General" );
    m_showScrollBars->setChecked( general.readBoolEntry( "ShowScrollBars", true ) );
    showScrollBars( m_showScrollBars->isChecked() );
    m_showPageList->setChecked( general.readBoolEntry( "ShowPageList", true ) );
    showMarkList( m_showPageList->isChecked() );
218 219
}

220 221 222 223 224 225 226
void Part::showScrollBars( bool show )
{
    m_outputDev->enableScrollBars( show );
}

void Part::showMarkList( bool show )
{
Laurent Montel's avatar
Laurent Montel committed
227 228 229 230
    if ( show )
        pdfpartview->pagesListBox->show();
    else
        pdfpartview->pagesListBox->hide();
231 232
}

Laurent Montel's avatar
Laurent Montel committed
233 234 235 236 237 238 239
void Part::slotGotoEnd()
{
    if ( m_doc && m_doc->getNumPages() > 0 );
    {
        m_currentPage = m_doc->getNumPages();
        pdfpartview->pagesListBox->setCurrentItem(m_currentPage);
        m_outputDev->setPage(m_currentPage);
Laurent Montel's avatar
Laurent Montel committed
240
        updateActionPage();
Laurent Montel's avatar
Laurent Montel committed
241 242 243 244 245 246 247 248 249 250 251
    }
}

void Part::slotGotoStart()
{
    if ( m_doc && m_doc->getNumPages() > 0 );
    {
        m_currentPage = 1;

        pdfpartview->pagesListBox->setCurrentItem(m_currentPage);
        m_outputDev->setPage(m_currentPage);
Laurent Montel's avatar
Laurent Montel committed
252
        updateActionPage();
Laurent Montel's avatar
Laurent Montel committed
253 254 255
     }
}

256
bool Part::nextPage()
257 258
{
    m_currentPage = pdfpartview->pagesListBox->currentItem() + 1;
259
    if ( m_doc && m_currentPage >= m_doc->getNumPages())
260
        return false;
261

262 263
    pdfpartview->pagesListBox->setCurrentItem(m_currentPage);
    m_outputDev->nextPage();
Laurent Montel's avatar
Laurent Montel committed
264
    updateActionPage();
265 266 267 268 269 270
    return true;
}

void Part::slotNextPage()
{
    nextPage();
271 272 273
}

void Part::slotPreviousPage()
274 275 276 277 278
{
    previousPage();
}

bool Part::previousPage()
279 280
{
    m_currentPage = pdfpartview->pagesListBox->currentItem() - 1;
281
    if ( m_currentPage  < 0)
282
        return false;
283

284 285
    pdfpartview->pagesListBox->setCurrentItem(m_currentPage );
    m_outputDev->previousPage();
Laurent Montel's avatar
Laurent Montel committed
286
    updateActionPage();
287
    return true;
288 289
}

290 291 292 293 294 295
  KAboutData*
Part::createAboutData()
{
  // the non-i18n name here must be the same as the directory in
  // which the part's rc file is installed ('partrcdir' in the
  // Makefile)
296
  KAboutData* aboutData = new KAboutData("kpdfpart", I18N_NOOP("KPDF::Part"),
297 298 299 300 301
                                         "0.1");
  aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org");
  return aboutData;
}

302 303 304 305 306
  bool
Part::closeURL()
{
  delete m_doc;
  m_doc = 0;
307

308 309 310
  return KParts::ReadOnlyPart::closeURL();
}

311 312 313 314 315 316 317 318
  bool
Part::openFile()
{
  // m_file is always local so we can use QFile on it
  QFile file(m_file);
  if (file.open(IO_ReadOnly) == false)
    return false;

319
  GString* filename = new GString(m_file.ascii());
Wilco Greven's avatar
Wilco Greven committed
320
  m_doc = new PDFDoc(filename, 0, 0);
321 322 323 324 325 326

  if (!m_doc->isOk())
    return false;
  // just for fun, set the status bar
  // emit setStatusBarText( QString::number( m_doc->getNumPages() ) );

Daniel Molkentin's avatar
Daniel Molkentin committed
327 328 329 330 331 332 333 334 335
  // fill the listbox with entries for every page
  pdfpartview->pagesListBox->setUpdatesEnabled(false);
  pdfpartview->pagesListBox->clear();
  for (int i = 1; i <= m_doc->getNumPages(); i++)
  {
    pdfpartview->pagesListBox->insertItem(QString::number(i));
  }
  pdfpartview->pagesListBox->setUpdatesEnabled(true);
  pdfpartview->pagesListBox->update();
336

337
  displayPage(1);
Daniel Molkentin's avatar
Daniel Molkentin committed
338
  m_outputDev->setPDFDocument(m_doc);
339 340 341
  return true;
}

342
  void
343 344
Part::displayPage(int pageNumber, float /*zoomFactor*/)
{
345 346
    if (pageNumber <= 0 || pageNumber > m_doc->getNumPages())
        return;
Laurent Montel's avatar
Laurent Montel committed
347
    updateActionPage();
348 349
    const double pageWidth  = m_doc->getPageWidth (pageNumber) * m_zoomFactor;
    const double pageHeight = m_doc->getPageHeight(pageNumber) * m_zoomFactor;
350

351 352
    // Pixels per point when the zoomFactor is 1.
    const float basePpp  = QPaintDevice::x11AppDpiX() / 72.0;
353

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
    switch (m_zoomMode)
    {
    case FitWidth:
    {
        const double pageAR = pageWidth/pageHeight; // Aspect ratio

        const int canvasWidth    = m_outputDev->contentsRect().width();
        const int canvasHeight   = m_outputDev->contentsRect().height();
        const int scrollBarWidth = m_outputDev->verticalScrollBar()->width();

        // Calculate the height so that the page fits the viewport width
        // assuming that we need a vertical scrollbar.
        float height = float(canvasWidth - scrollBarWidth) / pageAR;

        // If the vertical scrollbar wasn't needed after all, calculate the page
        // size so that the page fits the viewport width without the scrollbar.
        if (ceil(height) <= canvasHeight)
        {
            height = float(canvasWidth) / pageAR;

            // Handle the rare case that enlarging the page resulted in the need of
            // a vertical scrollbar. We can fit the page to the viewport height in
            // this case.
            if (ceil(height) > canvasHeight)
                height = float(canvasHeight) * pageAR;
        }

        m_zoomFactor = (height / pageHeight) / basePpp;
        break;
    }
    case FixedFactor:
    default:
        break;
    }
388

389
//const float ppp = basePpp * m_zoomFactor; // pixels per point
390

391
//  m_doc->displayPage(m_outputDev, pageNumber, int(m_zoomFactor * ppp * 72.0), 0, true);
392

393
//  m_outputDev->show();
394

395
//  m_currentPage = pageNumber;
396 397 398 399 400 401 402 403
}

  void
Part::displayDestination(LinkDest* dest)
{
  int pageNumber;
  // int dx, dy;

404
  if (dest->isPageRef())
405 406 407 408
  {
    Ref pageRef = dest->getPageRef();
    pageNumber = m_doc->findPage(pageRef.num, pageRef.gen);
  }
409
  else
410 411 412 413
  {
    pageNumber = dest->getPageNum();
  }

414
  if (pageNumber <= 0 || pageNumber > m_doc->getNumPages())
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
  {
    pageNumber = 1;
  }

  displayPage(pageNumber);
  return;
/*
  if (fullScreen) {
    return;
  }
  switch (dest->getKind()) {
  case destXYZ:
    out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
    if (dest->getChangeLeft() || dest->getChangeTop()) {
      if (dest->getChangeLeft()) {
	hScrollbar->setPos(dx, canvas->getWidth());
      }
      if (dest->getChangeTop()) {
	vScrollbar->setPos(dy, canvas->getHeight());
      }
      canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
    }
    //~ what is the zoom parameter?
    break;
  case destFit:
  case destFitB:
    //~ do fit
    hScrollbar->setPos(0, canvas->getWidth());
    vScrollbar->setPos(0, canvas->getHeight());
    canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
    break;
  case destFitH:
  case destFitBH:
    //~ do fit
    out->cvtUserToDev(0, dest->getTop(), &dx, &dy);
    hScrollbar->setPos(0, canvas->getWidth());
    vScrollbar->setPos(dy, canvas->getHeight());
    canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
    break;
  case destFitV:
  case destFitBV:
    //~ do fit
    out->cvtUserToDev(dest->getLeft(), 0, &dx, &dy);
    hScrollbar->setPos(dx, canvas->getWidth());
    vScrollbar->setPos(0, canvas->getHeight());
    canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
    break;
  case destFitR:
    //~ do fit
    out->cvtUserToDev(dest->getLeft(), dest->getTop(), &dx, &dy);
    hScrollbar->setPos(dx, canvas->getWidth());
    vScrollbar->setPos(dy, canvas->getHeight());
    canvas->scroll(hScrollbar->getPos(), vScrollbar->getPos());
    break;
  }
*/
}

473
  void
Wilco Greven's avatar
Wilco Greven committed
474
Part::print()
475 476 477 478 479 480 481 482 483 484
{
  if (m_doc == 0)
    return;

  KPrinter printer;

  printer.setPageSelection(KPrinter::ApplicationSide);
  printer.setCurrentPage(m_currentPage);
  printer.setMinMax(1, m_doc->getNumPages());

485
  if (printer.setup(widget()))
486 487 488
  {
    /*
    KTempFile tf(QString::null, ".ps");
489
    if (tf.status() == 0)
490 491 492 493
    {
      savePages(tf.name(), printer.pageList());
      printer.printFiles(QStringList( tf.name() ), true);
    }
494
    else
495 496 497 498 499 500 501 502
    {
       // TODO: Proper error handling
      ;
    }
    */
  }
}

503
  void
504 505 506 507 508
Part::displayNextPage()
{
  displayPage(m_currentPage + 1);
}

509
  void
510 511 512 513 514 515
Part::displayPreviousPage()
{
  displayPage(m_currentPage - 1);
}

/*
516
  void
517 518 519 520 521 522
Part::setFixedZoomFactor(float zoomFactor)
{

}
*/

523
  void
524 525 526
Part::executeAction(LinkAction* action)
{
  if (action == 0)
527
    return;
528 529 530

  LinkActionKind kind = action->getKind();

531
  switch (kind)
532 533 534 535 536
  {
  case actionGoTo:
  case actionGoToR:
  {
    LinkDest* dest = 0;
537
    GString* namedDest = 0;
538

539
    if (kind == actionGoTo)
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
    {
      if ((dest = ((LinkGoTo*)action)->getDest()))
        dest = dest->copy();
      else if ((namedDest = ((LinkGoTo*)action)->getNamedDest()))
        namedDest = namedDest->copy();
    }
    /*
    else
    {
      if ((dest = ((LinkGoToR*)action)->getDest()))
        dest = dest->copy();
      else if ((namedDest = ((LinkGoToR*)action)->getNamedDest()))
        namedDest = namedDest->copy();
      s = ((LinkGoToR*)action)->getFileName()->getCString();
      //~ translate path name for VMS (deal with '/')
555
      if (!loadFile(fileName))
556 557 558 559 560 561 562 563 564 565 566 567 568
      {
        delete dest;
        delete namedDest;
        return;
      }
    }
    */

    if (namedDest != 0)
    {
      dest = m_doc->findDest(namedDest);
      delete namedDest;
    }
569
    if (dest != 0)
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
    {
      displayDestination(dest);
      delete dest;
    }
    else
    {
      if (kind == actionGoToR)
        displayPage(1);
    }
    break;
  }
  default:
      break;
  }
}

  void
587
Part::slotFitToWidthToggled()
588
{
589
  m_zoomMode = m_fitToWidth->isChecked() ? FitWidth : FixedFactor;
590 591 592
  displayPage(m_currentPage);
}

Christophe Devriese's avatar
Christophe Devriese committed
593 594
// for optimization
bool redrawing = false;
Wilco Greven's avatar
Wilco Greven committed
595

Christophe Devriese's avatar
Christophe Devriese committed
596 597 598
void
Part::update()
{
599
	if (m_outputDev && ! redrawing)
Christophe Devriese's avatar
Christophe Devriese committed
600 601 602 603
	{
		redrawing = true;
		QTimer::singleShot(200, this, SLOT( redrawPage() ));
	}
604
}
Christophe Devriese's avatar
Christophe Devriese committed
605

606
void
Christophe Devriese's avatar
Christophe Devriese committed
607
Part::redrawPage()
608
{
Christophe Devriese's avatar
Christophe Devriese committed
609
	redrawing = false;
610
	displayPage(m_currentPage);
Christophe Devriese's avatar
Christophe Devriese committed
611 612
}

Laurent Montel's avatar
Laurent Montel committed
613
void Part::pageClicked ( QListBoxItem * qbi )
Christophe Devriese's avatar
Christophe Devriese committed
614
{
Laurent Montel's avatar
Laurent Montel committed
615 616
    if ( !qbi )
        return;
617 618
    m_currentPage = pdfpartview->pagesListBox->index(qbi)+1;
    m_outputDev->setPage(m_currentPage);
Laurent Montel's avatar
Laurent Montel committed
619
    updateActionPage();
Christophe Devriese's avatar
Christophe Devriese committed
620
}
621

Wilco Greven's avatar
Wilco Greven committed
622 623 624 625 626 627 628
BrowserExtension::BrowserExtension(Part* parent)
  : KParts::BrowserExtension( parent, "KPDF::BrowserExtension" )
{
  emit enableAction("print", true);
  setURLDropHandlingEnabled(true);
}

629
  void
Wilco Greven's avatar
Wilco Greven committed
630 631 632 633 634
BrowserExtension::print()
{
  static_cast<Part*>(parent())->print();
}

635 636 637
#include "kpdf_part.moc"

// vim:ts=2:sw=2:tw=78:et