You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kviewshell/kmultipage.cpp

1977 lines
55 KiB

#include <config.h>
#include <kaction.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kfiledialog.h>
#include <kiconloader.h>
#include <kio/job.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kprinter.h>
#include <kstdaction.h>
#include <tqobject.h>
#include <tqlayout.h>
#include <tqpaintdevicemetrics.h>
#include <tqprogressdialog.h>
#include <tqsplitter.h>
#include <tqurl.h>
#include <tqtoolbox.h>
#include <tqvbox.h>
#include "documentWidget.h"
#include "marklist.h"
#include "tableOfContents.h"
#include "kprintDialogPage_pageoptions.h"
#include "kvsprefs.h"
#include "kmultipage.h"
#include "pageNumber.h"
#include "renderedDocumentPagePrinter.h"
#include "searchWidget.h"
#include "textBox.h"
#include "zoomlimits.h"
//#define DEBUG_KMULTIPAGE
KMultiPage::KMultiPage(TQWidget *parentWidget, const char *widgetName, TQObject *parent, const char *name)
: DCOPObject("kmultipage"), KParts::ReadOnlyPart(parent, name)
{
// For reasons which I don't understand, the initialization of the
// DCOPObject above does not work properly, the name is ignored. It
// works fine if we repeat the name here. -- Stefan Kebekus
// This is because of the virtual inheritance. Get rid of it (but it's BC, and this is a lib...) -- DF
setObjId("kmultipage");
parentWdg = parentWidget;
lastCurrentPage = 0;
timer_id = -1;
searchInProgress = false;
TQVBox* verticalBox = new TQVBox(parentWidget);
verticalBox->setFocusPolicy(TQ_StrongFocus);
setWidget(verticalBox);
splitterWidget = new TQSplitter(verticalBox, widgetName);
splitterWidget->setOpaqueResize(false);
splitterWidget->tqsetSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::MinimumExpanding);
// Create SideBar
sideBar = new TQToolBox(splitterWidget, "sidebar");
// Create ContentsList
tableOfContents = new TableOfContents(sideBar);
sideBar->addItem(tableOfContents, TQIconSet(SmallIcon("contents")), i18n("Contents"));
connect(tableOfContents, TQT_SIGNAL(gotoPage(const Anchor&)), this, TQT_SLOT(gotoPage(const Anchor&)));
// Create MarkList
_markList = new MarkList(sideBar, "marklist");
sideBar->addItem(_markList, TQIconSet(SmallIcon("thumbnail")), i18n("Thumbnails"));
// Restore state of the sidebar
sideBar->setCurrentItem(sideBar->item(KVSPrefs::sideBarItem()));
splitterWidget->setResizeMode(sideBar, TQSplitter::KeepSize);
connect(_markList, TQT_SIGNAL(selected(const PageNumber&)), this, TQT_SLOT(gotoPage(const PageNumber&)));
_scrollView = new PageView(splitterWidget, widgetName);
// Create Search Panel
searchWidget = new SearchWidget(verticalBox);
searchWidget->hide();
connect(searchWidget, TQT_SIGNAL(findNextText()), this, TQT_SLOT(findNextText()));
connect(searchWidget, TQT_SIGNAL(findPrevText()), this, TQT_SLOT(findPrevText()));
sideBar->setMinimumWidth(80);
sideBar->setMaximumWidth(300);
connect(_scrollView, TQT_SIGNAL(currentPageChanged(const PageNumber&)), this, TQT_SLOT(setCurrentPageNumber(const PageNumber&)));
connect(_scrollView, TQT_SIGNAL(viewSizeChanged(const TQSize&)), scrollView(), TQT_SLOT(calculateCurrentPageNumber()));
connect(_scrollView, TQT_SIGNAL(wheelEventReceived(TQWheelEvent *)), this, TQT_SLOT(wheelEvent(TQWheelEvent*)));
connect(this, TQT_SIGNAL(enableMoveTool(bool)), _scrollView, TQT_SLOT(slotEnableMoveTool(bool)));
splitterWidget->setCollapsible(sideBar, false);
splitterWidget->setSizes(KVSPrefs::guiLayout());
connect(searchWidget, TQT_SIGNAL(searchEnabled(bool)), this, TQT_SIGNAL(searchEnabled(bool)));
connect(searchWidget, TQT_SIGNAL(stopSearch()), this, TQT_SLOT(stopSearch()));
}
KMultiPage::~KMultiPage()
{
writeSettings();
if (timer_id != -1)
killTimer(timer_id);
delete pageCache;
}
void KMultiPage::readSettings()
{
}
void KMultiPage::writeSettings()
{
// Save TOC tqlayout
tableOfContents->writeSettings();
KVSPrefs::setGuiLayout(splitterWidget->sizes());
// Save state of the sidebar
KVSPrefs::setSideBarItem(sideBar->indexOf(sideBar->currentItem()));
KVSPrefs::writeConfig();
}
TQString KMultiPage::name_of_current_file()
{
return m_file;
}
bool KMultiPage::is_file_loaded(const TQString& filename)
{
return (filename == m_file);
}
void KMultiPage::slotSave_defaultFilename()
{
slotSave();
}
void KMultiPage::slotSave()
{
// Try to guess the proper ending...
TQString formats;
TQString ending;
int rindex = m_file.findRev(".");
if (rindex == -1) {
ending = TQString();
formats = TQString();
} else {
ending = m_file.mid(rindex); // e.g. ".dvi"
formats = fileFormats().grep(ending).join("\n");
}
TQString fileName = KFileDialog::getSaveFileName(TQString(), formats, 0, i18n("Save File As"));
if (fileName.isEmpty())
return;
// Add the ending to the filename. I hope the user likes it that
// way.
if (!ending.isEmpty() && fileName.find(ending) == -1)
fileName = fileName+ending;
if (TQFile(fileName).exists()) {
int r = KMessageBox::warningContinueCancel (0, i18n("The file %1\nexists. Shall I overwrite that file?").tqarg(fileName),
i18n("Overwrite File"), i18n("Overwrite"));
if (r == KMessageBox::Cancel)
return;
}
KIO::Job *job = KIO::file_copy( KURL( m_file ), KURL( fileName ), 0600, true, false, true );
connect( job, TQT_SIGNAL( result( KIO::Job * ) ), this, TQT_SLOT( slotIOJobFinished ( KIO::Job * ) ) );
return;
}
void KMultiPage::setFile(bool)
{
return;
}
bool KMultiPage::closeURL()
{
#ifdef DEBUG_KMULTIPAGE
kdDebug(1233) << "KMultiPage::closeURL()" << endl;
#endif
if (renderer.isNull())
return false;
// Clear navigation history.
document_history.clear();
// Close the file.
renderer->setFile(TQString(), KURL());
renderer->clear();
// Delete Page Widgets.
widgetList.setAutoDelete(true);
widgetList.resize(0);
widgetList.setAutoDelete(false);
// Update ScrollView.
scrollView()->layoutPages();
enableActions(false);
// Clear Thumbnail List.
markList()->clear();
// Clear Table of Contents
tableOfContents->clear();
// Clear tqStatus Bar
emit setStatusBarText(TQString());
return true;
}
void KMultiPage::slotIOJobFinished ( KIO::Job *job )
{
if ( job->error() )
job->showErrorDialog( 0L );
}
void KMultiPage::slotShowScrollbars(bool status)
{
_scrollView->slotShowScrollbars(status);
}
void KMultiPage::slotShowSidebar(bool show)
{
if (show)
sideBar->show();
else
sideBar->hide();
}
void KMultiPage::slotShowThumbnails(bool show)
{
markList()->slotShowThumbnails(show);
}
void KMultiPage::slotSetFullPage(bool fullpage)
{
_scrollView->setFullScreenMode(fullpage);
if (fullpage)
slotShowSidebar(false);
}
void KMultiPage::preferencesChanged()
{
// We need to read the config options otherwise the KVSPrefs-object would
// not be syncronized between the kviewpart and the kmultipage.
KVSPrefs::self()->readConfig();
slotShowThumbnails(KVSPrefs::showThumbnails());
// if we are in overviewmode and the number of columns or rows has changed
if (scrollView()->overviewMode() &&
(scrollView()->getNrColumns() != KVSPrefs::overviewModeColumns() ||
scrollView()->getNrRows() != KVSPrefs::overviewModeRows()))
{
setViewMode(KVSPrefs::EnumViewMode::Overview);
}
if (KVSPrefs::changeColors() && KVSPrefs::renderMode() == KVSPrefs::EnumRenderMode::Paper)
renderer->setAccessibleBackground(true, KVSPrefs::paperColor());
else
renderer->setAccessibleBackground(false);
renderModeChanged();
}
void KMultiPage::setViewMode(int mode)
{
#ifdef DEBUG_KMULTIPAGE
kdDebug(1233) << "KMultiPage::setViewMode(" << mode << ")" << endl;
#endif
// Save the current page number because when we are changing the columns
// and rows in the scrollview the currently shown Page probably out of view.
PageNumber currentPage = currentPageNumber();
// Save viewMode for future uses of KViewShell
switch (mode)
{
case KVSPrefs::EnumViewMode::SinglePage:
KVSPrefs::setViewMode(KVSPrefs::EnumViewMode::SinglePage);
// Don't do anything if the view mode is already set
if ((scrollView()->getNrColumns() == 1) && (scrollView()->getNrRows() == 1) && (scrollView()->isContinuous() == false))
return;
scrollView()->setNrColumns(1);
scrollView()->setNrRows(1);
scrollView()->setContinuousViewMode(false);
// We scroll the view to the top, so that top and not the bottom
// of the visible page is shown.
scrollView()->scrollTop();
break;
case KVSPrefs::EnumViewMode::ContinuousFacing:
KVSPrefs::setViewMode(KVSPrefs::EnumViewMode::ContinuousFacing);
// Don't do anything if the view mode is already set
if ((scrollView()->getNrColumns() == 2) && (scrollView()->getNrRows() == 1) && (scrollView()->isContinuous() == true))
return;
scrollView()->setNrColumns(2);
scrollView()->setNrRows(1);
scrollView()->setContinuousViewMode(true);
break;
case KVSPrefs::EnumViewMode::Overview:
KVSPrefs::setViewMode(KVSPrefs::EnumViewMode::Overview);
// Don't do anything if the view mode is already set
if ((scrollView()->getNrColumns() == KVSPrefs::overviewModeColumns()) && (scrollView()->getNrRows() == KVSPrefs::overviewModeRows()) && (scrollView()->isContinuous() == false))
return;
scrollView()->setNrColumns(KVSPrefs::overviewModeColumns());
scrollView()->setNrRows(KVSPrefs::overviewModeRows());
scrollView()->setContinuousViewMode(false);
// We scroll the view to the top, so that top and not the bottom
// of the visible tableau is shown.
scrollView()->scrollTop();
break;
default: //KVSPrefs::EnumViewMode::Continuous
KVSPrefs::setViewMode(KVSPrefs::EnumViewMode::Continuous);
// Don't do anything if the view mode is already set
if ((scrollView()->getNrColumns() == 1) && (scrollView()->getNrRows() == 1) && (scrollView()->isContinuous() == true))
return;
scrollView()->setNrColumns(1);
scrollView()->setNrRows(1);
scrollView()->setContinuousViewMode(true);
}
generateDocumentWidgets(currentPage);
KVSPrefs::writeConfig();
emit viewModeChanged();
}
void KMultiPage::initializePageCache()
{
pageCache = new DocumentPageCache();
}
DocumentWidget* KMultiPage::createDocumentWidget()
{
DocumentWidget* documentWidget = new DocumentWidget(scrollView()->viewport(), scrollView(), pageCache, "singlePageWidget");
connect(documentWidget, TQT_SIGNAL(clearSelection()), this, TQT_SLOT(clearSelection()));
connect(this, TQT_SIGNAL(enableMoveTool(bool)), documentWidget, TQT_SLOT(slotEnableMoveTool(bool)));
return documentWidget;
}
void KMultiPage::generateDocumentWidgets(const PageNumber& _startPage)
{
PageNumber startPage = _startPage;
#ifdef DEBUG_KMULTIPAGE
kdDebug(1233) << "KMultiPage::generateDocumentWidgets(" << startPage << ")" << endl;
#endif
// Do nothing if no document is loaded.
if (getRenderer().isNull() || getRenderer()->isEmpty())
return;
// This function is only called with an invalid pagenumber, when
// the file has been loaded or reloaded.
bool reload = !startPage.isValid();
if (reload)
{
// Find the number of the current page, for later use.
startPage = currentPageNumber();
}
// Make sure that startPage is in the permissible range.
if (startPage < 1)
startPage = 1;
if (startPage > numberOfPages())
startPage = numberOfPages();
unsigned int tableauStartPage = startPage;
// Find out how many widgets are needed, and resize the widgetList accordingly.
widgetList.setAutoDelete(true);
TQ_UINT16 oldwidgetListSize = widgetList.size();
if (numberOfPages() == 0)
widgetList.resize(0);
else
{
switch (KVSPrefs::viewMode())
{
case KVSPrefs::EnumViewMode::SinglePage:
widgetList.resize(1);
break;
case KVSPrefs::EnumViewMode::Overview:
{
// Calculate the number of pages shown in overview mode.
unsigned int visiblePages = KVSPrefs::overviewModeColumns() * KVSPrefs::overviewModeRows();
// Calculate the number of the first page in the tableau.
tableauStartPage = startPage - ((startPage - 1) % visiblePages);
// We cannot have more widgets then pages in the document.
visiblePages = TQMIN(visiblePages, numberOfPages() - tableauStartPage + 1);
if (widgetList.size() != visiblePages)
widgetList.resize(visiblePages);
break;
}
default:
// In KVS_Continuous and KVS_ContinuousFacing all pages in the document are shown.
widgetList.resize(numberOfPages());
}
}
bool isWidgetListResized = (widgetList.size() != oldwidgetListSize);
widgetList.setAutoDelete(false);
// If the widgetList is empty, there is nothing left to do.
if (widgetList.size() == 0) {
scrollView()->addChild(&widgetList);
return;
}
// Allocate DocumentWidget structures so that all entries of
// widgetList point to a valid DocumentWidget.
DocumentWidget *documentWidget;
for(TQ_UINT16 i=0; i<widgetList.size(); i++) {
documentWidget = widgetList[i];
if (documentWidget == 0) {
documentWidget = createDocumentWidget();
widgetList.insert(i, documentWidget);
documentWidget->show();
connect(documentWidget, TQT_SIGNAL(localLink(const TQString &)), this, TQT_SLOT(handleLocalLink(const TQString &)));
connect(documentWidget, TQT_SIGNAL(setStatusBarText(const TQString&)), this, TQT_SIGNAL(setStatusBarText(const TQString&)) );
}
}
// Set the page numbers for the newly allocated widgets. How this is
// done depends on the viewMode.
if (KVSPrefs::viewMode() == KVSPrefs::EnumViewMode::SinglePage) {
// In KVS_SinglePage mode, any number between 1 and the maximum
// number of pages is acceptable. If an acceptable value is found,
// nothing is done, and otherwise '1' is set as a default.
documentWidget = widgetList[0];
if (documentWidget != 0) { // Paranoia safety check
documentWidget->setPageNumber(startPage);
documentWidget->update();
} else
kdError(4300) << "Zero-Pointer in widgetList in KMultiPage::generateDocumentWidgets()" << endl;
} else {
// In all other modes, the widgets will be numbered continuously,
// starting from firstShownPage.
for(TQ_UINT16 i=0; i<widgetList.size(); i++) {
documentWidget = widgetList[i];
if (documentWidget != 0) // Paranoia safety check
{
if (KVSPrefs::viewMode() == KVSPrefs::EnumViewMode::Overview)
documentWidget->setPageNumber(i+tableauStartPage);
else
documentWidget->setPageNumber(i+1);
}
else
kdError(4300) << "Zero-Pointer in widgetList in KMultiPage::generateDocumentWidgets()" << endl;
}
}
// Make the changes in the widgetList known to the scrollview. so
// that the scrollview may update its contents.
scrollView()->addChild(&widgetList);
// If the number of widgets has changed, or the viewmode has been changed the widget
// that displays the current page may not be visible anymore. Bring it back into focus.
if (isWidgetListResized || !reload)
gotoPage(startPage);
}
bool KMultiPage::gotoPage(const PageNumber& page)
{
return gotoPage(page, 0, true);
}
bool KMultiPage::gotoPage(const PageNumber& page, int y, bool isLink)
{
#ifdef DEBUG_KMULTIPAGE
kdDebug(1233) << "KMultiPage::gotoPage()" << endl;
#endif
if (widgetList.size() == 0) {
kdError(4300) << "KMultiPage::gotoPage(" << page << ", y) called, but widgetList is empty" << endl;
return false;
}
if (!page.isValid())
{
kdDebug(1223) << "KMultiPage::gotoPage(" << page << ") invalid pageNumber." << endl;
return false;
}
if (isLink)
document_history.add(page, y);
DocumentWidget* pageWidget;
// If we are in overview viewmode
if (KVSPrefs::viewMode() == KVSPrefs::EnumViewMode::Overview)
{
unsigned int visiblePages = KVSPrefs::overviewModeColumns() * KVSPrefs::overviewModeRows();
// Pagenumber of the first visibile Page in the current tableau
unsigned int firstPage = ((DocumentWidget*)widgetList[0])->getPageNumber();
// Pagenumber of the first page in the new tableau.
unsigned int tableauStartPage = page + 1 - (page % visiblePages);
// If these numbers arn't equal "page" is not in the current tableu.
if (firstPage != tableauStartPage) // widgets need to be updated
{
if ((numberOfPages() - tableauStartPage + 1 < visiblePages) || (widgetList.size() < visiblePages))
{
// resize widgetList
// the pages are also set correctly by "generateDocumentWidgets"
generateDocumentWidgets(tableauStartPage);
}
else
{
// "page" is not shown in the scrollview, so we have to switch widgets.
// Here we don't need to resize the widgetList.
for (unsigned int i = 0; i < widgetList.size(); i++)
{
pageWidget = (DocumentWidget*)(widgetList[i]);
if (pageWidget != 0)
pageWidget->setPageNumber(tableauStartPage + i);
}
scrollView()->layoutPages();
}
}
// move scrollview to "page".
// Make the widget pageWidget visible in the scrollview. Somehow this
// doesn't seem to trigger the signal contentsMoved in the
// TQScrollview, so that we better call setCurrentPage() ourselves.
pageWidget = (DocumentWidget*)(widgetList[page % visiblePages]);
scrollView()->moveViewportToWidget(pageWidget, y);
// Set current page number.
setCurrentPageNumber(page);
return true;
}
else if (widgetList.size() == 1)
{
// If the widget list contains only a single element, then either
// the document contains only one page, or we are in "single page"
// view mode. In either case, we set the page number of the single
// widget to 'page'
pageWidget = (DocumentWidget*)(widgetList[0]);
// Paranoia security check
if (pageWidget == 0) {
kdError(4300) << "KMultiPage::goto_Page() called with widgetList.size() == 1, but widgetList[0] == 0" << endl;
return false;
}
if (pageCache->sizeOfPageInPixel(currentPageNumber()) == pageCache->sizeOfPageInPixel(page))
{
// We are rendering the page before we switch the widget to the new page.
// To make a smooth transition. We only do this if the size of the current and new page are equal,
// otherwise we would have to render the page twice, if autozoom is enabled.
pageCache->getPage(page);
}
pageWidget->setPageNumber(page);
scrollView()->layoutPages();
scrollView()->moveViewportToWidget(pageWidget, y);
} else {
// There are multiple widgets, then we are either in the
// "Continuous" or in the "Continouous-Facing" view mode. In that
// case, we find the widget which is supposed to display page
// 'page' and move the scrollview to make it visible
// Paranoia security checks
if (widgetList.size() < page) {
kdError(4300) << "KMultiPage::goto_Page(page,y ) called with widgetList.size()=" << widgetList.size() << ", and page=" << page << endl;
return false;
}
pageWidget = (DocumentWidget*)(widgetList[page-1]);
if (pageWidget == 0) {
kdError(4300) << "KMultiPage::goto_Page() called with widgetList.size() > 1, but widgetList[page] == 0" << endl;
return false;
}
scrollView()->moveViewportToWidget(pageWidget, y);
}
if (isLink && y != 0)
pageWidget->flash(y);
// Set current page number.
setCurrentPageNumber(page);
return true;
}
void KMultiPage::handleLocalLink(const TQString &linkText)
{
#ifdef DEBUG_SPECIAL
kdDebug(4300) << "hit: local link to " << linkText << endl;
#endif
if (renderer.isNull()) {
kdError(4300) << "KMultiPage::handleLocalLink( " << linkText << " ) called, but renderer==0" << endl;
return;
}
TQString locallink;
if (linkText[0] == '#' )
locallink = linkText.mid(1); // Drop the '#' at the beginning
else
locallink = linkText;
Anchor anch = renderer->findAnchor(locallink);
if (anch.isValid())
gotoPage(anch);
else {
if (linkText[0] != '#' ) {
// We could in principle use KIO::Netaccess::run() here, but
// it is perhaps not a very good idea to allow a DVI-file to
// specify arbitrary commands, such as "rm -rvf /". Using
// the kfmclient seems to be MUCH safer.
TQUrl DVI_Url(m_file);
TQUrl Link_Url(DVI_Url, linkText, true);
TQStringList args;
args << "openURL";
args << Link_Url.toString();
kapp->tdeinitExec("kfmclient", args);
}
}
}
void KMultiPage::setCurrentPageNumber(const PageNumber& page)
{
#ifdef DEBUG_KMULTIPAGE
kdDebug(1233) << "KMultiPage::setCurrentPageNumber()" << endl;
#endif
if (page != currentPageNumber())
{
markList()->setCurrentPageNumber(page);
emit pageInfo(numberOfPages(), currentPageNumber());
}
}
PageNumber KMultiPage::currentPageNumber()
{
return markList()->currentPageNumber();
}
void KMultiPage::doGoBack()
{
HistoryItem *it = document_history.back();
if (it != 0)
gotoPage(it->page, it->ypos, false); // Do not add a history item.
else
kdDebug(4300) << "Faulty return -- bad history buffer" << endl;
return;
}
void KMultiPage::doGoForward()
{
HistoryItem *it = document_history.forward();
if (it != 0)
gotoPage(it->page, it->ypos, false); // Do not add a history item.
else
kdDebug(4300) << "Faulty return -- bad history buffer" << endl;
return;
}
void KMultiPage::renderModeChanged()
{
pageCache->clear();
generateDocumentWidgets();
scrollView()->layoutPages();
for (TQ_UINT16 i=0; i < widgetList.size(); i++)
{
DocumentWidget* documentWidget = widgetList[i];
if (documentWidget == 0)
continue;
documentWidget->update();
}
markList()->repaintThumbnails();
}
void KMultiPage::repaintAllVisibleWidgets()
{
#ifdef DEBUG_KMULTIPAGE
kdDebug(1233) << "KMultiPage::repaintAllVisibleWidgets()" << endl;
#endif
bool everResized = false;
// Go through the list of widgets and resize them, if necessary
for(TQ_UINT16 i=0; i<widgetList.size(); i++)
{
DocumentWidget* documentWidget = widgetList[i];
if (documentWidget == 0)
continue;
// Resize, if necessary
TQSize pageSize = pageCache->sizeOfPageInPixel(documentWidget->getPageNumber());
if (pageSize != documentWidget->pageSize())
{
documentWidget->setPageSize(pageSize);
everResized = true;
}
}
// If at least one widget was resized, all widgets should be
// re-aligned. This will automatically update all necessary
// widgets.
if (everResized == true)
scrollView()->layoutPages(true);
}
double KMultiPage::setZoom(double zoom)
{
#ifdef DEBUG_KMULTIPAGE
kdDebug(1233) << "KMultiPage::setZoom(" << zoom << ")" << endl;
#endif
if (zoom < ZoomLimits::MinZoom/1000.0)
zoom = ZoomLimits::MinZoom/1000.0;
if (zoom > ZoomLimits::MaxZoom/1000.0)
zoom = ZoomLimits::MaxZoom/1000.0;
pageCache->setResolution(TQPaintDevice::x11AppDpiX()*zoom);
emit zoomChanged();
return zoom;
}
void KMultiPage::print()
{
// Paranoid safety checks
if (renderer.isNull())
return;
if (renderer->isEmpty())
return;
// Allocate the printer structure
KPrinter *printer = getPrinter();
if (printer == 0)
return;
// initialize the printer using the print dialog
if ( printer->setup(parentWdg, i18n("Print %1").tqarg(m_file.section('/', -1))) ) {
// Now do the printing.
TQValueList<int> pageList = printer->pageList();
if (pageList.isEmpty())
printer->abort();
else {
printer->setCreator("kviewshell");
printer->setDocName(m_file);
RenderedDocumentPagePrinter rdpp(printer);
// Obtain papersize information that is required to perform
// the resizing and centering, if this is wanted by the user.
Length paperWidth, paperHeight;
TQPaintDeviceMetrics pdm(printer);
paperWidth.setLength_in_mm(pdm.widthMM());
paperHeight.setLength_in_mm(pdm.heightMM());
TQValueList<int>::ConstIterator it = pageList.begin();
while (true) {
SimplePageSize paper_s(paperWidth, paperHeight);
// Printing usually takes a while. This is to keep the GUI
// updated.
tqApp->processEvents();
TQPainter *paint = rdpp.getPainter();
if (paint != 0) {
// Before drawing the page, we figure out the zoom-value,
// taking the "page sizes and placement" options from the
// printer dialog into account
double factual_zoom = 1.0;
// Obtain pagesize information that is required to perform the
// resizing and centering, if this is wanted by the user.
SimplePageSize page_s = sizeOfPage(*it);
paint->save();
// Rotate the page, if appropriate. By default, page
// rotation is enabled. This is also hardcoded into
// KPrintDialogPage_PageOptions.cpp
if ((page_s.isPortrait() != paper_s.isPortrait()) && (printer->option( "kde-kviewshell-rotatepage" ) != "false")) {
paint->rotate(-90);
paint->translate(-printer->resolution()*paperHeight.getLength_in_inch(), 0.0);
paper_s = paper_s.rotate90();
}
double suggested_zoom = page_s.zoomToFitInto(paper_s);
// By default, "shrink page" and "expand page" are off. This
// is also hardcoded into KPrintDialogPage_PageOptions.cpp
if ((suggested_zoom < 1.0) && (printer->option( "kde-kviewshell-shrinkpage" ) == "true"))
factual_zoom = suggested_zoom;
if ((suggested_zoom > 1.0) && (printer->option( "kde-kviewshell-expandpage" ) == "true"))
factual_zoom = suggested_zoom;
Length delX, delY;
// By default, "center page" is on. This is also hardcoded
// into KPrintDialogPage_PageOptions.cpp
if (printer->option( "kde-kviewshell-centerpage" ) != "false") {
delX = (paper_s.width() - page_s.width()*factual_zoom)/2.0;
delY = (paper_s.height() - page_s.height()*factual_zoom)/2.0;
}
// Now draw the page.
rdpp.setPageNumber(*it);
double resolution = factual_zoom*printer->resolution();
paint->translate(resolution*delX.getLength_in_inch(), resolution*delY.getLength_in_inch());
renderer->drawPage(resolution, &rdpp);
paint->restore();
}
++it;
if ((it == pageList.end()) || (printer->aborted() == true))
break;
printer->newPage();
}
// At this point the rdpp is destructed. The last page is then
// printed.
}
}
delete printer;
}
void KMultiPage::setRenderer(DocumentRenderer* _renderer)
{
renderer = _renderer;
// Initialize documentPageCache.
initializePageCache();
pageCache->setRenderer(renderer);
_markList->setPageCache(pageCache);
// Clear widget list.
widgetList.resize(0);
// Relay signals.
connect(renderer, TQT_SIGNAL(setStatusBarText(const TQString&)), this, TQT_SIGNAL(setStatusBarText(const TQString&)));
connect(pageCache, TQT_SIGNAL(paperSizeChanged()), this, TQT_SLOT(renderModeChanged()));
connect(pageCache, TQT_SIGNAL(textSelected(bool)), this, TQT_SIGNAL(textSelected(bool)));
connect(renderer, TQT_SIGNAL(documentIsChanged()), this, TQT_SLOT(renderModeChanged()));
connect(this, TQT_SIGNAL(zoomChanged()), this, TQT_SLOT(repaintAllVisibleWidgets()));
}
void KMultiPage::updateWidgetSize(const PageNumber& pageNumber)
{
for(TQ_UINT16 i=0; i<widgetList.size(); i++)
{
DocumentWidget* documentWidget = widgetList[i];
if (documentWidget == 0)
continue;
if (documentWidget->getPageNumber() == pageNumber)
{
// Resize, if necessary
TQSize pageSize = pageCache->sizeOfPageInPixel(documentWidget->getPageNumber());
if (pageSize != documentWidget->pageSize())
{
documentWidget->setPageSize(pageSize);
scrollView()->layoutPages();
}
// We have just one widget per page.
break;
}
}
// Update marklist
markList()->updateWidgetSize(pageNumber);
}
PageNumber KMultiPage::widestPage() const
{
Length maxWidth;
PageNumber pageNumber = 1;
for (int i = 1; i <= numberOfPages(); i++)
{
Length width = pageCache->sizeOfPage(i).width();
if (width > maxWidth)
{
maxWidth = width;
pageNumber = i;
}
}
return pageNumber;
}
double KMultiPage::zoomForWidthColumns(unsigned int viewportWidth) const
{
Length maxLeftColumnWidth;
Length maxRightColumnWidth;
Length maxWidth;
PageNumber widestPageLeft;
PageNumber widestPageRight;
for (int i = 1; i <= numberOfPages(); i++)
{
Length width = pageCache->sizeOfPage(i).width();
if ( i % 2 == 0) // page is in left column
{
if (width > maxLeftColumnWidth)
{
maxLeftColumnWidth = width;
widestPageLeft = i;
}
}
if ( i % 2 == 1) // page is in right column
{
if (width > maxRightColumnWidth)
maxRightColumnWidth = width;
widestPageRight = i;
}
}
double ratio = maxLeftColumnWidth / (maxLeftColumnWidth + maxRightColumnWidth);
// This number is the amount of space the left column should occupy in the viewport.
unsigned int leftTargetWidth = (unsigned int)(ratio * viewportWidth);
return pageCache->sizeOfPage(widestPageLeft).zoomForWidth(leftTargetWidth);
}
double KMultiPage::calculateFitToHeightZoomValue()
{
PageNumber pageNumber = 1;
// See below, in the documentation of the method "calculatefitToWidthZoomLevel"
// for an explanation of the complicated calculation we are doing here.
int columns = scrollView()->getNrColumns();
int rows = scrollView()->getNrRows();
int continuousViewmode = scrollView()->isContinuous();
bool fullScreenMode = scrollView()->fullScreenMode();
if (columns == 1 && rows == 1 && !continuousViewmode) // single page mode
{
pageNumber = currentPageNumber();
if (!pageNumber.isValid())
pageNumber = 1;
}
int pageDistance = scrollView()->distanceBetweenPages();
if (columns == 1 && rows == 1 && !continuousViewmode && fullScreenMode)
{
// In Single Page Fullscreen Mode we want to fit the page to the
// window without a margin around it.
pageDistance = 0;
}
int targetViewportHeight = scrollView()->viewportSize(0,0).height();
int targetPageHeight = (targetViewportHeight - rows*pageDistance)/rows;
int targetPageWidth = (int)(targetPageHeight * pageCache->sizeOfPage(pageNumber).aspectRatio() );
int targetViewportWidth = targetPageWidth * columns + (columns+1)*pageDistance;
targetViewportHeight = scrollView()->viewportSize(targetViewportWidth, targetViewportHeight).height();
targetPageHeight = (targetViewportHeight - rows*pageDistance)/rows;
return pageCache->sizeOfPage(pageNumber).zoomForHeight(targetPageHeight);
}
double KMultiPage::calculateFitToWidthZoomValue()
{
PageNumber pageNumber = 1;
int columns = scrollView()->getNrColumns();
int rows = scrollView()->getNrRows();
int continuousViewmode = scrollView()->isContinuous();
bool fullScreenMode = scrollView()->fullScreenMode();
if (columns == 1 && rows == 1 && !continuousViewmode) // single page mode
{
// To calculate the zoom level in single page mode we need the size
// of the current page. When a new document is opened this function
// is called while the currentPageNumber is invalid. We use the size
// of the first page of the document in this case.
pageNumber = currentPageNumber();
if (!pageNumber.isValid())
pageNumber = 1;
}
if (columns == 1 && rows == 1 && continuousViewmode) // continuous viewmode
{
pageNumber = widestPage();
if (!pageNumber.isValid())
pageNumber = 1;
}
// rows should be 1 for Single Page Viewmode,
// the number of Pages in Continuous Viewmode
// and number of Pages/2 in Continuous-Facing Viewmode
if (continuousViewmode)
rows = (int)(ceil(numberOfPages() / (double)columns));
int pageDistance = scrollView()->distanceBetweenPages();
if (columns == 1 && rows == 1 && !continuousViewmode && fullScreenMode)
{
// In Single Page Fullscreen Mode we want to fit the page to the
// window without a margin around it.
pageDistance = 0;
}
// There is a slight complication here... if we just take the width
// of the viewport and scale the contents by a factor x so that it
// fits the viewport exactly, then, depending on chosen papersize
// (landscape, etc.), the contents may be higher than the viewport
// and the TQScrollview may or may not insert a scrollbar at the
// right. If the scrollbar appears, then the usable width of the
// viewport becomes smaller, and scaling by x does not really fit
// the (now smaller page) anymore.
// Calculate the width and height of the view, disregarding the
// possible complications with scrollbars, e.g. assuming the maximal
// space is available.
// width of the widget excluding possible scrollbars
int targetViewportWidth = scrollView()->viewportSize(0,0).width();
// maximal width of a single page
int targetPageWidth = (targetViewportWidth - (columns+1) * pageDistance) / columns;
// maximal height of a single page
int targetPageHeight = (int)(targetPageWidth/pageCache->sizeOfPage(pageNumber).aspectRatio());
// FIXME: this is only correct if all pages in the document have the same height
int targetViewportHeight = rows * targetPageHeight + (rows+1) * pageDistance;
// Think again, this time use only the area which is really
// acessible (which, in case that targetWidth targetHeight don't fit
// the viewport, is really smaller because of the scrollbars).
targetViewportWidth = scrollView()->viewportSize(targetViewportWidth, targetViewportHeight).width();
if (columns == 2 && continuousViewmode) // continuous facing
{
// TODO Generalize this for more than 2 columns
return zoomForWidthColumns(targetViewportWidth - (columns+1) * pageDistance);
}
// maximal width of a single page (now the scrollbars are taken into account)
targetPageWidth = (targetViewportWidth - (columns+1) * pageDistance) / columns;
return pageCache->sizeOfPage(pageNumber).zoomForWidth(targetPageWidth);
}
void KMultiPage::prevPage()
{
TQ_UINT8 cols = scrollView()->getNrColumns();
TQ_UINT8 rows = scrollView()->getNrRows();
PageNumber np = 1;
if (cols*rows < currentPageNumber())
{
np = currentPageNumber() - cols*rows;
}
gotoPage(np);
}
void KMultiPage::nextPage()
{
TQ_UINT8 cols = scrollView()->getNrColumns();
TQ_UINT8 rows = scrollView()->getNrRows();
PageNumber np = TQMIN(currentPageNumber() + cols*rows, (TQ_UINT16)numberOfPages());
gotoPage(np);
}
void KMultiPage::firstPage()
{
gotoPage(1);
}
void KMultiPage::lastPage()
{
gotoPage(numberOfPages());
}
void KMultiPage::scroll(TQ_INT32 deltaInPixel)
{
TQScrollBar* scrollBar = scrollView()->verticalScrollBar();
if (scrollBar == 0) {
kdError(4300) << "KMultiPage::scroll called without scrollBar" << endl;
return;
}
if (deltaInPixel < 0) {
if (scrollBar->value() == scrollBar->minValue()) {
if ( (currentPageNumber() == 1) || (changePageDelayTimer.isActive()) )
return;
if (scrollView()->isContinuous())
return;
changePageDelayTimer.stop();
prevPage();
scrollView()->setContentsPos(scrollView()->contentsX(), scrollBar->maxValue());
return;
}
}
if (deltaInPixel > 0) {
if (scrollBar->value() == scrollBar->maxValue()) {
if ( (currentPageNumber() == numberOfPages()) || (changePageDelayTimer.isActive()) )
return;
if (scrollView()->isContinuous())
return;
changePageDelayTimer.stop();
nextPage();
scrollView()->setContentsPos(scrollView()->contentsX(), 0);
return;
}
}
scrollBar->setValue(scrollBar->value() + deltaInPixel);
if ( (scrollBar->value() == scrollBar->maxValue()) || (scrollBar->value() == scrollBar->minValue()) )
changePageDelayTimer.start(200,true);
else
changePageDelayTimer.stop();
}
void KMultiPage::scrollUp()
{
TQScrollBar* scrollBar = scrollView()->verticalScrollBar();
if (scrollBar == 0)
return;
scroll(-scrollBar->lineStep());
}
void KMultiPage::scrollDown()
{
TQScrollBar* scrollBar = scrollView()->verticalScrollBar();
if (scrollBar == 0)
return;
scroll(scrollBar->lineStep());
}
void KMultiPage::scrollLeft()
{
TQScrollBar* scrollBar = scrollView()->horizontalScrollBar();
if (scrollBar)
scrollBar->subtractLine();
}
void KMultiPage::scrollRight()
{
TQScrollBar* scrollBar = scrollView()->horizontalScrollBar();
if (scrollBar)
scrollBar->addLine();
}
void KMultiPage::scrollUpPage()
{
TQScrollBar* scrollBar = scrollView()->verticalScrollBar();
if (scrollBar)
scrollBar->subtractPage();
}
void KMultiPage::scrollDownPage()
{
TQScrollBar* scrollBar = scrollView()->verticalScrollBar();
if (scrollBar)
scrollBar->addPage();
}
void KMultiPage::scrollLeftPage()
{
TQScrollBar* scrollBar = scrollView()->horizontalScrollBar();
if (scrollBar)
scrollBar->subtractPage();
}
void KMultiPage::scrollRightPage()
{
TQScrollBar* scrollBar = scrollView()->horizontalScrollBar();
if (scrollBar)
scrollBar->addPage();
}
void KMultiPage::readDown()
{
PageView* sv = scrollView();
if (sv->atBottom())
{
if (sv->isContinuous())
return;
if (currentPageNumber() == numberOfPages())
return;
nextPage();
sv->setContentsPos(sv->contentsX(), 0);
}
else
sv->readDown();
}
void KMultiPage::readUp()
{
PageView* sv = scrollView();
if (sv->atTop())
{
if (sv->isContinuous())
return;
if (currentPageNumber() == 1)
return;
prevPage();
sv->setContentsPos(sv->contentsX(), sv->contentsHeight());
}
else
sv->readUp();
}
void KMultiPage::jumpToReference(const TQString& reference)
{
if (renderer.isNull())
return;
gotoPage(renderer->parseReference(reference));
}
void KMultiPage::gotoPage(const Anchor &a)
{
if (!a.page.isValid() || (renderer.isNull()))
return;
gotoPage(a.page, (int)(a.distance_from_top.getLength_in_inch()*pageCache->getResolution() + 0.5), true);
}
void KMultiPage::gotoPage(const TextSelection& selection)
{
if (selection.isEmpty())
{
kdError(4300) << "KMultiPage::gotoPage(...) called with empty TextSelection." << endl;
return;
}
RenderedDocumentPage* pageData = pageCache->getPage(selection.getPageNumber());
if (pageData == 0) {
#ifdef DEBUG_DOCUMENTWIDGET
kdDebug(4300) << "DocumentWidget::paintEvent: no documentPage generated" << endl;
#endif
return;
}
switch (widgetList.size())
{
case 0:
kdError(4300) << "KMultiPage::select() while widgetList is empty" << endl;
break;
case 1:
((DocumentWidget*)widgetList[0])->select(selection);
break;
default:
if (widgetList.size() < currentPageNumber())
kdError(4300) << "KMultiPage::select() while widgetList.size()=" << widgetList.size() << "and currentPageNumber()=" << currentPageNumber() << endl;
else
((DocumentWidget*)widgetList[selection.getPageNumber() - 1])->select(selection);
}
unsigned int y = pageData->textBoxList[selection.getSelectedTextStart()].box.top();
gotoPage(selection.getPageNumber(), y, false);
}
void KMultiPage::doSelectAll()
{
switch( widgetList.size() ) {
case 0:
kdError(4300) << "KMultiPage::doSelectAll() while widgetList is empty" << endl;
break;
case 1:
((DocumentWidget *)widgetList[0])->selectAll();
break;
default:
if (widgetList.size() < currentPageNumber())
kdError(4300) << "KMultiPage::doSelectAll() while widgetList.size()=" << widgetList.size() << "and currentPageNumber()=" << currentPageNumber() << endl;
else
((DocumentWidget *)widgetList[currentPageNumber()-1])->selectAll();
}
}
void KMultiPage::showFindTextDialog()
{
if ((renderer.isNull()) || (renderer->supportsTextSearch() == false))
return;
searchWidget->show();
searchWidget->setFocus();
}
void KMultiPage::stopSearch()
{
if (searchInProgress)
{
// stop the search
searchInProgress = false;
}
else
searchWidget->hide();
}
void KMultiPage::findNextText()
{
#ifdef KDVI_MULTIPAGE_DEBUG
kdDebug(4300) << "KMultiPage::findNextText() called" << endl;
#endif
searchInProgress = true;
// Used to remember if the documentPage we use is from the cache.
// If not we need to delete it manually to avoid a memory leak.
bool cachedPage = false;
TQString searchText = searchWidget->getText();
if (searchText.isEmpty())
{
kdError(4300) << "KMultiPage::findNextText() called when search text was empty" << endl;
return;
}
bool case_sensitive = searchWidget->caseSensitive();
// Find the page and text position on the page where the search will
// start. If nothing is selected, we start at the beginning of the
// current page. Otherwise, start after the selected text. TODO:
// Optimize this to get a better 'user feeling'
TQ_UINT16 startingPage;
TQ_UINT16 startingTextItem;
TextSelection userSelection = pageCache->selectedText();
if (userSelection.isEmpty())
{
startingPage = currentPageNumber();
startingTextItem = 0;
}
else
{
startingPage = userSelection.getPageNumber();
startingTextItem = userSelection.getSelectedTextEnd()+1;
}
TextSelection foundSelection;
RenderedDocumentPagePixmap* searchPage = 0;
for(unsigned int i = 0; i < numberOfPages(); i++)
{
unsigned int pageNumber = (i + startingPage - 1) % numberOfPages() + 1;
if (!searchInProgress)
{
// Interrupt the search
setStatusBarText(i18n("Search interrupted"));
if (!cachedPage)
delete searchPage;
return;
}
if (i != 0)
{
setStatusBarText(i18n("Search page %1 of %2").tqarg(pageNumber).tqarg(numberOfPages()));
kapp->processEvents();
}
// Check if we already have a rendered version of the page in the cache. As we are only interested in the
// text we don't care about the page size.
if (pageCache->isPageCached(pageNumber))
{
// If the last search page used was created locally, we need to destroy it
if (!cachedPage)
delete searchPage;
searchPage = pageCache->getPage(pageNumber);
cachedPage = true;
}
else
{
// If the page is not in the cache we draw a small version of it, since this is faster.
// We only create a new searchPage if we need to, otherwise reuse the existing one.
if (!searchPage || cachedPage)
searchPage = new RenderedDocumentPagePixmap();
cachedPage = false;
searchPage->resize(1,1);
searchPage->setPageNumber(pageNumber);
renderer->getText(searchPage);
}
// If there is no text in the current page, try the next one.
if (searchPage->textBoxList.size() == 0)
continue;
foundSelection = searchPage->find(searchText, startingTextItem, case_sensitive);
if (foundSelection.isEmpty())
{
// In the next page, start search again at the beginning.
startingTextItem = 0;
clearSelection();
if (pageNumber == numberOfPages())
{
int answ = KMessageBox::questionYesNo(scrollView(),
i18n("<qt>The search string <strong>%1</strong> could not be found by the "
"end of the document. Should the search be restarted from the beginning "
"of the document?</qt>").tqarg(searchText),
i18n("Text Not Found"), KStdGuiItem::cont(), KStdGuiItem::cancel());
if (answ != KMessageBox::Yes)
{
setStatusBarText(TQString());
searchInProgress = false;
if (!cachedPage)
delete searchPage;
return;
}
}
}
else
{
pageCache->selectText(foundSelection);
gotoPage(pageCache->selectedText());
setStatusBarText(TQString());
searchInProgress = false;
if (!cachedPage)
delete searchPage;
return;
}
}
KMessageBox::sorry(scrollView(), i18n("<qt>The search string <strong>%1</strong> could not be found.</qt>").tqarg(searchText));
setStatusBarText(TQString());
searchInProgress = false;
if (!cachedPage)
delete searchPage;
}
void KMultiPage::findPrevText()
{
#ifdef KDVI_MULTIPAGE_DEBUG
kdDebug(4300) << "KMultiPage::findPrevText() called" << endl;
#endif
searchInProgress = true;
// Used to remember if the documentPage we use is from the cache.
// If not we need to delete it manually to avoid a memory leak.
bool cachedPage = false;
TQString searchText = searchWidget->getText();
if (searchText.isEmpty())
{
kdError(4300) << "KMultiPage::findPrevText() called when search text was empty" << endl;
return;
}
bool case_sensitive = searchWidget->caseSensitive();
// Find the page and text position on the page where the search will
// start. If nothing is selected, we start at the beginning of the
// current page. Otherwise, start after the selected text. TODO:
// Optimize this to get a better 'user feeling'
unsigned int startingPage;
int startingTextItem;
TextSelection userSelection = pageCache->selectedText();
if (userSelection.isEmpty())
{
startingPage = currentPageNumber();
startingTextItem = -1;
}
else
{
startingPage = userSelection.getPageNumber();
startingTextItem = userSelection.getSelectedTextStart()-1;
}
TextSelection foundSelection;
RenderedDocumentPagePixmap* searchPage = 0;
for(unsigned int i = 0; i < numberOfPages(); i++)
{
int pageNumber = startingPage - i;
if (pageNumber <= 0)
pageNumber += numberOfPages();
if (!searchInProgress)
{
// Interrupt the search
setStatusBarText(i18n("Search interrupted"));
if (!cachedPage)
delete searchPage;
return;
}
if (i != 0)
{
setStatusBarText(i18n("Search page %1 of %2").tqarg(pageNumber).tqarg(numberOfPages()));
kapp->processEvents();
}
// Check if we already have a rendered version of the page in the cache. As we are only interested in the
// text we don't care about the page size.
if (pageCache->isPageCached(pageNumber))
{
// If the last search page used was created locally, we need to destroy it
if (!cachedPage)
delete searchPage;
searchPage = pageCache->getPage(pageNumber);
cachedPage = true;
}
else
{
// If the page is not in the cache we draw a small version of it, since this is faster.
// We only create a new searchPage if we need to, otherwise reuse the existing one.
if (!searchPage || cachedPage)
searchPage = new RenderedDocumentPagePixmap();
cachedPage = false;
searchPage->resize(1,1);
searchPage->setPageNumber(pageNumber);
renderer->getText(searchPage);
}
// If there is no text in the current page, try the next one.
if (searchPage->textBoxList.size() == 0)
continue;
foundSelection = searchPage->findRev(searchText, startingTextItem, case_sensitive);
if (foundSelection.isEmpty())
{
// In the next page, start search again at the beginning.
startingTextItem = -1;
clearSelection();
if (pageNumber == 1)
{
int answ = KMessageBox::questionYesNo(scrollView(),
i18n("<qt>The search string <strong>%1</strong> could not be found by the "
"beginning of the document. Should the search be restarted from the end "
"of the document?</qt>").tqarg(searchText),
i18n("Text Not Found"), KStdGuiItem::cont(), KStdGuiItem::cancel());
if (answ != KMessageBox::Yes)
{
setStatusBarText(TQString());
searchInProgress = false;
if (!cachedPage)
delete searchPage;
return;
}
}
}
else
{
pageCache->selectText(foundSelection);
gotoPage(pageCache->selectedText());
setStatusBarText(TQString());
searchInProgress = false;
if (!cachedPage)
delete searchPage;
return;
}
}
KMessageBox::sorry(scrollView(), i18n("<qt>The search string <strong>%1</strong> could not be found.</qt>").tqarg(searchText));
setStatusBarText(TQString());
searchInProgress = false;
if (!cachedPage)
delete searchPage;
}
void KMultiPage::clearSelection()
{
PageNumber page = pageCache->selectedText().getPageNumber();
if (!page.isValid())
return;
// Clear selection
pageCache->deselectText();
// Now we need to update the widget which contained the selection
switch(widgetList.size())
{
case 0:
kdError(4300) << "KMultiPage::clearSelection() while widgetList is empty" << endl;
break;
case 1:
widgetList[0]->update();
break;
default:
for (unsigned int i = 0; i < widgetList.size(); i++)
{
DocumentWidget* pageWidget = (DocumentWidget*)widgetList[i];
if (pageWidget->getPageNumber() == page)
{
pageWidget->update();
break;
}
}
}
}
void KMultiPage::copyText()
{
pageCache->selectedText().copyText();
}
void KMultiPage::timerEvent( TQTimerEvent * )
{
#ifdef KMULTIPAGE_DEBUG
kdDebug(4300) << "Timer Event " << endl;
#endif
reload();
}
void KMultiPage::reload()
{
#ifdef KMULTIPAGE_DEBUG
kdDebug(4300) << "Reload file " << m_file << endl;
#endif
if (renderer.isNull()) {
kdError() << "KMultiPage::reload() called, but no renderer was set" << endl;
return;
}
if (renderer->isValidFile(m_file)) {
pageCache->clear();
pageCache->deselectText();
document_history.clear();
emit setStatusBarText(i18n("Reloading file %1").tqarg(m_file));
TQ_INT32 pg = currentPageNumber();
killTimer(timer_id);
timer_id = -1;
bool r = renderer->setFile(m_file, m_url);
generateDocumentWidgets();
// Set Table of Contents
tableOfContents->setContents(renderer->getBookmarks());
// Adjust number of widgets in the thumbnail sidebar
markList()->clear();
markList()->setNumberOfPages(numberOfPages(), KVSPrefs::showThumbnails());
setCurrentPageNumber(pg);
setFile(r);
emit setStatusBarText(TQString());
} else {
if (timer_id == -1)
timer_id = startTimer(1000);
}
}
bool KMultiPage::openFile()
{
if (renderer.isNull()) {
kdError(4300) << "KMultiPage::openFile() called when no renderer was set" << endl;
return false;
}
pageCache->deselectText();
document_history.clear();
pageCache->clear();
emit setStatusBarText(i18n("Loading file %1").tqarg(m_file));
bool r = renderer->setFile(m_file, m_url);
if (r) {
setCurrentPageNumber(1);
generateDocumentWidgets();
// Set number of widgets in the thumbnail sidebar
markList()->clear();
markList()->setNumberOfPages(numberOfPages(), KVSPrefs::showThumbnails());
TQString reference = url().ref();
if (!reference.isEmpty())
gotoPage(renderer->parseReference(reference));
// Set Table of Contents
tableOfContents->setContents(renderer->getBookmarks());
} else
m_file = TQString();
setFile(r);
// Clear Statusbar
emit setStatusBarText(TQString());
return r;
}
bool KMultiPage::openURL(const TQString &filename, const KURL &base_url)
{
m_file = filename;
m_url = base_url;
bool success = openFile();
if (success)
setCurrentPageNumber(1);
return success;
}
void KMultiPage::enableActions(bool fileLoaded)
{
Q_UNUSED(fileLoaded);
}
void KMultiPage::wheelEvent(TQWheelEvent *e)
{
TQScrollBar *sb = scrollView()->verticalScrollBar();
if (sb == 0)
return;
// Zoom in/out
if (e->state() & ControlButton)
{
if (e->delta() < 0)
emit zoomOut();
else
emit zoomIn();
return;
}
TQ_INT32 pxl = -(e->delta()*sb->lineStep())/60;
if (pxl == 0)
{
if (e->delta() > 0)
pxl = -1;
else
pxl = 1;
}
// Faster scrolling
if (e->state() & ShiftButton)
pxl *= 10;
scroll(pxl);
}
KPrinter *KMultiPage::getPrinter(bool enablePageSizeFeatures)
{
// Allocate a new KPrinter structure, if necessary
KPrinter *printer = new KPrinter(true);
if (printer == 0) {
kdError(1223) << "KMultiPage::getPrinter(..): Cannot allocate new KPrinter structure" << endl;
return 0;
}
// Allocate a new KPrintDialogPage structure and add it to the
// printer, if the kmultipage implementation requests that
if (enablePageSizeFeatures == true) {
KPrintDialogPage_PageOptions *pageOptions = new KPrintDialogPage_PageOptions();
if (pageOptions == 0) {
kdError(1223) << "KMultiPage::getPrinter(..): Cannot allocate new KPrintDialogPage_PageOptions structure" << endl;
delete printer;
return 0;
}
printer->addDialogPage( pageOptions );
}
// Feed the printer with useful defaults and information.
printer->setPageSelection( KPrinter::ApplicationSide );
printer->setCurrentPage( currentPageNumber() );
printer->setMinMax( 1, numberOfPages() );
printer->setFullPage( true );
// If pages are marked, give a list of marked pages to the
// printer. We try to be smart and optimize the list by using ranges
// ("5-11") wherever possible. The user will be tankful for
// that. Complicated? Yeah, but that's life.
TQValueList<int> selectedPageNo = selectedPages();
if (selectedPageNo.isEmpty() == true)
printer->setOption( "kde-range", "" );
else {
int commaflag = 0;
TQString range;
TQValueList<int>::ConstIterator it = selectedPageNo.begin();
do{
int val = *it;
if (commaflag == 1)
range += TQString(", ");
else
commaflag = 1;
int endval = val;
if (it != selectedPageNo.end()) {
TQValueList<int>::ConstIterator jt = it;
jt++;
do{
int val2 = *jt;
if (val2 == endval+1)
endval++;
else
break;
jt++;
} while( jt != selectedPageNo.end() );
it = jt;
} else
it++;
if (endval == val)
range += TQString("%1").tqarg(val);
else
range += TQString("%1-%2").tqarg(val).tqarg(endval);
} while (it != selectedPageNo.end() );
printer->setOption( "kde-range", range );
}
return printer;
}
void KMultiPage::doExportText()
{
// Generate a suggestion for a reasonable file name
TQString suggestedName = url().filename();
suggestedName = suggestedName.left(suggestedName.find(".")) + ".txt";
TQString fileName = KFileDialog::getSaveFileName(suggestedName, i18n("*.txt|Plain Text (Latin 1) (*.txt)"), scrollView(), i18n("Export File As"));
if (fileName.isEmpty())
return;
TQFileInfo finfo(fileName);
if (finfo.exists())
{
int r = KMessageBox::warningContinueCancel (scrollView(),
i18n("The file %1\nexists. Do you want to overwrite that file?").tqarg(fileName),
i18n("Overwrite File"), i18n("Overwrite"));
if (r == KMessageBox::Cancel)
return;
}
TQFile textFile(fileName);
textFile.open(IO_WriteOnly);
TQTextStream stream(&textFile);
TQProgressDialog progress(i18n("Exporting to text..."), i18n("Abort"), renderer->totalPages(),
scrollView(), "export_text_progress", true);
progress.setMinimumDuration(300);
RenderedDocumentPagePixmap dummyPage;
dummyPage.resize(1, 1);
for(unsigned int page = 1; page <= renderer->totalPages(); page++)
{
progress.setProgress(page);
tqApp->processEvents();
if (progress.wasCancelled())
break;
dummyPage.setPageNumber(page);
// We gracefully ignore any errors (bad file, etc.)
renderer->getText(&dummyPage);
for(unsigned int i = 0; i < dummyPage.textBoxList.size(); i++)
{
// We try to detect newlines
if (i > 0)
{
// Like all our textalgorithmns this currently assumes left to right text.
// TODO: make this more generic. But we first would need to guess the corrent
// orientation.
if (dummyPage.textBoxList[i].box.top() > dummyPage.textBoxList[i-1].box.bottom() &&
dummyPage.textBoxList[i].box.x() < dummyPage.textBoxList[i-1].box.x())
{
stream << "\n";
}
}
stream << dummyPage.textBoxList[i].text;
}
// Send newline after each page.
stream << "\n";
}
// Switch off the progress dialog, etc.
progress.setProgress(renderer->totalPages());
return;
}
void KMultiPage::slotEnableMoveTool(bool enable)
{
emit enableMoveTool(enable);
}
#include "kmultipage.moc"