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/renderedDocumentPage.cpp

376 lines
9.3 KiB

//
// Class: RenderedDocumentPage
//
// Widget for displaying TeX DVI files.
// Part of KDVI- A previewer for TeX DVI files.
//
// (C) 2004 Stefan Kebekus. Distributed under the GPL.
#include <config.h>
#include <kdebug.h>
#include "renderedDocumentPage.h"
#include "hyperlink.h"
#include "selection.h"
#include "textBox.h"
RenderedDocumentPage::RenderedDocumentPage()
{
textBoxList.reserve(250);
pageNr = 0;
isEmpty = true;
pageText = TQString::null;
}
RenderedDocumentPage::~RenderedDocumentPage()
{
;
}
void RenderedDocumentPage::setPageNumber(const PageNumber& pnr)
{
pageNr = pnr;
clear();
}
void RenderedDocumentPage::clear()
{
#ifdef DEBUG_DOCUMENTPAGE
kdDebug(1223) << "RenderedDocumentPage::clear() called for page #" << pageNumber << endl;
#endif
textBoxList.clear();
hyperLinkList.clear();
pageText = TQString::null;
isEmpty = true;
}
TQRegion RenderedDocumentPage::selectedRegion(const TextSelection& selection)
{
if (selection.isEmpty() || selection.getPageNumber() != pageNr)
return TQRegion();
int startIndex = selection.getSelectedTextStart();
int endIndex = selection.getSelectedTextEnd();
TQValueVector<TQRect> wordBox;
TQRect currentWordBox;
//unsigned int currentBaseline = 0;
// Merge character boxes into boxes containing complete words.
// Note: A word in this context is defined as a string of boxes
// with the same baseline.
for (int i = startIndex; i <= endIndex; i++)
{
if (i == 0)
{
// start first word
currentWordBox = textBoxList[i].box;
//currentBaseline = textBoxList[i].baseline;
continue;
}
/*if (currentBaseline == textBoxList[i].baseline)
{
currentWordBox = currentWordBox.unite(textBoxList[i].box);
}
else*/
{
// start next word
wordBox.push_back(currentWordBox);
currentWordBox = textBoxList[i].box;
//currentBaseline = textBoxList[i].baseline;
}
}
// we still need to store the last word
wordBox.push_back(currentWordBox);
TQValueVector<TQRect> lineBox;
// Merge word boxes into boxes containing whole lines.
// We start a new line if we encounter a wordbox which does not
// vertically overlap which the current lineBox.
TQRect currentLineBox;
for (unsigned int i = 0; i < wordBox.size(); i++)
{
if (!currentLineBox.isValid())
{
// start first line
currentLineBox = wordBox[i];
continue;
}
// check if there is vertical overlap
if (wordBox[i].top() <= currentLineBox.bottom() && wordBox[i].bottom() >= currentLineBox.top())
{
// the word belongs to the current line
currentLineBox = currentLineBox.unite(wordBox[i]);
}
else
{
// start next line
//kdDebug() << "push line (" << currentLineBox.top() << ", " << currentLineBox.bottom() << ")" << endl;
lineBox.push_back(currentLineBox);
currentLineBox = wordBox[i];
}
}
// we still need to store the last line
//kdDebug() << "push line (" << currentLineBox.top() << ", " << currentLineBox.bottom() << ")" << endl;
lineBox.push_back(currentLineBox);
//kdDebug() << "Number of lineboxes = " << lineBox.size() << endl;
// Now we increase the height of the lines if necessary to obtain a connected region
// for our selection.
for (unsigned int i = 0; i < lineBox.size() - 1; i++)
{
if (lineBox[i+1].top() >= lineBox[i].bottom())
{
int midPoint = (lineBox[i].bottom() + lineBox[i+1].top()) / 2;
lineBox[i].setBottom(midPoint);
lineBox[i+1].setTop(midPoint+1);
}
}
// Add the lineboxes to a Region
TQRegion selectedRegion;
for (unsigned int i = 0; i < lineBox.size(); i++)
{
selectedRegion += TQRegion(lineBox[i]);
}
return selectedRegion;
}
TextSelection RenderedDocumentPage::select(const TQRect& selectedRectangle)
{
int selectedTextStart = -1;
int selectedTextEnd = -1;
// Find the smallest and biggest index for which the corresponding
// textBoxList entry intersects the selected rectangle.
for (unsigned int i=0; i<textBoxList.size(); i++)
{
if (selectedRectangle.intersects(textBoxList[i].box))
{
if (selectedTextStart == -1)
selectedTextStart = i;
selectedTextEnd = i;
}
}
TextSelection selection;
TQString selectedText;
if (selectedTextStart != -1)
{
for (int i = selectedTextStart; (i <= selectedTextEnd) && (i < (int)textBoxList.size()); i++)
{
selectedText += textBoxList[i].text;
}
selection.set(pageNr, selectedTextStart, selectedTextEnd, selectedText);
return selection;
}
// return empty selection
return selection;
}
TextSelection RenderedDocumentPage::select(const TQPoint& point)
{
int selectedTextStart = -1;
int selectedTextEnd = -1;
for (unsigned int i=0; i<textBoxList.size(); i++)
{
if (textBoxList[i].box.contains(point))
{
selectedTextStart = i;
selectedTextEnd = i;
break;
}
}
TextSelection selection;
TQString selectedText;
if (selectedTextStart != -1)
{
selectedText = textBoxList[selectedTextStart].text;
selection.set(pageNr, selectedTextStart, selectedTextEnd, selectedText);
return selection;
}
// return empty selection
return selection;
}
TextSelection RenderedDocumentPage::find(const TQString& str, int index, bool caseSensitive)
{
if (pageText.isNull())
{
// Create the pageText by joining all entries of textBoxList.
for (TQValueVector<TextBox>::Iterator i = textBoxList.begin(); i != textBoxList.end(); i++)
{
pageText = pageText + i->text;
}
}
// Create empty selection;
TextSelection selection;
// If the page contains no searchable text
if (pageText.isNull())
return selection;
// Compute the corresponding pageText index
unsigned int subIndex = 0;
for (int i = 0; i < index; i++)
{
subIndex += textBoxList[i].text.length();
}
int textIndex = pageText.find(str, subIndex, caseSensitive);
if (textIndex == -1)
return selection;
// Because a single Hyperlink structure can possible store more then
// one character we now have to search for the Indices in the
// textBoxList Vector which corresponds to the found index in the
// String pageText. FIXME: It would be faster to search directly in
// the textBoxList.
int counter = 0;
int startIndex = 0;
while (counter < textIndex)
{
counter += textBoxList[startIndex].text.length();
// If the string we searched for starts in the middle of some text element we better return a
// selection that it somewhat bigger.
if (counter > textIndex)
break;
startIndex++;
// safety check
if (startIndex >= (int)textBoxList.size())
return selection;
}
// Search for the end index.
// TODO: This algorithm is not entirely correct if str does not start exactly at the beginning of some text element.
counter = 0;
int endIndex = startIndex;
while (counter < (int)str.length())
{
counter += textBoxList[endIndex].text.length();
if (counter >= (int)str.length())
break;
endIndex++;
// safety check
if (endIndex >= (int)textBoxList.size())
return selection;
}
// Set the selection
selection.set(pageNr, startIndex, endIndex, str);
return selection;
}
TextSelection RenderedDocumentPage::findRev(const TQString& str, int index, bool caseSensitive)
{
// Negative index means we start the search at the end of the text.
if (index < 0)
{
index = textBoxList.size();
}
if (pageText.isNull())
{
// Create the pageText by joining all entries of textBoxList.
for (TQValueVector<TextBox>::Iterator i = textBoxList.begin(); i != textBoxList.end(); i++)
{
pageText = pageText + i->text;
}
}
// Create empty selection;
TextSelection selection;
// If the page contains no searchable text
if (pageText.isNull())
return selection;
// Compute the corresponding pageText index
unsigned int subIndex = 0;
for (int i = 0; i < index; i++)
{
subIndex += textBoxList[i].text.length();
}
int textIndex = pageText.findRev(str, subIndex, caseSensitive);
if (textIndex == -1)
return selection;
// Because a single Hyperlink structure can possible store more then
// one character we now have to search for the Indices in the
// textBoxList Vector which corresponds to the found index in the
// String pageText. FIXME: It would be faster to search directly in
// the textBoxList.
int counter = 0;
int startIndex = 0;
while (counter < textIndex)
{
counter += textBoxList[startIndex].text.length();
// If the string we searched for starts in the middle of some text element we better return a
// selection that it somewhat bigger.
if (counter > textIndex)
break;
startIndex++;
// safety check
if (startIndex >= (int)textBoxList.size())
return selection;
}
// Search for the end index.
// TODO: This algorithm is not entirely correct if str does not start exactly at the beginning of some text element.
counter = 0;
int endIndex = startIndex;
while (counter < (int)str.length())
{
counter += textBoxList[endIndex].text.length();
if (counter >= (int)str.length())
break;
endIndex++;
// safety check
if (endIndex >= (int)textBoxList.size())
return selection;
}
// Set the selection
selection.set(pageNr, startIndex, endIndex, str);
return selection;
}
#include "renderedDocumentPage.moc"