...
 
Commits (3)
......@@ -74,8 +74,14 @@ the variabled DDJVUAPI_CFLAGS and DDJVUAPI_LIBS.
2.2 COMPILING AND INSTALLING UNDER UNIX
---------------------------------------
First run the script 'configure' to generate the makefiles.
First run the script 'configure' (or 'autogen.sh' as
explained above) to generate the makefiles.
Note that there will be no configure file if you obtain the djvulibre
source using git clone. Instead there is a script 'autogen.sh' that
uses automake to generate and call the actual configure script.
Since all autogen.sh arguments will be passed to configure,
you can simply treat autogen.sh as a replacement for configure.
Command 'configure --help' list options and environment
variables that affect the generation of makefile.
......
......@@ -2710,13 +2710,78 @@ QDjView::open(QString filename)
}
/*! Open the djvu document available at url \a url.
Only the \a http: and \a file: protocols are supported. */
/* Helper class to open remote documents */
class QDjView::NetOpen : public QObject
{
Q_OBJECT
private:
QDjView *q;
QDjVuNetDocument *doc;
QUrl url;
bool inNewWindow;
bool maybeInBrowser;
bool startedBrowser;
public:
~NetOpen() {
if (doc) {
doc->deref();
if (! startedBrowser) {
q->addToErrorDialog(tr("Cannot open URL '%1'.").arg(url.toString()));
q->raiseErrorDialog(QMessageBox::Critical, tr("Opening DjVu document"));
}
}
}
NetOpen(QDjView *q, QDjVuNetDocument *d, QUrl u, bool n, bool b)
: QObject(q),
q(q), doc(d), url(u),
inNewWindow(n), maybeInBrowser(b),
startedBrowser(false) {
doc->ref();
connect(doc, SIGNAL(docinfo()),
this, SLOT(docinfo()) );
connect(doc, SIGNAL(gotContentType(QString,bool&)),
this, SLOT(gotContentType(QString,bool&)) );
}
public slots:
void docinfo() {
int status = ddjvu_document_decoding_status(*doc);
if (status == DDJVU_JOB_OK) {
disconnect(doc,0,this,0);
if (inNewWindow) {
QDjView *other = q->copyWindow();
other->open(url);
other->show();
} else {
q->open(doc,url);
}
doc = 0;
}
if (status >= DDJVU_JOB_OK)
deleteLater();
}
void gotContentType(QString type, bool &okay) {
QRegExp re("image/(x[.]|vnd[.-]|)(djvu|dejavu|iw44)(;.*)?");
okay = re.exactMatch(type);
if (maybeInBrowser && !okay) {
startedBrowser = q->startBrowser(url);
if (startedBrowser) {
disconnect(doc,0,this,0);
deleteLater();
} else {
QString msg = tr("Cannot spawn a browser for url '%1'").arg(url.toString());
qWarning("%s",(const char*)msg.toLocal8Bit());
}
}
}
};
/*! Open the djvu document available at url \a url. */
bool
QDjView::open(QUrl url)
QDjView::open(QUrl url, bool inNewWindow, bool maybeInBrowser)
{
closeDocument();
QDjVuNetDocument *doc = new QDjVuNetDocument(true);
connect(doc, SIGNAL(error(QString,QString,int)),
errorDialog, SLOT(error(QString,QString,int)));
......@@ -2726,14 +2791,14 @@ QDjView::open(QUrl url)
this, SLOT(sslWhiteList(QString,bool&)) );
QUrl docurl = removeDjVuCgiArguments(url);
doc->setUrl(&djvuContext, docurl);
if (!doc->isValid())
if (! (url.isValid() && doc->isValid()))
{
delete doc;
addToErrorDialog(tr("Cannot open URL '%1'.").arg(url.toString()));
raiseErrorDialog(QMessageBox::Critical, tr("Opening DjVu document"));
return false;
}
open(doc, url);
new NetOpen(this, doc, url, inNewWindow, maybeInBrowser);
return true;
}
......@@ -4151,27 +4216,8 @@ QDjView::goToLink(QString link, QString target, int fromPage)
emit pluginGetUrl(url, target);
return;
}
// Standalone can open djvu documents
QFileInfo file = url.toLocalFile();
QString suffix = file.suffix().toLower();
if (file.exists() && (suffix=="djvu" || suffix=="djv"))
{
if (inPlace)
open(url);
else
{
QDjView *other = copyWindow();
other->open(url);
other->show();
}
return;
}
// Open a browser
if (! startBrowser(url))
{
QString msg = tr("Cannot spawn a browser for url '%1'").arg(link);
qWarning("%s",(const char*)msg.toLocal8Bit());
}
// Standalone only: call open(QUrl,...) with adequate flags
open(url, !inPlace, true);
}
......@@ -4957,6 +5003,11 @@ QDjView::performCopyAnnotation()
}
// ----------------------------------------
// MOC
#include "qdjview.moc"
/* -------------------------------------------------------------
Local Variables:
......
......@@ -131,7 +131,7 @@ class QDjView : public QMainWindow
public slots:
bool open(QString filename);
bool open(QUrl url);
bool open(QUrl url, bool inNewWindow=false, bool maybeInBrowser=false);
void open(QDjVuDocument *document, QUrl url = QUrl());
void closeDocument();
void reloadDocument();
......@@ -404,6 +404,8 @@ protected:
QTimer *undoTimer;
QList<UndoRedo> undoList;
QList<UndoRedo> redoList;
// netopen
class NetOpen;
};
#endif
......
......@@ -561,7 +561,7 @@ QDjVuDocument::streamClose(int streamid, bool stop)
/*! Processes DDJVUAPI messages for this document.
The default implementation emits signals for
the \a m_error, \a m_info, \a m_docinfo, \a m_pageingo
the \a m_error, \a m_info, \a m_docinfo, \a m_pageinfo
and \a m_thumbnail messsages. It also calls
the virtual function \a newstream when processing
a \m newstream message. The return value is a boolean indicating
......
......@@ -64,8 +64,7 @@ public slots:
void proxyAuthenticationRequired (const QNetworkProxy &proxy, QAuthenticator *auth);
private:
void doRead(QNetworkReply *reply, int streamid);
void doError(QNetworkReply *reply, int streamid);
bool doHeaders(QNetworkReply *reply, int streamid);
bool doAuth(QString why, QAuthenticator *auth);
};
......@@ -82,100 +81,115 @@ QDjVuNetDocument::Private::Private(QDjVuNetDocument *q)
QDjVuNetDocument::Private::~Private()
{
QMap<QNetworkReply*,int>::iterator it;
for(it = reqid.begin(); it != reqid.end(); ++it)
while (! reqid.isEmpty())
{
QMap<QNetworkReply*,int>::iterator it = reqid.begin();
QNetworkReply *reply = it.key();
int streamid = it.value();
if (streamid >= 0)
ddjvu_stream_close(*q, streamid, true);
reply->abort();
reply->deleteLater();
reqid.remove(reply);
}
reqid.clear();
reqok.clear();
}
void
QDjVuNetDocument::Private::doRead(QNetworkReply *reply, int streamid)
bool
QDjVuNetDocument::Private::doHeaders(QNetworkReply *reply, int streamid)
{
QByteArray b = reply->readAll();
if (streamid >= 0 && b.size() > 0)
if (streamid >= 0 && !reqok.value(reply, false))
{
if (! reqok.value(reply, false))
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QUrl location = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QByteArray type = reply->header(QNetworkRequest::ContentTypeHeader).toByteArray();
// check redirection
if (location.isValid())
{
reqid[reply] = -1;
QUrl nurl = reply->url().resolved(location);
if (streamid > 0 || status == 307) {
q->newstream(streamid, QString(), nurl);
} else {
// Permanent redirect on main stream changes the base url.
ddjvu_document_set_user_data(*q, 0);
ddjvu_stream_close(*q, streamid, true);
q->setUrl(ctx, nurl, cache);
}
return false;
}
// check status code
if (status != 200 && status != 203 && status != 0)
{
int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QUrl location = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QByteArray type = reply->header(QNetworkRequest::ContentTypeHeader).toByteArray();
// check redirection
if (location.isValid())
{
reqid[reply] = -1;
QUrl nurl = reply->url().resolved(location);
if (streamid > 0 || status == 307)
{
q->newstream(streamid, QString(), nurl);
return;
}
// Permanent redirect on main stream changes the base url.
ddjvu_stream_close(*q, streamid, false);
q->setUrl(ctx, nurl, cache);
if (q->isValid())
return;
}
// check status code
if (status != 200 && status != 203 && status != 0)
{
QString msg = tr("Received http status %1 while retrieving %2.",
"%1 is an http status code")
.arg(status)
.arg(reply->url().toString());
emit q->error(msg, __FILE__, __LINE__);
return;
}
// check content type
if (type.startsWith("text/"))
{
QString msg = tr("Received <%1> data while retrieving %2.",
"%1 is a mime type")
.arg(QString::fromLatin1(type))
.arg(reply->url().toString());
emit q->error(msg, __FILE__, __LINE__);
}
reqok[reply] = true;
reqid[reply] = -1;
ddjvu_stream_close(*q, streamid, false);
QString msg = tr("Received http status %1 while retrieving %2.",
"%1 is an http status code")
.arg(status)
.arg(reply->url().toString());
emit q->error(msg, __FILE__, __LINE__);
return false;
}
// process data
ddjvu_stream_write(*q, streamid, b.data(), b.size());
// broadcast content type
bool okay = !type.startsWith("text/");
if (! type.isEmpty())
emit q->gotContentType(type, okay);
if (! okay)
{
reqid[reply] = -1;
ddjvu_stream_close(*q, streamid, false);
QString msg = tr("Received <%1> data while retrieving %2.",
"%1 is a mime type")
.arg(QString::fromLatin1(type))
.arg(reply->url().toString());
emit q->error(msg, __FILE__, __LINE__);
return false;
}
reqok[reply] = true;
return true;
}
return false;
}
void
QDjVuNetDocument::Private::doError(QNetworkReply *reply, int streamid)
void
QDjVuNetDocument::Private::readyRead()
{
QNetworkReply::NetworkError code = reply->error();
if (streamid >= 0 && code != QNetworkReply::NoError)
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (reply)
{
QString msg = tr("%1 while retrieving '%2'.")
.arg(reply->errorString())
.arg(reply->url().toString());
emit q->error(msg , __FILE__, __LINE__);
ddjvu_stream_close(*q, streamid, false);
reqid[reply] = -1;
int streamid = reqid.value(reply, -1);
bool okay = reqok.value(reply, false);
if (streamid >= 0 && !okay)
okay = doHeaders(reply, streamid);
if (streamid >= 0 && okay)
{
QByteArray b = reply->readAll();
if (b.size() > 0)
ddjvu_stream_write(*q, streamid, b.data(), b.size());
}
}
}
void
QDjVuNetDocument::Private::readyRead()
QDjVuNetDocument::Private::error(QNetworkReply::NetworkError code)
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (reply)
{
int streamid = reqid.value(reply, -1);
if (streamid >= 0)
doRead(reply, streamid);
if (streamid >= 0 && code != QNetworkReply::NoError)
{
reqid[reply] = -1;
ddjvu_stream_close(*q, streamid, false);
QString msg = tr("%1 while retrieving '%2'.")
.arg(reply->errorString())
.arg(reply->url().toString());
emit q->error(msg , __FILE__, __LINE__);
}
}
}
void
QDjVuNetDocument::Private::finished()
{
......@@ -183,14 +197,13 @@ QDjVuNetDocument::Private::finished()
if (reply)
{
int streamid = reqid.value(reply, -1);
if (streamid >= 0)
bool okay = reqok.value(reply, false);
if (streamid >= 0 && !okay)
okay = doHeaders(reply, streamid);
if (streamid >= 0 && okay)
{
if (reply->bytesAvailable() > 0)
doRead(reply, streamid);
if (reply->error() != QNetworkReply::NoError)
doError(reply, streamid);
else
ddjvu_stream_close(*q, streamid, false);
ddjvu_stream_close(*q, streamid, false);
reqid[reply] = -1;
}
}
reqid.remove(reply);
......@@ -198,18 +211,6 @@ QDjVuNetDocument::Private::finished()
reply->deleteLater();
}
void
QDjVuNetDocument::Private::error(QNetworkReply::NetworkError)
{
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
if (reply)
{
int streamid = reqid.value(reply, -1);
if (streamid >= 0)
doError(reply, streamid);
}
}
void
QDjVuNetDocument::Private::sslErrors(const QList<QSslError>&)
{
......
......@@ -42,6 +42,7 @@ protected:
signals:
void authRequired(QString why, QString &user, QString &pass);
void sslWhiteList(QString why, bool &okay);
void gotContentType(QString type, bool &okay);
private:
class Private;
Private *p;
......
......@@ -2220,7 +2220,8 @@ QDjVuWidget::setDocument(QDjVuDocument *d)
priv, SLOT(info(QString)));
connect(priv->doc, SIGNAL(idle()),
priv, SLOT(makePageRequests()));
priv->docinfo();
// the document may already be ready
QTimer::singleShot(0, priv, SLOT(docinfo()));
}
// update
priv->estimatedWidth = 0;
......