summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-07-21 04:30:08 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-07-21 04:30:08 +0000
commita3570c360e8884f2bbf60b89e4d9531321ae01ad (patch)
treea6bc829daca69956b99be4dfa3939ff14193ec54 /src
downloadkbookreader-a3570c360e8884f2bbf60b89e4d9531321ae01ad.tar.gz
kbookreader-a3570c360e8884f2bbf60b89e4d9531321ae01ad.zip
Initial import of kbookreader
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kbookreader@1242482 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am47
-rw-r--r--src/README81
-rw-r--r--src/bookmark.cpp32
-rw-r--r--src/bookmark.h57
-rw-r--r--src/bookmarksdlg.cpp174
-rw-r--r--src/bookmarksdlg.h71
-rw-r--r--src/bookreader.cpp511
-rw-r--r--src/bookreader.desktop39
-rw-r--r--src/bookreader.h127
-rw-r--r--src/bookreader.kcfg24
-rw-r--r--src/bookreader.lsm16
-rw-r--r--src/bookreader_client.cpp45
-rw-r--r--src/bookreaderiface.h36
-rw-r--r--src/bookreaderui.rc19
-rw-r--r--src/bookwidget.cpp473
-rw-r--r--src/bookwidget.h125
-rw-r--r--src/hi16-app-bookreader.pngbin0 -> 631 bytes
-rw-r--r--src/hi32-app-bookreader.pngbin0 -> 1568 bytes
-rw-r--r--src/main.cpp66
-rw-r--r--src/renderer.cpp398
-rw-r--r--src/renderer.h138
-rw-r--r--src/settings.kcfgc6
-rw-r--r--src/settingsdlg.ui167
-rw-r--r--src/theme.cpp59
-rw-r--r--src/theme.h46
25 files changed, 2757 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..94dcdea
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,47 @@
+## Makefile.am for bookreader
+
+# this is the program that gets installed. it's name is used for all
+# of the other Makefile.am variables
+bin_PROGRAMS = bookreader bookreader_client
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# the library search path.
+bookreader_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+
+# the libraries to link against.
+bookreader_LDADD = $(LIB_KFILE) $(LIB_KDEPRINT)
+
+# which sources should be compiled for bookreader
+bookreader_SOURCES = main.cpp bookreader.cpp bookreaderiface.skel \
+ bookwidget.cpp theme.cpp settings.kcfgc settingsdlg.ui renderer.cpp bookmark.cpp \
+ bookmarksdlg.cpp
+
+# these are the headers for your project
+noinst_HEADERS = bookreader.h bookwidget.h theme.h renderer.h bookmark.h \
+ bookmarksdlg.h
+
+# client stuff
+bookreader_client_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+bookreader_client_LDADD = $(LIB_KDECORE)
+bookreader_client_SOURCES = bookreader_client.cpp
+
+kde_kcfg_DATA = bookreader.kcfg
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(EXTRACTRC) `find . -name \*.ui -o -name \*.rc` > rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/bookreader.pot
+
+KDE_ICON = AUTO
+
+# this is where the kdelnk file will go
+kdelnkdir = $(kde_appsdir)/Utilities
+kdelnk_DATA = bookreader.desktop
+
+# this is where the XML-GUI resource file goes
+rcdir = $(kde_datadir)/bookreader
+rc_DATA = bookreaderui.rc
diff --git a/src/README b/src/README
new file mode 100644
index 0000000..f04a563
--- /dev/null
+++ b/src/README
@@ -0,0 +1,81 @@
+-----------------------------------------------
+Kde application framework template quickstart
+Author: Thomas Nagy
+Date: 2004-03-22
+-----------------------------------------------
+
+This README file explains you basic things for starting with
+this application template.
+
+
+** Building and installing **
+
+* Build the configure script by "make -f Makefile.cvs"
+
+* To clean, use "make clean", and to clean everything
+(remove the makefiles, etc), use "make distclean"
+
+* To distribute your program, try "make dist".
+This will make a compact tarball archive of your release with the
+necessary scripts inside.
+
+* Modifying the auto-tools scripts
+for automake scripts there is an excellent tutorial there :
+http://developer.kde.org/documentation/other/makefile_am_howto.html
+
+* Simplify your life : install the project in your home directory for
+testing purposes.
+./configure --prefix=/home/user/dummyfolder/
+In the end when you finished the development you can
+rm -rf /home/user/dummyfolder/
+without fear.
+
+
+** Technologies **
+
+* Build the menus of your application easily
+kde applications now use an xml file (*ui.rc file) to build the menus.
+This allow a great customization of the application. However, when
+programming the menu is shown only after a "make install"
+
+For more details, consult :
+http://devel-home.kde.org/~larrosa/tutorial/p9.html
+http://developer.kde.org/documentation/tutorials/xmlui/preface.html
+
+* Use KConfig XT to create your configuration dialogs and make
+them more maintainable.
+
+For more details, consult :
+http://developer.kde.org/documentation/tutorials/kconfigxt/kconfigxt.html
+
+* With KParts, you can embed other kde components in your program, or make your program
+embeddable in other apps. For example, the kmplayer kpart can be called to play videos
+in your app.
+
+For more details, consult :
+http://www-106.ibm.com/developerworks/library/l-kparts/
+http://developer.kde.org/documentation/tutorials/dot/writing-plugins.html
+http://developer.kde.org/documentation/tutorials/developing-a-plugin-structure/index.html
+
+* With dcop, you can control your app from other applications
+Make sure to include K_DCOP and a kdcop: section in your .h file
+http://developer.kde.org/documentation/tutorials/dot/dcopiface/dcop-interface.html
+
+
+** Documentation **
+
+* For the translations :
+1. Download a patched gettext which can be found at:
+ http://public.kde.planetmirror.com/pub/kde/devel/gettext-kde/
+2. Install that gettext in ~/bin/
+3. cd ~/yourproject, export PATH=~/bin:$PATH, export
+KDEDIR=/where_your_KDE3_is
+4. make -f admin/Makefile.common package-messages
+5. make package-messages
+6. Translate the po files (not the pot!!) with kbabel or xemacs
+
+* Do not forget to write the documentation for your kde app
+edit the documentation template index.docbook in doc/
+
+
+
diff --git a/src/bookmark.cpp b/src/bookmark.cpp
new file mode 100644
index 0000000..e438dc3
--- /dev/null
+++ b/src/bookmark.cpp
@@ -0,0 +1,32 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Alexandr Nemish *
+ * atlanter@gmail.com *
+ * *
+ * 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 "bookmark.h"
+
+Bookmark::Bookmark(int page, const QString& name, QDateTime dateTime):
+ m_page(page),
+ m_name(name),
+ m_dateTime(dateTime)
+{
+}
+
+
+Bookmark::~Bookmark()
+{
+}
diff --git a/src/bookmark.h b/src/bookmark.h
new file mode 100644
index 0000000..b144b2a
--- /dev/null
+++ b/src/bookmark.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Alexander Nemish *
+ * atlanter@gmail.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef BOOKMARK_H
+#define BOOKMARK_H
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include <vector>
+
+class Bookmark;
+typedef std::vector<Bookmark> Bookmarks;
+
+/**
+*/
+class Bookmark
+{
+public:
+ Bookmark(int page, const QString& name = QString::null,
+ QDateTime dateTime = QDateTime::currentDateTime());
+ ~Bookmark();
+
+ void setPage(unsigned int page) { m_page = page; }
+ unsigned int page() const { return m_page; }
+ const QString & name() const { return m_name; }
+ const QDateTime & dateTime() const { return m_dateTime; }
+
+ bool operator < (const Bookmark& rhs) const { return (m_page < rhs.m_page); }
+
+ void setName(const QString& theValue)
+ {
+ m_name = theValue;
+ }
+
+private:
+ unsigned int m_page;
+ QString m_name;
+ QDateTime m_dateTime;
+};
+
+#endif
diff --git a/src/bookmarksdlg.cpp b/src/bookmarksdlg.cpp
new file mode 100644
index 0000000..f3bd823
--- /dev/null
+++ b/src/bookmarksdlg.cpp
@@ -0,0 +1,174 @@
+/***************************************************************************
+* 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 <kdialog.h>
+#include <klocale.h>
+#include <qvariant.h>
+#include <qpushbutton.h>
+#include <qheader.h>
+#include <qtable.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+#include "bookmarksdlg.h"
+/*
+ * Constructs a BookmarksDlg as a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'.
+ *
+ * The dialog will by default be modeless, unless you set 'modal' to
+ * TRUE to construct a modal dialog.
+ */
+
+BookmarksDlg::BookmarksDlg(const Bookmarks& bms, QWidget* parent,
+ const char* name, bool modal, WFlags fl)
+ : QDialog(parent, name, modal, fl),
+ m_bookmarks(bms)
+{
+ if ( !name )
+ setName( "BookmarksDlg" );
+ setSizeGripEnabled(TRUE);
+ BookmarksDlgLayout = new QVBoxLayout( this, 11, 6, "BookmarksDlgLayout");
+
+ layout3 = new QHBoxLayout( 0, 0, 6, "layout3");
+
+ bookmarksTable = new QTable(3, 2, this, "bookmarksList" );
+ bookmarksTable->horizontalHeader()->setLabel(0, "Title");
+ bookmarksTable->horizontalHeader()->setLabel(1, "Page number");
+// bookmarksTable->setLeftMargin(0);
+ bookmarksTable->setColumnStretchable(0, true);
+ bookmarksTable->setSelectionMode(QTable::SingleRow);
+ layout3->addWidget( bookmarksTable );
+
+ layout2 = new QVBoxLayout( 0, 0, 6, "layout2");
+
+ addButton = new QPushButton( this, "addButton" );
+ layout2->addWidget( addButton );
+
+ deleteButton = new QPushButton( this, "deleteButton" );
+ layout2->addWidget( deleteButton );
+ Horizontal_Spacing2_2 = new QSpacerItem( 20, 60, QSizePolicy::Minimum, QSizePolicy::Expanding );
+ layout2->addItem( Horizontal_Spacing2_2 );
+ layout3->addLayout( layout2 );
+ BookmarksDlgLayout->addLayout( layout3 );
+
+ Layout1 = new QHBoxLayout( 0, 0, 6, "Layout1");
+
+ buttonHelp = new QPushButton( this, "buttonHelp" );
+ buttonHelp->setAutoDefault( TRUE );
+ Layout1->addWidget( buttonHelp );
+ Horizontal_Spacing2 = new QSpacerItem( 20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum );
+ Layout1->addItem( Horizontal_Spacing2 );
+
+ buttonOk = new QPushButton( this, "buttonOk" );
+ buttonOk->setAutoDefault( TRUE );
+ buttonOk->setDefault( TRUE );
+ Layout1->addWidget( buttonOk );
+
+ buttonCancel = new QPushButton( this, "buttonCancel" );
+ buttonCancel->setAutoDefault( TRUE );
+ Layout1->addWidget( buttonCancel );
+ BookmarksDlgLayout->addLayout( Layout1 );
+ languageChange();
+ resize( QSize(400, 267).expandedTo(minimumSizeHint()) );
+ clearWState( WState_Polished );
+
+ updateBookmarks();
+ // signals and slots connections
+ connect(buttonOk, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(addButton, SIGNAL(clicked()), this, SLOT(addBookmark()));
+ connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteBookmark()));
+ connect(bookmarksTable, SIGNAL(valueChanged(int, int)), this, SLOT(valueChanged(int, int)));
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+BookmarksDlg::~BookmarksDlg()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+/*
+ * Sets the strings of the subwidgets using the current
+ * language.
+ */
+void BookmarksDlg::languageChange()
+{
+ setCaption( tr2i18n( "Bookmarks editor" ) );
+ addButton->setText( tr2i18n( "Add" ) );
+ deleteButton->setText( tr2i18n( "Delete" ) );
+ buttonHelp->setText( tr2i18n( "&Help" ) );
+ buttonHelp->setAccel( QKeySequence( tr2i18n( "F1" ) ) );
+ buttonOk->setText( tr2i18n( "&OK" ) );
+ buttonOk->setAccel( QKeySequence( QString::null ) );
+ buttonCancel->setText( tr2i18n( "Ca&ncel" ) );
+ buttonCancel->setAccel( QKeySequence( tr2i18n( "Alt+N" ) ) );
+}
+
+void BookmarksDlg::addBookmark()
+{
+ m_bookmarks.push_back(Bookmark(2, "new bookmark"));
+ std::sort(m_bookmarks.begin(), m_bookmarks.end());
+ updateBookmarks();
+}
+
+void BookmarksDlg::deleteBookmark()
+{
+ int row = bookmarksTable->currentRow();
+ if (row >= 0 && row < m_bookmarks.size())
+ {
+ m_bookmarks.erase(m_bookmarks.begin() + row);
+ updateBookmarks();
+ }
+}
+
+void BookmarksDlg::updateBookmarks()
+{
+ bookmarksTable->setNumRows(0);
+ for (Bookmarks::size_type i = 0; i < m_bookmarks.size(); ++i)
+ {
+ const Bookmark& bm = m_bookmarks[i];
+ bookmarksTable->setNumRows(i+1);
+ bookmarksTable->setText(i, 0, bm.name());
+ bookmarksTable->setText(i, 1, QString::number(bm.page()));
+ }
+}
+
+void BookmarksDlg::valueChanged(int row, int col)
+{
+ if (row >= m_bookmarks.size()) return;
+ Bookmark& bm = m_bookmarks[row];
+ //Bookmark title
+ if (col == 0)
+ bm.setName(bookmarksTable->text(row, col));
+ //page number
+ else if (col == 1)
+ {
+ bool ok;
+ unsigned int page = bookmarksTable->text(row, col).toUInt(&ok);
+ if (ok)
+ bm.setPage(page);
+ else
+ //return old value
+ bookmarksTable->setText(row, col, QString::number(bm.page()));
+ }
+}
+
+#include "bookmarksdlg.moc"
diff --git a/src/bookmarksdlg.h b/src/bookmarksdlg.h
new file mode 100644
index 0000000..79d8df2
--- /dev/null
+++ b/src/bookmarksdlg.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+* 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. *
+***************************************************************************/
+
+#ifndef BOOKMARKSDLG_H
+#define BOOKMARKSDLG_H
+
+#include <qvariant.h>
+#include <qdialog.h>
+#include <algorithm>
+#include "bookmark.h"
+
+class QVBoxLayout;
+class QHBoxLayout;
+class QGridLayout;
+class QSpacerItem;
+class QTable;
+class QPushButton;
+
+class BookmarksDlg : public QDialog
+{
+ Q_OBJECT
+
+public:
+ BookmarksDlg(const Bookmarks& bms, QWidget* parent = 0,
+ const char* name = 0, bool modal = FALSE, WFlags fl = 0);
+ ~BookmarksDlg();
+
+ const Bookmarks& bookmarks() const { return m_bookmarks; }
+
+ QTable* bookmarksTable;
+ QPushButton* addButton;
+ QPushButton* deleteButton;
+ QPushButton* buttonHelp;
+ QPushButton* buttonOk;
+ QPushButton* buttonCancel;
+
+protected:
+ QVBoxLayout* BookmarksDlgLayout;
+ QHBoxLayout* layout3;
+ QVBoxLayout* layout2;
+ QSpacerItem* Horizontal_Spacing2_2;
+ QHBoxLayout* Layout1;
+ QSpacerItem* Horizontal_Spacing2;
+
+protected slots:
+ virtual void languageChange();
+ void addBookmark();
+ void deleteBookmark();
+ void valueChanged(int row, int col);
+ void updateBookmarks();
+private:
+ Bookmarks m_bookmarks;
+};
+
+#endif // BOOKMARKSDLG_H
diff --git a/src/bookreader.cpp b/src/bookreader.cpp
new file mode 100644
index 0000000..662d283
--- /dev/null
+++ b/src/bookreader.cpp
@@ -0,0 +1,511 @@
+/***************************************************************************
+* Copyright (C) 2005 by Alexander Nemish *
+* atlanter@gmail.com *
+* *
+* 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 <kaccel.h>
+#include <kaction.h>
+#include <kcharsets.h>
+#include <kconfig.h>
+#include <kconfigdialog.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kencodingfiledialog.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kinputdialog.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmenubar.h>
+#include <kmessagebox.h>
+#include <kprinter.h>
+#include <kstatusbar.h>
+#include <ksplashscreen.h>
+#include <kstandarddirs.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kurl.h>
+#include <kurldrag.h>
+#include <kurlrequesterdlg.h>
+#include <kio/netaccess.h>
+#include <qdragobject.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+#include <qpixmap.h>
+#include <qtextcodec.h>
+#include <qsignalmapper.h>
+#include <assert.h>
+#include "bookreader.h"
+#include "settings.h"
+#include "settingsdlg.h"
+#include "bookmarksdlg.h"
+
+namespace {
+QStringList listEncodings()
+{
+ const QStringList encodings(KGlobal::charsets()->availableEncodingNames());
+ QStringList availEncodings;
+ for (unsigned int i=0; i < encodings.count(); ++i)
+ {
+ bool found = false;
+ KGlobal::charsets()->codecForName(encodings[i], found);
+ if (found)
+ availEncodings << encodings[i];
+ }
+ return availEncodings;
+}
+}
+
+
+BookReader::BookReader()
+ : KMainWindow(0, "BookReader"),
+ m_view(new BookWidget(this)),
+ m_fullScreenAction(0),
+ m_splash(0),
+ m_printer(0)
+{
+
+ QPixmap splash(KGlobal::dirs()->findResource("appdata",
+ "themes/default/splash.png"));
+ m_splash = new KSplashScreen(splash);
+ m_splash->show();
+ // accept dnd
+ setAcceptDrops(true);
+
+ // tell the KMainWindow that this is indeed the main widget
+ setCentralWidget(m_view);
+
+ // then, setup our actions
+ setupActions();
+
+ // and a status bar
+ statusBar()->show();
+
+ // Apply the create the main window and ask the mainwindow to
+ // automatically save settings if changed: window size, toolbar
+ // position, icon size, etc. Also to add actions for the statusbar
+ // toolbar, and keybindings if necessary.
+ KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection());
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled( true );
+ KStdAction::configureToolbars(this, SLOT(configureToolbars() ), actionCollection());
+ createGUI(QString::null, false);
+ initialGeometrySet();
+ setAutoSaveSettings();
+
+ // allow the view to change the statusbar and caption
+ connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
+ this, SLOT(changeStatusbar(const QString&)));
+ connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
+ this, SLOT(changeCaption(const QString&)));
+
+ readSettings();
+ m_splash->finish(m_view);
+}
+
+BookReader::~BookReader()
+{
+ writeSettings();
+ delete m_splash;
+}
+
+void BookReader::load(const KURL& url)
+{
+ QString target;
+ // download the contents
+ if(!KIO::NetAccess::download(url, target, this))
+ {
+ KMessageBox::error(this, KIO::NetAccess::lastErrorString());
+ return;
+ }
+ recentFilesAction->addURL(url);
+ setCaption(url.fileName());
+ m_view->openURL(url);
+ updateBookmarks();
+ KIO::NetAccess::removeTempFile(target);
+}
+
+void BookReader::setupActions()
+{
+// KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
+ KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+ recentFilesAction = KStdAction::openRecent(this, SLOT(slotURLSelected(const KURL &)),
+ actionCollection());
+ KStdAction::save(this, SLOT(fileSave()), actionCollection());
+ KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
+ KStdAction::print(this, SLOT(filePrint()), actionCollection());
+ KStdAction::quit(kapp, SLOT(quit()), actionCollection());
+
+ KStdAction::firstPage(this, SLOT(gotoFirstPage()), actionCollection());
+ KStdAction::prior(this, SLOT(prevPage()), actionCollection());
+ KStdAction::next(this, SLOT(nextPage()), actionCollection());
+ KStdAction::lastPage(this, SLOT(gotoLastPage()), actionCollection());
+
+ KStdAction::addBookmark(this, SLOT(addBookmark()), actionCollection());
+ KStdAction::editBookmarks(this, SLOT(editBookmarks()), actionCollection());
+
+ KStdAction::gotoPage(this, SLOT(gotoPage()), actionCollection());
+
+ m_fullScreenAction = KStdAction::fullScreen(this, SLOT(fullScreen()),
+ actionCollection(), this);
+
+ KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
+
+ KConfig *config = kapp->config();
+ recentFilesAction->loadEntries(config);
+
+ // this doesn't do anything useful. it's just here to illustrate
+ // how to insert a custom menu and menu item
+ /*
+ KAction *custom = new KAction( i18n( "Cus&tom Menuitem" ), 0,
+ this, SLOT( optionsPreferences() ),
+ actionCollection(), "custom_action" );*/
+}
+
+void BookReader::saveProperties(KConfig *config)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+ if (!m_view->currentURL().isEmpty())
+ {
+ config->writeEntry("lastURL", m_view->currentURL());
+ config->writeEntry("currentPage", m_view->currentPage());
+ }
+}
+
+void BookReader::readProperties(KConfig */*config*/)
+{
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+
+// QString url = config->readPathEntry("lastURL");
+// int currentPage = config->readEntry("currentPage").toInt();
+ /* Disable forawhile
+ if (!url.isEmpty())
+ {
+ m_view->openURL(KURL(url));
+ m_view->setCurrentPage(currentPage);
+ }
+ */
+}
+
+void BookReader::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void BookReader::dropEvent(QDropEvent *event)
+{
+ // this is a very simplistic implementation of a drop event. we
+ // will only accept a dropped URL. the Qt dnd code can do *much*
+ // much more, so please read the docs there
+ KURL::List urls;
+
+ // see if we can decode a URI.. if not, just ignore it
+ if (KURLDrag::decode(event, urls) && !urls.isEmpty())
+ {
+ // okay, we have a URI.. process it
+ const KURL & url = urls.first();
+
+ // load in the file
+ load(url);
+ }
+}
+
+void BookReader::fileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+ /*
+ // this brings up the generic open dialog
+ KURL url = KURLRequesterDlg::getURL(QString::null, this, i18n("Open Location") );
+ */
+ // standard filedialog
+ KEncodingFileDialog::Result res =
+ KEncodingFileDialog::getOpenURLAndEncoding(
+ listEncodings()[Settings::defaultEncoding()]);
+ KURL url = res.URLs.front();
+ m_view->setEncoding(res.encoding);
+ if (!url.isEmpty())
+ load(url);
+}
+
+void BookReader::fileSave()
+{
+ // this slot is called whenever the File->Save menu is selected,
+ // the Save shortcut is pressed (usually CTRL+S) or the Save toolbar
+ // button is clicked
+
+ // save the current file
+}
+
+void BookReader::fileSaveAs()
+{
+ // this slot is called whenever the File->Save As menu is selected,
+ KURL file_url = KFileDialog::getSaveURL();
+ if (!file_url.isEmpty() && file_url.isValid())
+ {
+ // save your info, here
+ }
+}
+
+void BookReader::filePrint()
+{
+ // this slot is called whenever the File->Print menu is selected,
+ // the Print shortcut is pressed (usually CTRL+P) or the Print toolbar
+ // button is clicked
+ if (!m_printer) m_printer = new KPrinter;
+ if (m_printer->setup(this))
+ {
+ // setup the printer. with Qt, you always "print" to a
+ // QPainter.. whether the output medium is a pixmap, a screen,
+ // or paper
+ QPainter p;
+ p.begin(m_printer);
+
+ // we let our view do the actual printing
+ QPaintDeviceMetrics metrics(m_printer);
+ //m_view->print( &p, metrics.height(), metrics.width() );
+
+ // and send the result to the printer
+ p.end();
+ }
+}
+
+void BookReader::optionsPreferences()
+{
+ if (KConfigDialog::showDialog("settings"))
+ return ;
+
+ KConfigDialog *dialog = new KConfigDialog(this, "settings", Settings::self(),
+ KDialogBase::IconList);
+ SettingsWidget *general = new SettingsWidget(0, "General");
+
+ const QStringList encodings(listEncodings());
+
+ QString curEncoding(encodings[Settings::defaultEncoding()]);
+ if (curEncoding.isEmpty())
+ curEncoding = QString::fromLatin1(KGlobal::locale()->encoding());
+
+ general->kcfg_DefaultEncoding->clear();
+ general->kcfg_DefaultEncoding->insertStringList(encodings);
+ for (unsigned int i=0; i < encodings.count(); ++i)
+ if (encodings[i] == curEncoding)
+ general->kcfg_DefaultEncoding->setCurrentItem(i);
+
+ dialog->addPage(general, i18n("General"), "settings");
+ connect(dialog, SIGNAL(settingsChanged()), this, SLOT(loadSettings()));
+ dialog->show();
+}
+
+void BookReader::changeStatusbar(const QString& text)
+{
+ // display the text on the statusbar
+ statusBar()->message(text);
+}
+
+void BookReader::changeCaption(const QString& text)
+{
+ // display the text on the caption
+ setCaption(text);
+}
+
+void BookReader::loadSettings()
+{
+ m_view->setFont(Settings::font());
+ m_view->setParaOffset(Settings::paraOffset());
+ m_view->setEncoding(Settings::defaultEncoding());
+}
+
+void BookReader::slotURLSelected(const KURL & url)
+{
+ load(url);
+}
+
+bool BookReader::queryExit()
+{
+ writeSettings();
+ return true;
+}
+
+void BookReader::writeSettings()
+{
+ KConfig * config = kapp->config();
+ config->writeEntry("size", m_view->size());
+ config->writeEntry("lastURL", m_view->currentURL());
+ config->writeEntry("lastURLPage", m_view->currentPage());
+ recentFilesAction->saveEntries(KGlobal::config());
+}
+
+void BookReader::readSettings()
+{
+ recentFilesAction->loadEntries(KGlobal::config());
+ recentFilesAction->setEnabled(true); // force enabling
+
+ m_view->setParaOffset(Settings::paraOffset());
+ m_view->setEncodings(listEncodings());
+ m_view->setEncoding(Settings::defaultEncoding());
+
+ if (Settings::loadLastUrl())
+ {
+ loadLastUrl();
+ }
+}
+
+void BookReader::fullScreen()
+{
+ if (m_fullScreenAction->isChecked())
+ {
+ menuBar()->hide();
+ setWindowState(windowState() | WindowFullScreen);
+ }
+ else
+ {
+ menuBar()->show();
+ setWindowState(windowState() & ~WindowFullScreen);
+ }
+}
+
+void BookReader::loadLastUrl()
+{
+ KConfig * config = kapp->config();
+ QSize size = config->readSizeEntry("size");
+ lastURL = config->readEntry("lastURL");
+ connect(m_view, SIGNAL(loadingFinished()), this, SLOT(loadLastURLSetPage()));
+ if (!lastURL.isEmpty())
+ {
+// kdDebug() << "loadLastUrl: initial size = " << m_view->size() << endl;
+ m_view->resize(size);
+// kdDebug() << "loadLastUrl: resize = " << m_view->size() << endl;
+ m_view->setupPageSize();
+// kdDebug() << "render = 1" << endl;
+ load(lastURL);
+ }
+}
+
+void BookReader::loaded(int loaded)
+{
+ //m_loaded = loaded;
+ m_splash->message(tr("Loading: %1 - %2%").arg(lastURL.fileName()).arg(loaded));
+}
+
+void BookReader::gotoFirstPage()
+{
+ m_view->firstPage();
+}
+
+void BookReader::nextPage()
+{
+ m_view->nextPage();
+}
+
+void BookReader::prevPage()
+{
+ m_view->prevPage();
+}
+
+void BookReader::gotoLastPage( )
+{
+ m_view->lastPage();
+}
+
+void BookReader::gotoPage()
+{
+ bool isOk;
+ int page = KInputDialog::getInteger(tr("Goto page"), tr("Page number"),
+ m_view->currentPage(), 1,
+ m_view->pageCount(), 1, &isOk);
+ m_view->setCurrentPage(page - 1);
+}
+
+void BookReader::loadLastURLSetPage()
+{
+ int lastURLPage = kapp->config()->readNumEntry("lastURLPage");
+ m_view->setCurrentPage(lastURLPage);
+}
+
+void BookReader::addBookmark()
+{
+ bool isOk;
+ QString name = KInputDialog::getText(tr("Add bookmark"),
+ tr("Bookmark name"), tr("Here"), &isOk);
+ if (isOk)
+ {
+ m_view->addBookmark(name);
+ updateBookmarks();
+ }
+}
+
+/*!
+ \fn BookReader::updateBookmarks()
+ */
+void BookReader::updateBookmarks()
+{
+ unplugActionList("my_bookmarks");
+ m_bookmarkActions.clear();
+ m_bookmarkActions.setAutoDelete(true);
+ const Bookmarks & bms = m_view->bookmarks();
+
+ QSignalMapper *bookmarkMapper = new QSignalMapper(this);
+ connect(bookmarkMapper, SIGNAL(mapped(int)), this, SLOT(gotoBookmark(int)));
+ for (Bookmarks::size_type i = 0; i < 9 && i < bms.size(); ++i)
+ {
+ const Bookmark & bm = bms[i];
+ KAction * action = new KAction(bm.name(), ALT+Key_1 + i);
+ connect(action, SIGNAL(activated()), bookmarkMapper, SLOT(map()));
+ m_bookmarkActions.append(action);
+ bookmarkMapper->setMapping(action, i);
+ }
+ plugActionList("my_bookmarks", m_bookmarkActions);
+}
+
+
+/*!
+ \fn BookReader::gotoBookmark(int index)
+ */
+void BookReader::gotoBookmark(int index)
+{
+ const Bookmarks & bms = m_view->bookmarks();
+ assert(index < bms.size());
+
+ unsigned int page = bms[index].page();
+ m_view->setCurrentPage(page);
+}
+
+
+
+/*!
+ \fn BookReader::editBookmarks()
+ */
+void BookReader::editBookmarks()
+{
+ /// @todo implement me
+ BookmarksDlg dialog(m_view->bookmarks());
+ if (dialog.exec() == QDialog::Accepted)
+ {
+ m_view->setBookmarks(dialog.bookmarks());
+ updateBookmarks();
+ }
+}
+
+
+#include "bookreader.moc"
diff --git a/src/bookreader.desktop b/src/bookreader.desktop
new file mode 100644
index 0000000..e946f19
--- /dev/null
+++ b/src/bookreader.desktop
@@ -0,0 +1,39 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=BookReader
+Exec=bookreader %i %m -caption "%c"
+Icon=bookreader
+Type=Application
+DocPath=bookreader/bookreader.html
+Comment=A KDE KPart Application
+Comment[br]=Ur meziant Kpart evit KDE
+Comment[ca]=Una aplicació KPart per a KDE
+Comment[cy]=Cymhwysiad KPart KDE
+Comment[da]=Et KDE KPart program
+Comment[de]=Eine KDE-Komponenten-Anwendung
+Comment[el]=Μια εφαρμογή KPart του KDE
+Comment[es]=Una aplicación KPart de KDE
+Comment[et]=KDE KPart rakendus
+Comment[eu]=KDE KPart aplikazio bat
+Comment[fr]=Une application KPart pour KDE.
+Comment[ga]=Feidhmchlár KPart KDE
+Comment[hi]=एक केडीई के-पार्ट अनुप्रयोग
+Comment[hu]=KPart-alapú KDE-alkalmazás
+Comment[is]=KDE KPart forrit
+Comment[it]=Applicazione KPart di KDE
+Comment[ja]=KDE KPart アプリケーション
+Comment[lt]=KDE KPart programa
+Comment[nb]=Et KDE KPart-program
+Comment[nl]=Een KDE KPart-toepassing
+Comment[pl]=Osadzalny element KPart KDE
+Comment[pt]=Uma aplicação KPart do KDE
+Comment[pt_BR]=Um Aplicativo KPart do KDE
+Comment[ru]=Приложение KPart для KDE
+Comment[sl]=Program KPart za KDE
+Comment[sr]=KDE KPart програм
+Comment[sr@Latn]=KDE KPart program
+Comment[sv]=Ett KDE Kpart-program
+Comment[ta]=கெடி கெபார்ட் பயன்பாடு
+Comment[tg]=Ба кор андохтани KPart барои KDE
+Comment[zh_CN]=一个 KDE KPart 应用程序
+Terminal=false
diff --git a/src/bookreader.h b/src/bookreader.h
new file mode 100644
index 0000000..989d099
--- /dev/null
+++ b/src/bookreader.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Alexandr Nemish *
+ * atlanter@gmail.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+#ifndef _BOOKREADER_H_
+#define _BOOKREADER_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kmainwindow.h>
+#include "bookwidget.h"
+
+
+class KPrinter;
+class KURL;
+class KRecentFilesAction;
+class KToggleFullScreenAction;
+class KSplashScreen;
+
+/**
+ * This class serves as the main window for BookReader. It handles the
+ * menus, toolbars, and status bars.
+ *
+ * @short Main window class
+ * @author Alexandr Nemish <atlanter@gmail.com>
+ */
+class BookReader : public KMainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ BookReader();
+
+ /**
+ * Default Destructor
+ */
+ virtual ~BookReader();
+
+ /**
+ * Use this method to load whatever file/URL you have
+ */
+ void load(const KURL& url);
+ void loadLastUrl();
+ void updateBookmarks();
+
+protected:
+ /**
+ * Overridden virtuals for Qt drag 'n drop (XDND)
+ */
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
+ virtual bool queryExit();
+
+protected:
+ /**
+ * This function is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig *);
+
+ /**
+ * This function is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig *);
+
+
+private slots:
+ void fileOpen();
+ void fileSave();
+ void fileSaveAs();
+ void filePrint();
+ void optionsPreferences();
+ void slotURLSelected(const KURL &);
+ void fullScreen();
+ void changeStatusbar(const QString& text);
+ void changeCaption(const QString& text);
+ void loadSettings();
+ void loaded(int);
+ void gotoFirstPage();
+ void nextPage();
+ void prevPage();
+ void gotoLastPage();
+ void gotoPage();
+ void loadLastURLSetPage();
+ void addBookmark();
+ void gotoBookmark(int index);
+ void editBookmarks();
+private:
+ void setupAccel();
+ void setupActions();
+ void readSettings();
+ void writeSettings();
+private:
+ BookWidget * m_view;
+ //Actions
+ KRecentFilesAction * recentFilesAction;
+ KToggleFullScreenAction * m_fullScreenAction;
+ QPtrList<KAction> m_bookmarkActions;
+ KURL lastURL;
+ KSplashScreen * m_splash;
+ KPrinter * m_printer;
+};
+
+#endif // _BOOKREADER_H_
+
diff --git a/src/bookreader.kcfg b/src/bookreader.kcfg
new file mode 100644
index 0000000..efec977
--- /dev/null
+++ b/src/bookreader.kcfg
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="bookreaderrc"/>
+ <group name="Preferences">
+ <entry name="Font" type="Font">
+ <label>The font used to display the contents of books.</label>
+ <default code="true">KGlobalSettings::generalFont()</default>
+ </entry>
+ <entry name="ParaOffset" type="Int">
+ <label>This is an offset of paragraph's first line in pixels</label>
+ <default>50</default>
+ </entry>
+ <entry name="DefaultEncoding" type="Int">
+ <label>This is a default encoding</label>
+ </entry>
+ <entry name="LoadLastUrl" type="Bool">
+ <label>This is ...</label>
+ <default>false</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/src/bookreader.lsm b/src/bookreader.lsm
new file mode 100644
index 0000000..333b057
--- /dev/null
+++ b/src/bookreader.lsm
@@ -0,0 +1,16 @@
+Begin3
+Title: BookReader -- Some description
+Version: 0.1
+Entered-date:
+Description:
+Keywords: KDE Qt
+Author: Alexandr Nemish <atlanter@gmail.com>
+Maintained-by: Alexandr Nemish <atlanter@gmail.com>
+Home-page:
+Alternate-site:
+Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils
+ xxxxxx bookreader-0.1.tar.gz
+ xxx bookreader-0.1.lsm
+Platform: Linux. Needs KDE
+Copying-policy: GPL
+End
diff --git a/src/bookreader_client.cpp b/src/bookreader_client.cpp
new file mode 100644
index 0000000..d07eb27
--- /dev/null
+++ b/src/bookreader_client.cpp
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Alexander Nemish *
+ * atlanter@gmail.com *
+ * *
+ * 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 <kapplication.h>
+#include <dcopclient.h>
+#include <qdatastream.h>
+#include <qstring.h>
+
+int main(int argc, char **argv)
+{
+ KApplication app(argc, argv, "bookreader_client", false);
+
+ // get our DCOP client and attach so that we may use it
+ DCOPClient *client = app.dcopClient();
+ client->attach();
+
+ // do a 'send' for now
+ QByteArray data;
+ QDataStream ds(data, IO_WriteOnly);
+ if (argc > 1)
+ ds << QString(argv[1]);
+ else
+ ds << QString("http://www.kde.org");
+ client->send("bookreader", "BookReaderIface", "openURL(QString)", data);
+
+ return app.exec();
+}
diff --git a/src/bookreaderiface.h b/src/bookreaderiface.h
new file mode 100644
index 0000000..6f733ec
--- /dev/null
+++ b/src/bookreaderiface.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Alexandr Nemish *
+ * atlanter@gmail.com *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+
+#ifndef _BOOKREADERIFACE_H_
+#define _BOOKREADERIFACE_H_
+
+#include <dcopobject.h>
+
+class BookReaderIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+k_dcop:
+ virtual void openURL(QString url) = 0;
+};
+
+#endif // _BOOKREADERIFACE_H_
diff --git a/src/bookreaderui.rc b/src/bookreaderui.rc
new file mode 100644
index 0000000..65c25af
--- /dev/null
+++ b/src/bookreaderui.rc
@@ -0,0 +1,19 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui version="1" name="bookreader" >
+ <MenuBar>
+ <Menu name="bookmarks" >
+ <ActionList name="my_bookmarks" />
+ <Action name="copy" />
+ </Menu>
+ </MenuBar>
+ <ToolBar noMerge="1" name="mainToolBar" >
+ <text>Main Toolbar</text>
+ <Action name="file_open" />
+ <Action name="file_save" />
+ <Action name="file_print" />
+ <Separator weakSeparator="1" name="separator_0" />
+ <Action name="go_previous" />
+ <Action name="go_next" />
+ <Action name="fullscreen" />
+ </ToolBar>
+</kpartgui>
diff --git a/src/bookwidget.cpp b/src/bookwidget.cpp
new file mode 100644
index 0000000..8eec9df
--- /dev/null
+++ b/src/bookwidget.cpp
@@ -0,0 +1,473 @@
+/***************************************************************************
+* 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 <qpainter.h>
+#include <qevent.h>
+#include <qimage.h>
+#include <kdebug.h>
+#include <kprogress.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qtextcodec.h>
+#include <qstring.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include "bookwidget.h"
+#include "theme.h"
+#include "settings.h"
+#include "renderer.h"
+//#include "ktextprogressdlg.h"
+
+class QStringList;
+class QRect;
+class QPixmap;
+
+BookWidget::BookWidget(QWidget *parent, const char *name)
+ : QWidget(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(Qt::WNoAutoErase);
+ setFocusPolicy(QWidget::StrongFocus);
+
+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(loadLine()));
+ connect(m_renderer.get(), SIGNAL(renderingFinished()), this, 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 QTextStream(&m_file));
+ m_textLines.reset(new QStringList);
+ QString name(encoding());
+ QTextCodec *codec = QTextCodec::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(), SIGNAL(cancelClicked()), 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());
+}
+
+QString BookWidget::currentURL()
+{
+ return m_url.path();
+}
+
+void BookWidget::drawContent(QPainter& paint)
+{
+ const QRect lrect (rectLeftPage());
+ const QRect 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(QPainter & paint)
+{
+ if (m_renderer->isEmpty())
+ return;
+ const QRect lrect (rectLeftPage());
+ const QRect rrect(rectRightPage());
+ const QString number = QString::number(currentPage() + 2);
+ // setup font
+ QFont pageFont(font());
+ int pointSize = 10;
+ pageFont.setPointSize(pointSize);
+ pageFont.setBold(false);
+ pageFont.setItalic(false);
+ pageFont.setUnderline(false);
+ paint.setFont(pageFont);
+ const QFontMetrics fm(pageFont);
+ const int width = fm.width(number);
+ //paint page numbers
+ const int offset = 8;
+ paint.drawText(lrect.left(), QWidget::height() - offset,
+ QString::number(currentPage() + 1));
+ paint.drawText(rrect.left() + rrect.width() - width,
+ QWidget::height() - offset, number);
+}
+
+void BookWidget::drawBookmark(QPainter & paint, Bookmark const& bm)
+{
+ const QRect lrect (rectLeftPage());
+ const QRect rrect(rectRightPage());
+ const QPixmap & bookmarkImage = Theme::self()->bookmarkPixmap();
+ const int width = bookmarkImage.width();
+ paint.drawPixmap(QWidget::width()/2 - width/2, 0, bookmarkImage);
+ if (!bm.name().isEmpty())
+ {
+ paint.save();
+ paint.translate(QWidget::width()/2., 20.);
+ paint.rotate(90.);
+ const QString text = bm.name() + " (" + bm.dateTime().toString(Qt::LocalDate) + ")";
+ paint.drawText(0, 0, text);
+ paint.restore();
+ }
+}
+
+void BookWidget::paintEvent(QPaintEvent* event)
+{
+ // use cached page pixmap if the page wasn't modified
+ if (!modified())
+ {
+ QRect 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 QRect lrect (rectLeftPage());
+ const QRect rrect(rectRightPage());
+ const unsigned int curPage = currentPage();
+ QPixmap pm(size());
+ QPainter paint(&pm);
+ //draw background image
+ const QPixmap & image = Theme::self()->bgPixmap(QWidget::size());
+ paint.drawPixmap(0, 0, image);
+ if (m_renderer->busy())
+ {
+ QFont f(font());
+ f.setPointSize(20);
+ paint.setFont(f);
+ const QFontMetrics fm(f);
+ QString 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()
+{
+ QSize 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(QMouseEvent * event)
+{
+ if (event->button() == LeftButton)
+ {
+ if (rectLeftPage().contains(event->pos()))
+ {
+ prevPage();
+ }
+ else if (rectRightPage().contains(event->pos()))
+ {
+ nextPage();
+ }
+ }
+ QWidget::mousePressEvent(event);
+}
+
+const QRect BookWidget::rectLeftPage() const
+{
+ return QRect(m_left_margin, m_top_margin,
+ m_renderer->pageSize().width(),
+ m_renderer->pageSize().height());
+}
+
+const QRect BookWidget::rectRightPage() const
+{
+ return QRect(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(QWheelEvent * e)
+{
+ e->accept();
+ if (e->delta() > 0)
+ prevPage();
+ else nextPage();
+}
+
+void BookWidget::resizeEvent(QResizeEvent * e)
+{
+ m_modified = true;
+ setupPageSize();
+ m_renderer->render();
+// //if size become lower recalc current page
+// if (currentPage() > m_renderer->pageCount())
+// lastPage();
+ QWidget::resizeEvent(e);
+}
+
+QSize BookWidget::minimumSizeHint() const
+{
+ return QSize(400, 300);
+}
+
+void BookWidget::setFont(const QFont & font)
+{
+ m_modified = true;
+ QWidget::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(QKeyEvent * e)
+{
+ if (e->key() == Qt::Key_Right || e->key() == Qt::Key_Down
+ || e->key() == Qt::Key_Space)
+ {
+ nextPage();
+ }
+ else if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Up)
+ {
+ prevPage();
+ }
+ else if (e->key() == Qt::Key_Home)
+ {
+ firstPage();
+ }
+ else if (e->key() == Qt::Key_End)
+ {
+ lastPage();
+ }
+
+ QWidget::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())
+ 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 QStringList & a_encodings)
+{
+ m_encodings = a_encodings;
+}
+
+void BookWidget::setEncoding(const QString & a_encoding)
+{
+ m_encoding = (m_encodings.findIndex(a_encoding));
+}
+
+void BookWidget::addBookmark(const QString& 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 QString fileName = "bookreader/" + m_url.fileName();
+ QFile::remove(KGlobal::dirs()->findResource("appdata", m_url.fileName()));
+ KConfig config(fileName, false, false, "data");
+ for (Bookmarks::size_type i = 0; i < m_bookmarks.size(); ++i)
+ {
+ const Bookmark & bm = m_bookmarks[i];
+ config.setGroup(tr("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 QString fileName = "bookreader/" + m_url.fileName();
+ KConfig config(fileName, true, false, "data");
+ QStringList groups = config.groupList();
+ typedef QStringList::const_iterator IT;
+ for (IT it = groups.constBegin(); it != groups.constEnd(); ++it)
+ {
+ config.setGroup(*it);
+ const QString name = config.readEntry("name");
+ const unsigned int page = config.readUnsignedNumEntry("page");
+ const QDateTime 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"
diff --git a/src/bookwidget.h b/src/bookwidget.h
new file mode 100644
index 0000000..8089b3d
--- /dev/null
+++ b/src/bookwidget.h
@@ -0,0 +1,125 @@
+/***************************************************************************
+* 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. *
+***************************************************************************/
+#ifndef BOOKWIDGET_H
+#define BOOKWIDGET_H
+
+#include <qwidget.h>
+#include <qevent.h>
+#include <qpixmap.h>
+#include <qthread.h>
+#include <qtimer.h>
+#include <qfile.h>
+#include <kurl.h>
+#include <algorithm>
+#include "renderer.h"
+#include "bookmark.h"
+
+class QStringList;
+class QRect;
+class KProgressDialog;
+
+
+/**
+ */
+class BookWidget : public QWidget
+{
+ Q_OBJECT
+public:
+
+
+ BookWidget(QWidget *parent = 0, const char *name = 0);
+ ~BookWidget();
+
+ virtual void openURL(const KURL & url);
+ virtual QString currentURL();
+ void paintEvent (QPaintEvent *);
+ void setFont( const QFont & );
+ void setParaOffset(int offset);
+ void setCurrentPage(int number);
+ int currentPage() const { return m_currentPage; };
+ int pageCount() const { return m_renderer->pageCount(); }
+ void nextPage();
+ void prevPage();
+ void firstPage();
+ void lastPage();
+ QSize minimumSizeHint () const;
+ void setupPageSize();
+ void setEncoding(int);
+ void setEncoding(const QString & a_encoding);
+ void setEncodings(const QStringList & a_encodings);
+ QString encoding() const { return m_encodings[m_encoding]; }
+ //const TextThread * thread() const {return m_thread;}
+ void addBookmark(const QString& name);
+ void saveBookmarks();
+ void loadBookmarks();
+ void setBookmarks(const Bookmarks& bms);
+ const Bookmarks & bookmarks() const { return m_bookmarks; }
+signals:
+ /**
+ * Use this signal to change the content of the statusbar
+ */
+ void signalChangeStatusbar(const QString& text);
+
+ /**
+ * Use this signal to change the content of the caption
+ */
+ void signalChangeCaption(const QString& text);
+
+ void loaded(int);
+ void loadingFinished();
+protected:
+ const QRect rectLeftPage() const;
+ const QRect rectRightPage() const;
+ void mousePressEvent(QMouseEvent *);
+ void keyPressEvent (QKeyEvent * e);
+ void resizeEvent (QResizeEvent * e);
+ void wheelEvent (QWheelEvent * e);
+ void clearAll();
+ void drawContent(QPainter& paint);
+ void drawPageNumbers(QPainter& paint);
+ void drawBookmark(QPainter& paint, Bookmark const& bm);
+ bool modified() const { return m_modified; };
+
+private slots:
+ void loadLine();
+ void cancelLoading();
+ void renderingFinished();
+
+private:
+ KURL m_url;
+ bool m_modified;
+ QPixmap m_cachePixmap;
+ int m_currentPage;
+ int m_left_margin;
+ int m_right_margin;
+ int m_top_margin;
+ int m_bottom_margin;
+ int m_middle_margin;
+ QFile m_file;
+ QTimer m_timer;
+ QStringList m_encodings;
+ int m_encoding;
+ std::auto_ptr<Renderer> m_renderer;
+ std::auto_ptr<QTextStream> m_stream;
+ std::auto_ptr<QStringList> m_textLines;
+ std::auto_ptr<KProgressDialog> m_progressDlg;
+ Bookmarks m_bookmarks;
+};
+
+#endif
diff --git a/src/hi16-app-bookreader.png b/src/hi16-app-bookreader.png
new file mode 100644
index 0000000..90705d9
--- /dev/null
+++ b/src/hi16-app-bookreader.png
Binary files differ
diff --git a/src/hi32-app-bookreader.png b/src/hi32-app-bookreader.png
new file mode 100644
index 0000000..73418b9
--- /dev/null
+++ b/src/hi32-app-bookreader.png
Binary files differ
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..73504d2
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Alexander Nemish *
+ * atlanter@gmail.com *
+ * *
+ * 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 <kapplication.h>
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <ksplashscreen.h>
+#include "bookreader.h"
+
+static const char description[] = I18N_NOOP("A KDE Application");
+static const char version[] = "0.2";
+static KCmdLineOptions options[] =
+{
+ { "[URL]", I18N_NOOP("Document to open"), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("bookreader", I18N_NOOP("BooKreader"), version, description,
+ KAboutData::License_GPL,
+ "(C) 2005-2007 Alexander Nemish", 0, 0, "atlanter@gmail.com");
+ about.addAuthor("Alexander Nemish", 0, "atlanter@gmail.com");
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+ KApplication app;
+
+ // register ourselves as a dcop client
+ app.dcopClient()->registerAs(app.name(), false);
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ {
+ RESTORE(BookReader);
+ }
+ else
+ {
+ // no session.. just start up normally
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ BookReader *widget = new BookReader;
+ app.setMainWidget(widget->centralWidget());
+ if (args->count() == 1)
+ widget->load(args->url(0));
+ widget->show();
+ args->clear();
+ }
+ return app.exec();
+}
diff --git a/src/renderer.cpp b/src/renderer.cpp
new file mode 100644
index 0000000..a04b0d0
--- /dev/null
+++ b/src/renderer.cpp
@@ -0,0 +1,398 @@
+/***************************************************************************
+* Copyright (C) 2005 - 2007 by Alexander Nemish *
+* atlanter@gmail.com *
+* *
+* 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 <kdebug.h>
+#include <qfontmetrics.h>
+#include <qpainter.h>
+#include <vector>
+#include <cmath>
+#include <iostream>
+#include "renderer.h"
+
+Renderer::Renderer():
+ m_pageCount(0),
+ m_linesPerPage(0),
+ m_paraOffset(50),
+ m_fontMetrics(new QFontMetrics(m_font)),
+ m_curParagraph(0),
+ m_isRendering(false)
+{
+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(timeout()));
+}
+
+
+Renderer::~Renderer()
+{
+}
+
+/**
+* If the list is empty do nothing.
+* \param a_list List of strings to render
+*/
+void Renderer::load(const QStringList & a_list)
+{
+ if (a_list.isEmpty())
+ return;
+ m_text.clear();
+
+ QString string;
+ TStringIter it(a_list.constBegin());
+
+ while (it != a_list.constEnd())
+ {
+ //skip spaces;
+ string = (*it).stripWhiteSpace();
+ //process string until paragraph ends
+ while (++it != a_list.constEnd())
+ {
+ QChar const ch((*it)[0]);
+ //insert empty lines
+ if ((*it).isEmpty())
+ break;
+ //check whether paragraph not ends
+ if (!ch.isSpace() && (ch != '-'))
+ {
+ string += " " + *it;
+ }
+ else break;
+ }
+ // add paragraph
+ m_text.push_back(string);
+ //add empty line if we have one
+ if ((*it).isEmpty())
+ m_text.push_back("");
+ }
+ render();
+}
+
+/**
+* \note You need manually update your widget. Like
+* \code
+* renderer->render();
+* update();
+* \endcode
+*/
+void Renderer::render()
+{
+ if (isEmpty())
+ return;
+ if (busy())
+ cancel();
+ clear();
+ m_isRendering = true;
+ m_linesPerPage = m_pageSize.height() / (QFontMetrics(font()).height());
+ m_timer.start(0, false);
+}
+
+void Renderer::timeout()
+{
+ if (m_curParagraph < m_text.size())
+ {
+ parseParagraph(m_curParagraph);
+ m_curParagraph++;
+ }
+ else
+ {
+ cancel();
+ emit renderingFinished();
+ }
+ m_pageCount = m_linesPerPage ? (m_lines.size() / m_linesPerPage) + 1 : 0;
+}
+
+void Renderer::cancel()
+{
+ m_timer.stop();
+ m_curParagraph = 0;
+ m_isRendering = false;
+}
+
+/**
+ * Call it for simple view clearing.
+* \code
+* renderer->clear();
+* update();
+* \endcode
+*/
+void Renderer::clear()
+{
+ m_lines.clear();
+ m_pageCount = 0;
+ m_linesPerPage = 0;
+}
+
+/**
+* \param a_string Line to parse
+*/
+void Renderer::parseParagraph(TIndex paraIndex)
+{
+ //Don't parse empty lines
+ const QString a_string(m_text[paraIndex]);
+ if (a_string.isEmpty())
+ return;
+
+ QString string(a_string);
+ const int avgCharWidth = m_fontMetrics->width(" ");
+ //calc approx string width
+ unsigned int avgLen = m_pageSize.width() / avgCharWidth;
+ unsigned int len;
+ int begin = 0;
+ m_isStartAdded = false;
+ int curWidth = width(string);
+
+ // whole paragraph in single line
+ if (curWidth <= m_pageSize.width())
+ {
+ addLine(TextLine(paraIndex, 0, a_string.length(), TextLine::PARA_BOTH));
+ return;
+ }
+
+ for (; curWidth > m_pageSize.width(); curWidth = width(string))
+ {
+ len = avgLen;
+ //turn left if missed
+ int w = width(string.left(len));
+ for (; (w > m_pageSize.width()) && (len > 0); w = width(string.left(len)))
+ {
+ int diff = w - m_pageSize.width();
+ int charDiff = diff / 10;
+ if (charDiff > len)
+ charDiff = charDiff % len;
+ charDiff = (charDiff == 0) ? 1 : charDiff;
+ len -= charDiff;
+ }
+ //turn right if missed
+ while ((width(string.left(len)) <= m_pageSize.width())
+ && (len < string.length()))
+ ++len;
+ --len;
+
+ // update statistics on average length
+ avgLen = (unsigned int) (len / (1 + 1. / avgLen));
+
+ //check whether we in a word
+ if (!(string[len - 1].isSpace() || string[len].isSpace()))
+ {
+ //find last word start index
+ const int wordBegin = wordAt(string, len);
+ //check whether its width less than page width
+ if (width(getWord(string, wordBegin)) <= m_pageSize.width())
+ {
+ //if so, move last word to the next line
+ // invariant: wordBegin > 0,
+ // because otherwise the word is greater than page width
+
+ // i points to a space before the word
+ int i = wordBegin -1;
+ // skip spaces
+ while (i && string[i].isSpace())
+ --i;
+ addLine(TextLine(paraIndex, begin, begin + i + 1));
+ string = string.right(string.length() - wordBegin);
+ begin += wordBegin;
+ }
+ else
+ {
+ //if its width greater than page width - split it
+ addLine(TextLine(paraIndex, begin, begin + len));
+ string = string.right(string.length() - len);
+ begin += len;
+ }
+ }
+ // line ends with spaces and next line begins with spaces,
+ // trim them
+ else if (string[len - 1].isSpace() && string[len].isSpace())
+ {
+ int idx = len - 1;
+ while (string[--idx] == ' ');
+ addLine(TextLine(paraIndex, begin, begin + idx + 1));
+ idx = len;
+ while (string[++idx] == ' ');
+ string = string.right(string.length() - idx);
+ begin += idx;
+ }
+ else if (string[len - 1].isSpace())
+ {
+ int idx = len - 1;
+ while (string[--idx] == ' ');
+ addLine(TextLine(paraIndex, begin, begin + idx + 1));
+ string = string.right(string.length() - len);
+ begin += len;
+ }
+ else if (string[len].isSpace())
+ {
+ int idx = len;
+ while (string[++idx] == ' ');
+ addLine(TextLine(paraIndex, begin, begin + len));
+ string = string.right(string.length() - idx);
+ begin += idx;
+ }
+ }
+ //last line in multiline para.
+ len = string.length();
+ addLine(TextLine(paraIndex, begin, begin + len, TextLine::PARA_END));
+}
+
+int Renderer::width(const QString & a_string) const
+{
+ int w = m_fontMetrics->width(a_string);
+ return m_isStartAdded ? w : w + paraOffset();
+}
+
+void Renderer::addLine(TextLine line)
+{
+ if (!m_isStartAdded)
+ line.setParagraphFlags(line.paragraphFlags() | TextLine::PARA_START);
+ m_lines.push_back(line);
+ m_isStartAdded = true;
+}
+
+int Renderer::wordAt(const QString & string, int len)
+{
+ while (--len >= 0)
+ if (string[len] == ' ')
+ return ++len;
+ return 0;
+}
+
+QString Renderer::getWord(const QString & a_string, int a_idx)
+{
+ int idx = a_idx;
+ while (a_string[++idx] != ' ' && idx < a_string.length());
+ return QString(a_string.mid(a_idx, idx - a_idx));
+}
+
+/**
+* Draws page number \c pageNumber on \c paint
+* bounding \c rect rectangle
+*/
+void Renderer::drawPage(QPainter & paint, QRect rect, int pageNumber)
+{
+ int height = m_fontMetrics->height();
+ int line = 1;
+ TLines::size_type count = m_lines.size();
+
+ if (count == 0)
+ return;
+
+ if ((pageNumber * m_linesPerPage) >= count)
+ return;
+
+ TLines::size_type idx = pageNumber * m_linesPerPage;
+ for (; (line <= m_linesPerPage) && idx < m_lines.size(); ++idx, ++line)
+ drawLine(paint, rect.left(), rect.top() + line * height, idx);
+}
+
+void Renderer::drawLine(QPainter & paint, int x, int y, const TLines::size_type index)
+{
+ const TextLine textLine(m_lines[index]);
+ const int length = textLine.size();
+ const QString & paragraph = m_text[textLine.paragraphIndex()];
+ const QString string = paragraph.mid(textLine.begin(), textLine.size());
+
+ // indent paragraph
+ if (textLine.isParaStart())
+ x += paraOffset();
+
+ // don't justify on paragraph end
+ if (textLine.isParaEnd())
+ {
+ paint.drawText(x, y, string);
+ return;
+ }
+
+ const int pageWidth = m_pageSize.width();
+ const int spaceWidth = m_fontMetrics->width(" ");
+ int width = m_fontMetrics->width(string);
+ const int curWidth = textLine.isParaStart() ? width + paraOffset() : width;
+
+ if (curWidth == pageWidth)
+ {
+ paint.drawText(x, y, string);
+ }
+
+ // string width is lower than page width. justify by space width
+ long pos = 0, off = 0;
+
+ //count spaces
+ std::vector<int> spaces;
+ spaces.reserve(50);
+ while (((pos = string.find(' ', off)) != -1) && (pos < length))
+ {
+ spaces.push_back(pos);
+ off = pos + 1;
+ }
+ const std::vector<int>::size_type spacesCount = spaces.size();
+ // no spaces no justifications
+ if (!spacesCount)
+ {
+ paint.drawText(x, y, string);
+ return;
+ }
+ // justify line
+ double x1 = x;
+ // calc average space width
+ const double avgLen = ((double)(pageWidth - curWidth) / spacesCount);
+ int start = 0;
+ QString tmp;
+ for (std::vector<int>::size_type i = 0; i < spacesCount; ++i)
+ {
+ pos = spaces[i];
+ tmp = string.mid(start, pos - start);
+ paint.drawText((int)std::ceil(x1), y, tmp);
+ x1 += m_fontMetrics->width(tmp);
+ x1 += spaceWidth + avgLen;
+ start = pos + 1;
+ }
+ //last chunk
+ paint.drawText((int)std::ceil(x1), y, string.right(length - start));
+}
+
+/**
+ * Sets current font to \c font and re-renders text.
+ * You don't need to directly call render().
+ */
+void Renderer::setFont(const QFont & font)
+{
+ if (font == m_font) return;
+ m_font = font;
+ m_fontMetrics.reset(new QFontMetrics(m_font));
+ render();
+}
+
+/**
+* Sets current paragraph offset to \c offset
+* and re-renders text if it's changed.
+*/
+void Renderer::setParaOffset(int offset)
+{
+ if (offset == m_paraOffset) return;
+ m_paraOffset = offset;
+ render();
+}
+
+/**
+ * Sets current page size to \c size.
+ * \note It don't call render() after changing.
+ */
+void Renderer::setPageSize(const QSize & size)
+{
+ m_pageSize = size;
+}
+
+#include "renderer.moc"
diff --git a/src/renderer.h b/src/renderer.h
new file mode 100644
index 0000000..23263ca
--- /dev/null
+++ b/src/renderer.h
@@ -0,0 +1,138 @@
+/***************************************************************************
+* Copyright (C) 2005 by Alexander Nemish *
+* atlanter@gmail.com *
+* *
+* 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. *
+***************************************************************************/
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include <qstringlist.h>
+#include <qfont.h>
+#include <qstring.h>
+#include <qobject.h>
+#include <qsize.h>
+#include <qtimer.h>
+#include <vector>
+#include <memory>
+class QStringList;
+
+class TextLine
+{
+public:
+ static const int PARA_NONE = 0;
+ static const int PARA_START = 1;
+ static const int PARA_END = 2;
+ static const int PARA_BOTH = 3;
+
+ TextLine(int index, int begin, int end, int paraFlags = PARA_NONE):
+ m_paragraphFlags(paraFlags),
+ m_begin(begin),
+ m_end(end),
+ m_index(index)
+ {}
+ bool isParaStart() const { return m_paragraphFlags & PARA_START; }
+ bool isParaEnd() const { return m_paragraphFlags & PARA_END; }
+ void setParagraphFlags(int flags) { m_paragraphFlags = flags; }
+ const int paragraphFlags() const { return m_paragraphFlags; }
+ const int paragraphIndex() const { return m_index; }
+ const int begin() const { return m_begin; }
+ const int end() const { return m_end; }
+ const int size() const { return m_end - m_begin; }
+private:
+ int m_paragraphFlags;
+ int m_begin;
+ int m_end;
+ int m_index;
+};
+
+/**
+* \brief Renders input text into list of word wrapped strings
+* \author Alexandr Nemish <anemish@gmail.com>
+*/
+class Renderer : public QObject
+{
+ Q_OBJECT
+public:
+ Renderer();
+ ~Renderer();
+
+ /// \brief Loads and renders list of strings
+ void load(const QStringList & list);
+ /// \brief Renders loaded list of strings
+ void render();
+ /// \brief Clears all rendered data
+ void clear();
+ /// \brief Draws page
+ void drawPage(QPainter & paint, QRect rect, int pageNumber);
+ //Getters
+ /// \brief Returns whether the text is empty
+ bool isEmpty() const { return m_text.empty(); };
+ /// \brief Returns current font
+ QFont font() const { return m_font; }
+ /// \brief Returns current paragraph offset in pixels
+ int paraOffset() const { return m_paraOffset; }
+ /// \brief Returns the number of pages
+ int pageCount() const { return m_pageCount; }
+ /// \brief Returns page size in pixels
+ QSize pageSize() const { return m_pageSize; }
+ //Setters
+ /// \brief Sets current font
+ void setFont(const QFont & font);
+ /// \brief Sets current paragraph offset in pixels
+ void setParaOffset(int offset);
+ /// \brief Sets size of a page
+ void setPageSize(const QSize & size);
+
+ bool busy() const { return m_isRendering; }
+signals:
+ void renderingFinished();
+private slots:
+ void timeout();
+private:
+ typedef QStringList::const_iterator TStringIter;
+ typedef std::vector<QString> TParagraphs;
+ typedef TParagraphs::size_type TIndex;
+ typedef std::vector<TextLine> TLines;
+ //make it non-copyable
+ Renderer(const Renderer &);
+ Renderer & operator = (const Renderer &);
+ /// \brief Renders input paragraph into list of wrapped lines
+ void parseParagraph(TIndex idx);
+ /// \brief Returns width of string in pixels
+ int width(const QString & a_string) const;
+ void addLine(TextLine line);
+ int wordAt(const QString & str, int len);
+ QString getWord(const QString & str, int idx);
+ /// \brief Draws justified string
+ void drawLine(QPainter& paint, int x, int y, const TLines::size_type idx);
+ void cancel();
+
+ TParagraphs m_text;
+ TLines m_lines;
+ int m_pageCount;
+ int m_linesPerPage;
+ int m_paraOffset;
+ QFont m_font;
+ std::auto_ptr<QFontMetrics> m_fontMetrics;
+ QSize m_pageSize;
+ bool m_isStartAdded;
+ TIndex m_curParagraph;
+ bool m_isRendering;
+ QTimer m_timer;
+};
+
+#endif
diff --git a/src/settings.kcfgc b/src/settings.kcfgc
new file mode 100644
index 0000000..2f6554f
--- /dev/null
+++ b/src/settings.kcfgc
@@ -0,0 +1,6 @@
+# Code generation options for kconfig_compiler
+File=bookreader.kcfg
+ClassName=Settings
+Singleton=true
+Mutators=col_background,col_foreground
+# will create the necessary code for setting those variables
diff --git a/src/settingsdlg.ui b/src/settingsdlg.ui
new file mode 100644
index 0000000..a2a3db8
--- /dev/null
+++ b/src/settingsdlg.ui
@@ -0,0 +1,167 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>SettingsWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>SettingsDlg</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>405</width>
+ <height>170</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form1</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QFrame">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Font</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kFontRequester1</cstring>
+ </property>
+ </widget>
+ <widget class="KFontRequester">
+ <property name="name">
+ <cstring>kcfg_Font</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>Paragraph Offset</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox">
+ <property name="name">
+ <cstring>kcfg_ParaOffset</cstring>
+ </property>
+ <property name="value">
+ <number>30</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout8</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1_3</cstring>
+ </property>
+ <property name="text">
+ <string>Default encoding</string>
+ </property>
+ </widget>
+ <widget class="QComboBox">
+ <property name="name">
+ <cstring>kcfg_DefaultEncoding</cstring>
+ </property>
+ <property name="editable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_LoadLastUrl</cstring>
+ </property>
+ <property name="text">
+ <string>Load last URL on startup</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>30</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>kcfg_ParaOffset</sender>
+ <signal>valueChanged(const QString&amp;)</signal>
+ <receiver>SettingsDlg</receiver>
+ <slot>kcfg_ParaOffset_valueChanged(const QString&amp;)</slot>
+ </connection>
+</connections>
+<slots>
+ <slot>kcfg_ParaOffset_valueChanged(const QString&amp;)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kfontrequester.h</includehint>
+</includehints>
+</UI>
diff --git a/src/theme.cpp b/src/theme.cpp
new file mode 100644
index 0000000..d6e868c
--- /dev/null
+++ b/src/theme.cpp
@@ -0,0 +1,59 @@
+/***************************************************************************
+* Copyright (C) 2005 by Alexander Nemish *
+* atlanter@gmail.com *
+* *
+* 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 <qstring.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include "theme.h"
+
+Theme* Theme::theme = 0;
+
+Theme::Theme()
+{}
+
+
+Theme * Theme::self()
+{
+ if ( !theme )
+ theme = new Theme();
+ return theme;
+}
+
+void Theme::loadTheme(const QString& name)
+{
+ const QString themePath = "themes/" + name; //FIXME: Add 'name' check. Could be a hole.
+ QString bgPath = KGlobal::dirs()->findResource("appdata", themePath + "/bg.png");
+ QString bookmarkPath = KGlobal::dirs()->findResource("appdata", themePath + "/bookmark.png");
+ m_bgPixmap = QPixmap(bgPath);
+ m_bgResizedPixmap = m_bgPixmap;
+ m_bookmarkPixmap = QPixmap(bookmarkPath);
+}
+
+const QPixmap & Theme::bgPixmap(QSize size) const
+{
+ if (size == QSize(0, 0) || size == m_bgPixmap.size())
+ return m_bgPixmap;
+ if (size == m_bgResizedPixmap.size())
+ return m_bgResizedPixmap;
+ m_bgResizedPixmap = m_bgPixmap;
+ m_bgResizedPixmap.convertFromImage(m_bgResizedPixmap.convertToImage().scale(size));
+ return m_bgResizedPixmap;
+}
diff --git a/src/theme.h b/src/theme.h
new file mode 100644
index 0000000..fae0f45
--- /dev/null
+++ b/src/theme.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+* Copyright (C) 2005 by Alexander Nemish *
+* atlanter@gmail.com *
+* *
+* 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. *
+***************************************************************************/
+#ifndef BOOKREADER_THEME_H
+#define BOOKREADER_THEME_H
+
+#include <qstring.h>
+#include <qpixmap.h>
+
+
+class Theme
+{
+public:
+ static Theme * self();
+ /// \brief Loads theme with given name. Default is "default". :)
+ void loadTheme(const QString& name = "default");
+ const QPixmap & bgPixmap(QSize size = QSize(0,0)) const;
+ const QPixmap & bookmarkPixmap() const { return m_bookmarkPixmap; }
+ //const QFont & font() const {return m_font;}
+private:
+ static Theme * theme;
+ Theme();
+ Theme(const Theme &);
+ Theme & operator = (const Theme&);
+ QPixmap m_bgPixmap;
+ mutable QPixmap m_bgResizedPixmap;
+ QPixmap m_bookmarkPixmap;
+};
+
+#endif