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.
 
 
 
 
 

414 lines
14 KiB

//
// Class: kdvi_multipage
// Author: Stefan Kebekus
//
// (C) 2001-2004, Stefan Kebekus.
//
// Previewer for TeX DVI files.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
// Please report bugs or improvements, etc. via the "Report bug"-Menu
// of kdvi.
#include <kaction.h>
#include <kdebug.h>
#include <keditcl.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <qapplication.h>
#include <qprogressdialog.h>
#include "documentPagePixmap.h"
#include "documentWidget.h"
#include "kdvi_multipage.h"
//#define KDVI_MULTIPAGE_DEBUG
void KDVIMultiPage::doExportText(void)
{
#ifdef KDVI_MULTIPAGE_DEBUG
kdDebug(4300) << "KDVIMultiPage::doExportText(void) called" << endl;
#endif
// Paranoid safety checks
if ((window == 0) || (window->dviFile == 0))
return;
if (window->dviFile->dvi_Data() == 0 )
return;
if (KMessageBox::warningContinueCancel( scrollView(),
i18n("<qt>This function exports the DVI file to a plain text. Unfortunately, this version of "
"KDVI treats only plain ASCII characters properly. Symbols, ligatures, mathematical "
"formulae, accented characters, and non-english text, such as Russian or Korean, will "
"most likely be messed up completely.</qt>"),
i18n("Function May Not Work as Expected"),
i18n("Continue Anyway"),
"warning_export_to_text_may_not_work") == KMessageBox::Cancel)
return;
// Generate a suggestion for a reasonable file name
QString suggestedName = window->dviFile->filename;
suggestedName = suggestedName.left(suggestedName.find(".")) + ".txt";
QString fileName = KFileDialog::getSaveFileName(suggestedName, i18n("*.txt|Plain Text (Latin 1) (*.txt)"), scrollView(), i18n("Export File As"));
if (fileName.isEmpty())
return;
QFileInfo finfo(fileName);
if (finfo.exists()) {
int r = KMessageBox::warningYesNo (scrollView(), i18n("The file %1\nexists. Do you want to overwrite that file?").arg(fileName),
i18n("Overwrite File"));
if (r == KMessageBox::No)
return;
}
QFile textFile(fileName);
textFile.open( IO_WriteOnly );
QTextStream stream( &textFile );
QProgressDialog progress( i18n("Exporting to text..."), i18n("Abort"), window->dviFile->total_pages, scrollView(), "export_text_progress", TRUE );
progress.setMinimumDuration(300);
documentPagePixmap dummyPage;
dummyPage.resize(1,1);
for(int page=1; page <= window->dviFile->total_pages; page++) {
progress.setProgress( page );
// Funny. The manual to QT tells us that we need to call
// qApp->processEvents() regularly to keep the application from
// freezing. However, the application crashes immediately if we
// uncomment the following line and works just fine as it is. Wild
// guess: Could that be related to the fact that we are linking
// agains qt-mt?
// qApp->processEvents();
if ( progress.wasCancelled() )
break;
dummyPage.setPageNumber(page);
window->drawPage(100.0, &dummyPage); // We gracefully ingore any errors (bad dvi-file, etc.) which may occur during draw_page()
for(unsigned int i=0; i<dummyPage.textLinkList.size(); i++)
stream << dummyPage.textLinkList[i].linkText << endl;
}
// Switch off the progress dialog, etc.
progress.setProgress( window->dviFile->total_pages );
return;
}
void KDVIMultiPage::showFindTextDialog(void)
{
if ((window == 0) || (window->supportsTextSearch() == false))
return;
if (findDialog == 0) {
// WARNING: This text appears several times in the code. Change
// everywhere, or nowhere!
if (KMessageBox::warningContinueCancel( scrollView(),
i18n("<qt>This function searches the DVI file for plain text. Unfortunately, this version of "
"KDVI treats only plain ASCII characters properly. Symbols, ligatures, mathematical "
"formulae, accented characters, and non-english text, such as Russian or Korean, will "
"most likely be messed up completely. Continue anyway?</qt>"),
i18n("Function May Not Work as Expected"),
KStdGuiItem::cont(),
"warning_search_text_may_not_work") == KMessageBox::Cancel)
return;
findDialog = new KEdFind( scrollView(), "Text find dialog", true);
if (findDialog == 0) {
kdError(4300) << "Could not open text search dialog" << endl;
return;
}
findDialog->setName("text search dialog");
connect(findDialog, SIGNAL(search()), this, SLOT(findText()));
}
findDialog->show();
}
void KDVIMultiPage::findText(void)
{
#ifdef KDVI_MULTIPAGE_DEBUG
kdDebug(4300) << "KDVIMultiPage::findText(void) called" << endl;
#endif
// Paranoid security checks
if (findDialog == 0) {
kdError(4300) << "KDVIMultiPage::findText(void) called but findDialog == 0" << endl;
return;
}
QString searchText = findDialog->getText();
if (searchText.isEmpty())
return;
if (findNextAction != 0)
findNextAction->setEnabled(!searchText.isEmpty());
if (findPrevAction != 0)
findPrevAction->setEnabled(!searchText.isEmpty());
if (findDialog->get_direction())
findPrevText();
else
findNextText();
}
void KDVIMultiPage::findNextText(void)
{
#ifdef KDVI_MULTIPAGE_DEBUG
kdDebug(4300) << "KDVIMultiPage::findNextText() called" << endl;
#endif
// Paranoia safety checks
if (findDialog == 0) {
kdError(4300) << "KDVIMultiPage::findNextText(void) called when findDialog == 0" << endl;
return;
}
QString searchText = findDialog->getText();
if (searchText.isEmpty()) {
kdError(4300) << "KDVIMultiPage::findNextText(void) called when search text was empty" << endl;
return;
}
bool case_sensitive = findDialog->case_sensitive();
bool oneTimeRound = false;
QProgressDialog progress( i18n("Searching for '%1'...").arg(searchText), i18n("Abort"),
window->dviFile->total_pages, scrollView(), "searchForwardTextProgress", TRUE );
progress.setMinimumDuration ( 1000 );
documentPagePixmap dummyPage;
dummyPage.resize(1,1);
// 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'
Q_UINT16 startingPage;
Q_UINT16 startingTextItem;
if (userSelection.getPageNumber() == 0) {
startingPage = getCurrentPageNumber();
startingTextItem = 0;
} else {
startingPage = userSelection.getPageNumber();
startingTextItem = userSelection.getSelectedTextEnd()+1;
}
for(Q_UINT16 pageNumber = startingPage;; pageNumber++) {
// If we reach the end of the last page, start from the beginning
// of the document, but ask the user first.
if (pageNumber > window->dviFile->total_pages) {
progress.hide();
if (oneTimeRound == true)
break;
oneTimeRound = true;
// Do not ask the user if the search really started from the
// beginning of the first page
if ( (startingPage == 1)&&(startingTextItem == 0) )
return;
int answ = KMessageBox::questionYesNo(scrollView(), i18n("<qt>The search string <strong>%1</strong> could not be found till the "
"end of the document. Should the search be restarted from the beginning "
"of the document?</qt>").arg(searchText),
i18n("Text Not Found"));
if (answ == KMessageBox::Yes)
pageNumber = 1;
else
return;
}
if (pageNumber > startingPage)
progress.setProgress( pageNumber - startingPage );
else
progress.setProgress( pageNumber + window->dviFile->total_pages - startingPage );
qApp->processEvents();
if ( progress.wasCancelled() )
break;
dummyPage.setPageNumber(pageNumber);
window->drawPage(100.0, &dummyPage); // We don't really care for errors in draw_page(), no error handling here.
if (dummyPage.textLinkList.size() == 0)
continue;
// Go trough the text of the page and search for the string. How
// much of the page we actually search depends on the page: we
// start the search on the current page *after* the selected text,
// if there is any, then search the other pages entirely, and then
// the rest of the current page.
if (pageNumber != startingPage) {
// On pages which are not our current page, search through
// everything
for(unsigned int i=0; i<dummyPage.textLinkList.size(); i++)
if (dummyPage.textLinkList[i].linkText.find(searchText, 0, case_sensitive) >= 0) {
gotoPage(pageNumber, i, i );
return;
}
} else {
if (oneTimeRound == false) {
// The first time we search on the current page, search
// everything from the end of the selected text to the end of
// the page
for(unsigned int i=startingTextItem; i<dummyPage.textLinkList.size(); i++)
if (dummyPage.textLinkList[i].linkText.find(searchText, 0, case_sensitive) >= 0) {
gotoPage(pageNumber, i, i );
return;
}
} else {
// The second time we come to the current page, search
// everything from the beginning of the page till the
// beginning of the selected test, then end the search.
for(unsigned int i=0; i<startingTextItem; i++)
if (dummyPage.textLinkList[i].linkText.find(searchText, 0, case_sensitive) >= 0) {
gotoPage(pageNumber, i, i );
return;
}
KMessageBox::sorry( scrollView(), i18n("<qt>The search string <strong>%1</strong> could not be found.</qt>").arg(searchText) );
return;
}
}
}// of while (all pages)
}
void KDVIMultiPage::findPrevText(void)
{
#ifdef KDVI_MULTIPAGE_DEBUG
kdDebug(4300) << "KDVIMultiPage::findPrevText() called" << endl;
#endif
// Paranoia safety checks
if (findDialog == 0) {
kdError(4300) << "KDVIMultiPage::findPrevText(void) called when findDialog == 0" << endl;
return;
}
QString searchText = findDialog->getText();
if (searchText.isEmpty()) {
kdError(4300) << "KDVIMultiPage::findPrevText(void) called when search text was empty" << endl;
return;
}
bool case_sensitive = findDialog->case_sensitive();
bool oneTimeRound = false;
QProgressDialog progress( i18n("Searching for '%1'...").arg(searchText), i18n("Abort"),
window->dviFile->total_pages, scrollView(), "searchForwardTextProgress", TRUE );
progress.setMinimumDuration ( 1000 );
// Find the page and text position on the page where the search will
// start. If nothing is selected, we start at the end of the current
// page. Otherwise, start before the selected text. TODO: Optimize
// this to get a better 'user feeling'
Q_UINT16 startingPage;
Q_UINT16 startingTextItem;
documentPagePixmap dummyPage;
dummyPage.resize(1,1);
if (userSelection.getPageNumber() == 0) {
startingPage = getCurrentPageNumber();
dummyPage.setPageNumber(startingPage);
window->drawPage(100.0, &dummyPage);
startingTextItem = dummyPage.textLinkList.size();
} else {
startingPage = userSelection.getPageNumber();
startingTextItem = userSelection.getSelectedTextStart();
}
for(Q_UINT16 pageNumber = startingPage;; pageNumber--) {
// If we reach the beginning of the last page, start from the end
// of the document, but ask the user first.
if (pageNumber <= 0) {
progress.hide();
if (oneTimeRound == true)
break;
oneTimeRound = true;
int answ = KMessageBox::questionYesNo(scrollView(), i18n("<qt>The search string <strong>%1</strong> could not be found till the "
"beginning of the document. Should the search be restarted from the end "
"of the document?</qt>").arg(searchText),
i18n("Text Not Found"));
if (answ == KMessageBox::Yes)
pageNumber = window->dviFile->total_pages;
else
return;
}
if (pageNumber < startingPage)
progress.setProgress( startingPage - pageNumber );
else
progress.setProgress( startingPage + window->dviFile->total_pages - pageNumber );
qApp->processEvents();
if ( progress.wasCancelled() )
break;
dummyPage.setPageNumber(pageNumber);
window->drawPage(100.0, &dummyPage);
if (dummyPage.textLinkList.size() == 0)
continue;
// Go trough the text of the page and search for the string. How
// much of the page we actually search depends on the page: we
// start the search on the current page *before* the selected
// text, if there is any, then search the other pages entirely,
// and then the rest of the current page.
if (pageNumber != startingPage) {
// On pages which are not our current page, search through
// everything
for(int i=dummyPage.textLinkList.size()-1; i>=0; i--)
if (dummyPage.textLinkList[i].linkText.find(searchText, 0, case_sensitive) >= 0) {
gotoPage(pageNumber, i, i );
return;
}
} else {
if (oneTimeRound == false) {
// The first time we search on the current page, search
// everything from the beginning of the selected text to the
// beginning of the page
for(int i = startingTextItem-1; i>=0; i--) {
if (dummyPage.textLinkList[i].linkText.find(searchText, 0, case_sensitive) >= 0) {
gotoPage(pageNumber, i, i );
return;
}
}
} else {
// The second time we come to the current page, search
// everything from the end of the page till the end of the
// selected test, then end the search.
for(int i=dummyPage.textLinkList.size()-1; i>startingTextItem; i--)
if (dummyPage.textLinkList[i].linkText.find(searchText, 0, case_sensitive) >= 0) {
gotoPage(pageNumber, i, i );
return;
}
KMessageBox::sorry( scrollView(), i18n("<qt>The search string <strong>%1</strong> could not be found.</qt>").arg(searchText) );
return;
}
}
}// of while (all pages)
}