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.
kbookreader/src/bookwidget.cpp

474 lines
12 KiB

/***************************************************************************
* Copyright (C) 2005 by Alexander Nemish *
* *
* 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. *
***************************************************************************/
#include <tqpainter.h>
#include <tqevent.h>
#include <tqimage.h>
#include <kdebug.h>
#include <kprogress.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqtextcodec.h>
#include <tqstring.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include "bookwidget.h"
#include "theme.h"
#include "settings.h"
#include "renderer.h"
//#include "ktextprogressdlg.h"
class TQStringList;
class TQRect;
class TQPixmap;
BookWidget::BookWidget(TQWidget *parent, const char *name)
: TQWidget(parent, name),
m_modified(true),
m_currentPage(0),
m_left_margin(0),
m_right_margin(0),
m_top_margin(0),
m_bottom_margin(0),
m_middle_margin(0),
m_encoding(0),
m_renderer(new Renderer)
{
//setupPageSize();
//setupSlots();
m_left_margin = 30;
m_right_margin = 30;
m_top_margin = 20;
m_bottom_margin = 15;
m_middle_margin = 20;
setFont(Settings::font());
Theme::self()->loadTheme("default");
setWFlags(TQt::WNoAutoErase);
setFocusPolicy(TQ_StrongFocus);
connect(&m_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(loadLine()));
connect(m_renderer.get(), TQT_SIGNAL(renderingFinished()), this, TQT_SLOT(renderingFinished()));
}
BookWidget::~BookWidget()
{
}
void BookWidget::openURL(const KURL & url)
{
m_url = url;
m_file.setName(m_url.path());
if (! m_file.open(IO_ReadOnly)) return;
///@todo Write encoding detection
m_stream.reset(new TQTextStream(&m_file));
m_textLines.reset(new TQStringList);
TQString name(encoding());
TQTextCodec *codec = TQTextCodec::codecForName(encoding()); // get the codec
if (codec)
m_stream->setCodec(codec);
//show progress dialog
m_progressDlg.reset(new KProgressDialog(this, "progressDlg", "Loading...",
"Loading file ", true));
m_progressDlg->setLabel("Loading file " + m_url.path());
m_progressDlg->setAllowCancel(true);
m_progressDlg->progressBar()->setTotalSteps(0);
connect(m_progressDlg.get(), TQT_SIGNAL(cancelClicked()), TQT_SLOT(cancelLoading()));
KDialog::centerOnScreen(m_progressDlg.get());
m_progressDlg->show();
//start timer for processing gui events
m_timer.start(0, false);
//load bookmark for the book
loadBookmarks();
// just for fun, set the status bar
emit signalChangeStatusbar(m_url.prettyURL());
}
TQString BookWidget::currentURL()
{
return m_url.path();
}
void BookWidget::drawContent(TQPainter& paint)
{
const TQRect lrect (rectLeftPage());
const TQRect rrect(rectRightPage());
const unsigned int curPage = currentPage();
//draw pages
m_renderer->drawPage(paint, lrect, curPage);
m_renderer->drawPage(paint, rrect, curPage + 1);
}
void BookWidget::drawPageNumbers(TQPainter & paint)
{
if (m_renderer->isEmpty())
return;
const TQRect lrect (rectLeftPage());
const TQRect rrect(rectRightPage());
const TQString number = TQString::number(currentPage() + 2);
// setup font
TQFont pageFont(font());
int pointSize = 10;
pageFont.setPointSize(pointSize);
pageFont.setBold(false);
pageFont.setItalic(false);
pageFont.setUnderline(false);
paint.setFont(pageFont);
const TQFontMetrics fm(pageFont);
const int width = fm.width(number);
//paint page numbers
const int offset = 8;
paint.drawText(lrect.left(), TQWidget::height() - offset,
TQString::number(currentPage() + 1));
paint.drawText(rrect.left() + rrect.width() - width,
TQWidget::height() - offset, number);
}
void BookWidget::drawBookmark(TQPainter & paint, Bookmark const& bm)
{
const TQRect lrect (rectLeftPage());
const TQRect rrect(rectRightPage());
const TQPixmap & bookmarkImage = Theme::self()->bookmarkPixmap();
const int width = bookmarkImage.width();
paint.drawPixmap(TQWidget::width()/2 - width/2, 0, bookmarkImage);
if (!bm.name().isEmpty())
{
paint.save();
paint.translate(TQWidget::width()/2., 20.);
paint.rotate(90.);
const TQString text = bm.name() + " (" + bm.dateTime().toString(Qt::LocalDate) + ")";
paint.drawText(0, 0, text);
paint.restore();
}
}
void BookWidget::paintEvent(TQPaintEvent* event)
{
// use cached page pixmap if the page wasn't modified
if (!modified())
{
TQRect rect(event->rect());
bitBlt(this, rect.x(), rect.y(), &m_cachePixmap, rect.x(), rect.y(), rect.width(), rect.height());
return;
}
// do full painting otherwise
setupPageSize();
const TQRect lrect (rectLeftPage());
const TQRect rrect(rectRightPage());
const unsigned int curPage = currentPage();
TQPixmap pm(size());
TQPainter paint(&pm);
//draw background image
const TQPixmap & image = Theme::self()->bgPixmap(TQWidget::size());
paint.drawPixmap(0, 0, image);
if (m_renderer->busy())
{
TQFont f(font());
f.setPointSize(20);
paint.setFont(f);
const TQFontMetrics fm(f);
TQString text = tr("Rendering...");
const int w = fm.width(text);
const int h = fm.height();
const int dx = (lrect.width() - w) / 2;
const int dy = (lrect.height() - h) / 2;
paint.drawText(lrect.x() + dx, lrect.y() + dy, text);
paint.drawText(rrect.x() + dx, rrect.y() + dy, text);
}
else
{
paint.setFont(font());
//draw pages
drawContent(paint);
drawPageNumbers(paint);
//draw bookmark if it is
typedef Bookmarks::const_iterator IT;
IT it = std::lower_bound(m_bookmarks.begin(), m_bookmarks.end(), curPage);
if (it != m_bookmarks.end() && (*it).page() == curPage)
drawBookmark(paint, *it);
}
paint.end();
bitBlt(this, 0, 0, &pm);
// store painted pixmap as cache
m_cachePixmap = pm;
m_modified = false;
}
void BookWidget::setupPageSize()
{
TQSize size((width() - m_left_margin - m_right_margin - 2 * m_middle_margin) / 2,
(height() - m_top_margin - m_bottom_margin));
m_renderer->setPageSize(size);
}
void BookWidget::mousePressEvent(TQMouseEvent * event)
{
if (event->button() == Qt::LeftButton)
{
if (rectLeftPage().contains(event->pos()))
{
prevPage();
}
else if (rectRightPage().contains(event->pos()))
{
nextPage();
}
}
TQWidget::mousePressEvent(event);
}
const TQRect BookWidget::rectLeftPage() const
{
return TQRect(m_left_margin, m_top_margin,
m_renderer->pageSize().width(),
m_renderer->pageSize().height());
}
const TQRect BookWidget::rectRightPage() const
{
return TQRect(m_left_margin + 2 * m_middle_margin + m_renderer->pageSize().width(),
m_top_margin,
m_renderer->pageSize().width(),
m_renderer->pageSize().height());
}
void BookWidget::clearAll()
{
setCurrentPage(0);
}
void BookWidget::prevPage()
{
setCurrentPage(currentPage() - 2);
}
void BookWidget::nextPage()
{
setCurrentPage(currentPage() + 2);
}
void BookWidget::firstPage()
{
setCurrentPage(0);
}
void BookWidget::lastPage()
{
setCurrentPage(m_renderer->pageCount() - 1);
}
void BookWidget::wheelEvent(TQWheelEvent * e)
{
e->accept();
if (e->delta() > 0)
prevPage();
else nextPage();
}
void BookWidget::resizeEvent(TQResizeEvent * e)
{
m_modified = true;
setupPageSize();
m_renderer->render();
// //if size become lower recalc current page
// if (currentPage() > m_renderer->pageCount())
// lastPage();
TQWidget::resizeEvent(e);
}
TQSize BookWidget::minimumSizeHint() const
{
return TQSize(400, 300);
}
void BookWidget::setFont(const TQFont & font)
{
m_modified = true;
TQWidget::setFont(font);
m_renderer->setFont(font);
update();
}
void BookWidget::setCurrentPage(int number)
{
// do nothing while renderer is working
if (m_renderer->busy())
return;
if (number >= m_renderer->pageCount())
number = m_renderer->pageCount() - 1;
if (number < 0) number = 0;
//only even page numbers allowed
int newPage = (number % 2) ? number - 1 : number;
if (newPage != m_currentPage)
m_modified = true;
m_currentPage = newPage;
update();
}
void BookWidget::keyPressEvent(TQKeyEvent * e)
{
if (e->key() == TQt::Key_Right || e->key() == TQt::Key_Down
|| e->key() == TQt::Key_Space)
{
nextPage();
}
else if (e->key() == TQt::Key_Left || e->key() == TQt::Key_Up)
{
prevPage();
}
else if (e->key() == TQt::Key_Home)
{
firstPage();
}
else if (e->key() == TQt::Key_End)
{
lastPage();
}
TQWidget::keyPressEvent(e);
}
void BookWidget::loadLine()
{
static int lineCount = 0;
if (!m_stream->eof())
{
*m_textLines << m_stream->readLine();
//progress update after every 50 lines
if (!(++lineCount % 50))
m_progressDlg->progressBar()->setProgress(
m_progressDlg->progressBar()->progress() + 1);
return;
}
m_timer.stop();
//render
m_renderer->load(*m_textLines);
//setup and show
firstPage();
//clean up
m_progressDlg.reset(0);
m_stream.reset(0);
m_textLines.reset(0);
m_file.close();
m_modified = true;
emit loadingFinished();
}
void BookWidget::cancelLoading()
{
m_timer.stop();
if (parentWidget())
TQT_TQWIDGET(parentWidget())->setCaption("");
//clean up
m_progressDlg->hide();
m_stream.reset(0);
m_textLines.reset(0);
m_file.close();
//setup and show
m_renderer->clear();
firstPage();
}
void BookWidget::setParaOffset(int offset)
{
m_modified = true;
m_renderer->setParaOffset(offset);
update();
}
void BookWidget::setEncoding(int a_encoding)
{
m_encoding = a_encoding;
}
void BookWidget::setEncodings(const TQStringList & a_encodings)
{
m_encodings = a_encodings;
}
void BookWidget::setEncoding(const TQString & a_encoding)
{
m_encoding = (m_encodings.findIndex(a_encoding));
}
void BookWidget::addBookmark(const TQString& name)
{
m_bookmarks.push_back(Bookmark(currentPage(), name));
std::sort(m_bookmarks.begin(), m_bookmarks.end());
// KAction menu = new KAction()
saveBookmarks();
}
void BookWidget::saveBookmarks( )
{
const TQString fileName = "bookreader/" + m_url.fileName();
TQFile::remove(TDEGlobal::dirs()->findResource("appdata", m_url.fileName()));
TDEConfig config(fileName, false, false, "data");
for (Bookmarks::size_type i = 0; i < m_bookmarks.size(); ++i)
{
const Bookmark & bm = m_bookmarks[i];
config.setGroup(tqtr("Bookmark %1").arg(i));
config.writeEntry("page", bm.page());
config.writeEntry("name", bm.name());
config.writeEntry("dateTime", bm.dateTime());
}
}
void BookWidget::loadBookmarks()
{
m_bookmarks.clear();
const TQString fileName = "bookreader/" + m_url.fileName();
TDEConfig config(fileName, true, false, "data");
TQStringList groups = config.groupList();
typedef TQStringList::const_iterator IT;
for (IT it = groups.constBegin(); it != groups.constEnd(); ++it)
{
config.setGroup(*it);
const TQString name = config.readEntry("name");
const unsigned int page = config.readUnsignedNumEntry("page");
const TQDateTime dateTime = config.readDateTimeEntry("dateTime");
const Bookmark bm(page, name, dateTime);
m_bookmarks.push_back(bm);
}
std::sort(m_bookmarks.begin(), m_bookmarks.end());
}
void BookWidget::setBookmarks(const Bookmarks & bms)
{
m_bookmarks.clear();
m_bookmarks = bms;
std::sort(m_bookmarks.begin(), m_bookmarks.end());
saveBookmarks();
}
void BookWidget::renderingFinished()
{
m_modified = true;
setCurrentPage(currentPage());
update();
}
#include "bookwidget.moc"