⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pdfwidget.cpp

📁 爱可视605看PDF程式源代码, 基于APDF
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include <qpainter.h>#include <qpixmap.h>#include <qimage.h>#include <qwidget.h>#include <qscrollview.h>#include <qlabel.h>#include <qpoint.h>#include <qarray.h>#include <qtimer.h>#include <qthread.h>#include <qapplication.h>#include <stdlib.h>#include <unistd.h>#include <sys/time.h>#include <qgfx_qws.h>#include "pdfwidget.h"#define MAX_SCROLL_DELAY 8static Poppler::Page *page = 0;static QWidget *eventReceiver;static bool abortCheck(void*);// must be accessable by the pdfWidget so it can abort the poppler librarystatic volatile bool abortedFastMove = false;static struct timeval preview_time;static bool running = false;struct renderJob{	Poppler::Document *doc;	int pageNum;	int scale;};class RenderThread : public QThread {	public :		RenderThread(QObject* m) : QThread()			, master(m)			, currentJobPending(false)			, jobBufferPending(false)		{}		virtual void run(void)		{			QImage *q = 0;			while (currentJobPending || jobBufferPending) {				lock.lock();				if (jobBufferPending) {					qWarning("picking up job from Buffer");					delete q;					currentJob = jobBuffer;					jobBufferPending = false;					abortedFastMove = false;				}				lock.unlock();				delete page;				page = 0;				page = currentJob.doc->getPage(currentJob.pageNum);				qWarning("starting to work on page %i, scale %i", currentJob.pageNum, currentJob.scale);				gettimeofday(&preview_time, NULL);				page->renderToImageScaled(&q, currentJob.scale, currentJob.scale, &abortCheck, 0);				qWarning("finished Page");				currentJobPending = false;			}			QApplication::postEvent(master, new QCustomEvent((QEvent::Type)PageReady, q));		}				void setJob(renderJob& j) 		{			lock.lock();			if (!running()) {				qWarning("starting renderThread");				currentJob = j;				currentJobPending = true;				abortedFastMove = false;				start();			} else {				qWarning("adding job for running thread");				jobBuffer = j;				jobBufferPending = true;				abortedFastMove = true;			}			lock.unlock();		}	private:		QObject* master;		QMutex lock;		renderJob currentJob;		bool currentJobPending;		renderJob jobBuffer;		bool jobBufferPending;};bool preview_time_elapsed(struct timeval *preview, struct timeval *now){	// previews every 3/4 seconds	return ((now->tv_sec * 1000000 + now->tv_usec) -			(preview->tv_sec * 1000000 + preview->tv_usec))	>= 7500000;}static bool abortCheck(void*){	bool ret = false;	struct timeval now;	if (abortedFastMove) {		qWarning("abortedFastMove");		ret = true;		abortedFastMove = false;	}	else {		gettimeofday(&now, NULL);		if (preview_time_elapsed(&preview_time, &now)) {			if (page) {				qWarning("sending preview event");				QImage* image;				page->getPagePreview(&image);				QApplication::postEvent(eventReceiver,					new QCustomEvent((QEvent::Type)PagePreview, image));				gettimeofday(&preview_time, NULL);			}		}	}	return ret;}PDFWidget::PDFWidget(Poppler::Document *d, QWidget *parent, const char* name, bool helpViewer ) :        QScrollView(parent, name, WRepaintNoErase ),        m_scale(72),        currentPage(0),        pixmap(0),        doc(d),        page(0),        m_panning(false),        m_panningPos(0),		zoomLevel(FIT_TO_WIDTH),        scheduledContentsPosX(0),        scheduledContentsPosY(0),        selectedLink(-1),        m_linkSelected(false),        m_LinkPos(0),        x_origin(0),        y_origin(0),        direction(Forward){	renderThread = new RenderThread(this);	if (helpViewer) {		borderWidth = 0;	// the help viewer doesn't use a border	}	else {		borderWidth = 5;	}    setHScrollBarMode(AlwaysOff);    setVScrollBarMode(AlwaysOff);    setFrameStyle(NoFrame);	eventReceiver = this;    display();}PDFWidget::~PDFWidget() {    /** @todo: should we pthread_join() the renderer thread? */    delete pixmap;	delete renderThread;}void PDFWidget::setDocument( Poppler::Document *d, int scale) {	doc = d;	currentPage = 0;	delete page;	page = doc->getPage(currentPage);	delete pixmap;	pixmap = 0;	emitNavSignals();	zoomLevel = FIT_TO_WIDTH;	setZoom(scale);}void PDFWidget::drawContents( QPainter *painter, int, int, int, int){    int sv_width = viewport()->width();    int sv_height = viewport()->height();    if (pixmap) {        x_origin = borderWidth;        y_origin = borderWidth;        // center horizontaly        if (pixmap->width() <= sv_width) {            x_origin = (sv_width - pixmap->width()) / 2;        }        // center verticaly        if (pixmap->height() <= sv_height) {            y_origin = (sv_height - pixmap->height()) / 2;        }        painter->drawPixmap(x_origin, y_origin, *pixmap);        // paint the visible content area not used by the pixmap        // structured so we avoid painting overlapping areas twice        painter->fillRect(0, 0, x_origin, contentsHeight(),                QColor(123, 121, 123));        // right of the pixmap        painter->fillRect(x_origin + pixmap->width(), 0,                contentsWidth(), contentsHeight(), QColor(123, 121, 123));        // over the pixmap        painter->fillRect(x_origin, 0,                x_origin + pixmap->width(),                y_origin, QColor(123, 121, 123));        // under the pixmap        painter->fillRect(x_origin,                y_origin + pixmap->height(),                x_origin + pixmap->width(),                contentsHeight(), QColor(123, 121, 123));        // when not in helpViewer mode there is a border and we want a frame	if (borderWidth) {		int pageW, pageH;		if (pixmap->width() == sv_width) {			pageW = pixmap->width();		}		else if (pixmap->width() < sv_width) {			pageW = pixmap->width() + 1;		}		else {			pageW = contentsWidth() - x_origin - (borderWidth - 1);		}		if (pixmap->height() == sv_height) {			pageH = pixmap->height();		}		else if (pixmap->height() < sv_height) {			pageH = pixmap->height() + 1;		}		else {			pageH = contentsHeight() - y_origin - (borderWidth - 1);		}		painter->drawRect(x_origin, y_origin, pageW, pageH);	}    }    else {        qWarning("No valid pixmap to display");        painter->fillRect(0, 0, sv_width, sv_height, QColor(123, 121, 123));    }}int PDFWidget::fitToPageDpi() const{	float pWidth = getPageWidth();	float pHeight = getPageHeight();	//qWarning("getPageWidth(); = %f", pWidth);	//qWarning("getPageHeight() + borderWidth * 2 = %f", pHeight);	// this will only work as long the pdfdWidget covers the whole screen	int dw = qt_screen->width();	int dh = qt_screen->height();	//qWarning("------fitToPageDpi %i",(int)(QMIN((dw * 72.0) / pWidth, (dh * 72.0) / pHeight)));	return (int)(QMIN((dw * 72.0) / pWidth, (dh * 72.0) / pHeight));}int PDFWidget::fitToWidthDpi() const{	int dw = qt_screen->width();	//qWarning("----------------fitToWidthDpi %i", (int)((dw * 72.0) / getPageWidth()));	// this will only work as long the pdfdWidged covers the whole screen	return (int)((dw * 72.0) / getPageWidth());}int PDFWidget::fitToPagePercent() const{	//qWarning("------------------fitToPagePercent %i", (int)(fitToPageDpi() / (72.0 / 100)));	return (int)(fitToPageDpi() / (72.0 / 100));}int PDFWidget::dpiToPercent(int scale) const{	//qWarning("-----------------dpiToPercent %i", (int)(m_scale / (72.0 / 100)));	return (int)(scale / (72.0 / 100));}void PDFWidget::zoomOut(){	if (zoomLevel == FIT_TO_WIDTH && (fitToPageDpi() != fitToWidthDpi())) {		zoomLevel = FIT_TO_PAGE;		//qWarning("FIT_TO_PAGE %i", zoomLevel);		setZoom(FIT_TO_PAGE);	}	else if (zoomLevel == FIT_TO_WIDTH + 1) {		zoomLevel = FIT_TO_WIDTH;		//qWarning("FIT_TO_WIDTH__ %i", zoomLevel);		setZoom(FIT_TO_WIDTH);	}	else if (zoomLevel > FIT_TO_WIDTH + 1) {		zoomLevel--;		//qWarning("zoomLevel-- %i", zoomLevel);		setZoom(dpiToPercent(fitToWidthDpi()) + 15 * (zoomLevel - 1));	}	selectedLink = selectLink();	emit zoomChanged();}void PDFWidget::zoomIn(){	if (zoomLevel == FIT_TO_PAGE) {		zoomLevel = FIT_TO_WIDTH;		//qWarning("FIT_TO_WIDTH %i", zoomLevel);		setZoom(FIT_TO_WIDTH);	}	else if (zoomLevel < maxZoomLevel) {		zoomLevel++;		//qWarning("zoomLevel++ %i", zoomLevel);		setZoom(dpiToPercent(fitToWidthDpi()) + 15 * (zoomLevel - 1));	}	selectedLink = selectLink();	emit zoomChanged();}bool PDFWidget::zoomIsUpperBound(){	bool ret = true;	if (doc)		ret = zoomLevel == maxZoomLevel;	return ret;}bool PDFWidget::zoomIsLowerBound(){	bool ret = true;	if (doc)		ret = (zoomLevel == FIT_TO_PAGE) || (zoomLevel == FIT_TO_WIDTH && fitToPageDpi() == fitToWidthDpi());	return ret;}bool PDFWidget::zoomIsDefault(){	return zoomLevel == FIT_TO_WIDTH;}// a temporary wrapper. setZoom is to broken to be public.void PDFWidget::setFitToPage(){	zoomLevel = FIT_TO_PAGE;	setZoom(FIT_TO_PAGE);}void PDFWidget::setFitToWidth(){	zoomLevel = FIT_TO_WIDTH;	setZoom(FIT_TO_WIDTH);}void PDFWidget::setZoom(unsigned int percent){	unsigned int dpi = 0;	switch (percent) {		case FIT_TO_WIDTH:			dpi = fitToWidthDpi();			emit zoomChanged();			break;		case FIT_TO_PAGE:			dpi = fitToPageDpi();			emit zoomChanged();			break;		default:			dpi = static_cast<int>(percent * 72.0 / 100);			//qWarning("dpi = %i, percent = %i", dpi, percent);			break;	}	m_scale = dpi;	if (doc == 0) {		return;	}	// keep the content the user was viewing visible.	int new_cX = (int) ((double)contentsX() / m_scale) * dpi;	int new_cY = (int) ((double)contentsY() / m_scale) * dpi;	scheduleContentsPosUpdate(new_cX, new_cY);	display();}void PDFWidget::updateViewRect(){	int x1, y1, x2, y2;	if (!pixmap)		return;	if (pixmap->width() < viewport()->width()) {		x1 = 0;		x2 = pixmap->width();	}	else {		x1 = contentsX() - x_origin > 0 ? contentsX() - x_origin : 0;		x2 = x1 + visibleWidth() - x_origin;		// FIXME if there is no border visible it's off by borderwidth pixels.	}	if (pixmap->height() < viewport()->height()) {		//qWarning("doc inside vp");		y1 = 0;		y2 = pixmap->height();	}	else {		// border visibl. at the top		if (contentsY() <= y_origin) {			//qWarning("border at top");			y1 = 0;			y2 = visibleHeight() - (y_origin - contentsY());		}		// border at the bottom		else if ((contentsY() - y_origin) + visibleHeight() >= pixmap->height()) {			//qWarning("border at bottom");			y1 = contentsY() - y_origin;			y2 = y1 + (visibleHeight() - y_origin);		}		// no border visible		else {			//qWarning("no border whatsoever");			y1 = contentsY() - y_origin;			y2 = y1 + visibleHeight();		}	}	//qWarning("y1 = %i, y2 = %i (diff %i)", y1, y2, y2 - y1);	viewRect = QRect(QPoint(x1, y1), QPoint(x2, y2));}void PDFWidget::scrollUp(int factor){	static int delayCounter = 0;	int tmp = selectNextLink(Up, selectedLink);	if (tmp != selectedLink && tmp != -1) {		selectedLink = tmp;		drawLinks(pixmap, selectedLink);		QRect m = viewRect; m.moveBy(0, -32);		Poppler::Links links = page->getLinks();		Poppler::Link l = links.getLink(selectedLink);		// will the link be visible if we scroll?		if (m.contains(l.getScreenCoords().center(), true)) {			//int x1, y1, x2, y2;			//m.coords(&x1, &y1, &x2, &y2);			//qWarning("x1 = %i, y1 = %i x2 = %i y2 = %i", x1, y1, x2, y2);			//qWarning("xc = %i, yc = %i", l.getScreenCoords().center().x(), l.getScreenCoords().center().y());			scrollBy(0, -8 * factor);		}		updateContents(0, 0, contentsWidth(), contentsHeight());	}	else {		// special case: page is to small to scroll		if (verticalScrollBar()->maxValue() == 0 && !running) {			prevPage();		}		else {			scrollBy(0, -8 * factor);					if (verticalScrollBar()->value() == verticalScrollBar()->minValue() && !running) {						delayCounter++;				if (delayCounter > MAX_SCROLL_DELAY) {					prevPage();					delayCounter = 0;				}			}			else {				delayCounter = 0;			}		}	}	updateViewRect();}void PDFWidget::scrollDown(int factor){	static int delayCounter = 0;	int tmp = selectNextLink(Down, selectedLink);	if (tmp != selectedLink && tmp != -1) {		selectedLink = tmp;		drawLinks(pixmap, selectedLink);		QRect m = viewRect; m.moveBy(0, 32);		Poppler::Links links = page->getLinks();		Poppler::Link l = links.getLink(selectedLink);		// will the link be visible if we scroll?		if (m.contains(l.getScreenCoords().center(), true)) {			//int x1, y1, x2, y2;			//m.coords(&x1, &y1, &x2, &y2);			//qWarning("x1 = %i, y1 = %i x2 = %i y2 = %i", x1, y1, x2, y2);			//qWarning("xc = %i, yc = %i", l.getScreenCoords().center().x(), l.getScreenCoords().center().y());			scrollBy(0, 8 * factor);		}		updateContents(0, 0, contentsWidth(), contentsHeight());	}	else {		// special case: page is to small to scroll		if (verticalScrollBar()->maxValue() == 0 && !running) {			nextPage();		}		else {			scrollBy(0, 8 * factor);				if (verticalScrollBar()->value() == verticalScrollBar()->maxValue() && !running) {					delayCounter++;				if (delayCounter > MAX_SCROLL_DELAY) {					nextPage();					delayCounter = 0;				}			}			else {				delayCounter = 0;			}		}	}	updateViewRect();}void PDFWidget::scrollLeft(int factor){	int tmp = selectNextLink(Left, selectedLink);	if (tmp != selectedLink) {		selectedLink = tmp;		drawLinks(pixmap, selectedLink);		scrollBy(-8 * factor, 0);		updateContents(0, 0, contentsWidth(), contentsHeight());	}	else {		scrollBy(-8 * factor, 0);	}	updateViewRect();}void PDFWidget::scrollRight(int factor){	int tmp = selectNextLink(Right, selectedLink);	if (tmp != selectedLink) {		selectedLink = tmp;		drawLinks(pixmap, selectedLink);		scrollBy(8 * factor, 0);		updateContents(0, 0, contentsWidth(), contentsHeight());	}	else {		scrollBy(8 * factor, 0);	}	updateViewRect();}void PDFWidget::display(){	if (doc) {		emit rendererRunning(true);		running = true;		firstPreview = true;		renderJob j = { doc, currentPage, m_scale };		renderThread->setJob(j);	}	else {		qWarning("No document was set");	}}void PDFWidget::customEvent(QCustomEvent *e) {    if ((int)e->type() == PageReady) {        pageReady(e->data());

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -