00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "PDFView.h"
00025 #include "PDFViewerLog.h"
00026 #include "goo/gtypes.h"
00027 #include "controller.h"
00028 #include "PageInfo.h"
00029 #include <X11/keysym.h>
00030 #include "liberdm/erdm.h"
00031 #include "PDFApp.h"
00032 #include <liberipc/eripcviewer.h>
00033 #include <math.h>
00034 #include "PDFPortraitView.h"
00035 #include "PDFLandscapeView.h"
00036 #include "GtkAuthDialog.h"
00037
00038 static CPDFPortraitView portraitView;
00039 static CPDFLandscapeView landscapeView;
00040
00041 CPDFView::CPDFView(GtkWidget * win, Controller * c)
00042 {
00043 drawArea = win; ctrl = c;
00044
00045
00046 int nRet = 0, fd = -1;
00047 erServerChannel_t channel;
00048 nRet = erIpcOpenServerChannel(ER_PDF_VIEWER_CHANNEL, &channel);
00049 ctrl->channels.erIpcChannel = channel;
00050 fd = erIpcGetServerFd(channel);
00051
00052 gdk_input_add (fd,
00053 GDK_INPUT_READ,
00054 (GdkInputFunction)ipcCbk,
00055 (gpointer) this);
00056
00057
00058 bAuth = gFalse;
00059 password = NULL;
00060
00061
00062 panPt.x = panPt.y = 0;
00063 zoomRect.left = zoomRect.top = zoomRect.right = zoomRect.bottom = 0;
00064 portraitView.setView(this);
00065 landscapeView.setView(this);
00066
00067 installEventHandler(win);
00068 }
00069
00070 void CPDFView::initializeViews()
00071 {
00072
00073 if (bAuth)
00074 {
00075 bAuth = gFalse;
00076 gtk_window_unfullscreen(GTK_WINDOW(drawArea));
00077 }
00078
00079
00080 if (isLandscapeView())
00081 {
00082 landscapeView.init();
00083 }
00084 else
00085 {
00086 portraitView.init();
00087 }
00088 }
00089
00090 CPDFView::~CPDFView(void)
00091 {
00092 }
00093
00094 void CPDFView::installEventHandler(GtkWidget * window)
00095 {
00096 drawArea = window;
00097
00098 gtk_signal_connect (GTK_OBJECT (window), "expose_event",
00099 GTK_SIGNAL_FUNC (exposeCbk), this);
00100
00101 gtk_signal_connect (GTK_OBJECT (window), "button_press_event",
00102 GTK_SIGNAL_FUNC (buttonPressCbk), this);
00103
00104 gtk_signal_connect (GTK_OBJECT (window), "button_release_event",
00105 GTK_SIGNAL_FUNC (buttonReleaseCbk), this);
00106
00107 gtk_signal_connect (GTK_OBJECT (window), "motion_notify_event",
00108 GTK_SIGNAL_FUNC (motionNotifyCbk), this);
00109
00110 gtk_signal_connect (GTK_OBJECT (window), "key_press_event",
00111 GTK_SIGNAL_FUNC (keyPressCbk), this);
00112
00113 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
00114 GTK_SIGNAL_FUNC (deleteCbk), this);
00115 }
00116
00117 void CPDFView::onClose()
00118 {
00119 portraitView.clear();
00120 landscapeView.clear();
00121 ctrl->scbMgr.close();
00122 }
00123
00124 void CPDFView::initPan(const int x, const int y)
00125 {
00126 panPt.x = x; panPt.y = y;
00127 }
00128
00129 void CPDFView::initZoomRect(const int x, const int y)
00130 {
00131 zoomRect.left = zoomRect.right = x;
00132 zoomRect.top = zoomRect.bottom = y;
00133 }
00134
00135 void CPDFView::adjustZoomRect(const int x, const int y)
00136 {
00137 if (zoomRect.left > x)
00138 {
00139 zoomRect.left = x;
00140 }
00141 if (zoomRect.top > y)
00142 {
00143 zoomRect.top = y;
00144 }
00145 if (zoomRect.right < x)
00146 {
00147 zoomRect.right = x;
00148 }
00149 if (zoomRect.bottom < y)
00150 {
00151 zoomRect.bottom = y;
00152 }
00153 }
00154
00155 GBool CPDFView::isSmallOffset(const int x, const int y)
00156 {
00157 if (isPanEnable())
00158 {
00159 return (abs(panPt.x - x) < SmallOffset &&
00160 abs(panPt.y - y) < SmallOffset);
00161 }
00162 if (isZoomInEnable() ||
00163 isZoomOutEnable())
00164 {
00165 adjustZoomRect(x, y);
00166 return (abs(zoomRect.left - zoomRect.right) < SmallOffset &&
00167 abs(zoomRect.top - zoomRect.bottom) < SmallOffset);
00168 }
00169 return gTrue;
00170 }
00171
00172 int CPDFView::lessThreshold(const rectangle & rect)
00173 {
00174 if (rect.right - rect.left < RectThreshold)
00175 {
00176 return SmallWidth;
00177 }
00178
00179 if (rect.bottom - rect.top < RectThreshold)
00180 {
00181 return SmallHeight;
00182 }
00183 return SmallNone;
00184 }
00185
00186 GBool CPDFView::isPanEnable()
00187 {
00188 return ctrl->channels.isPanEnable();
00189 }
00190
00191 GBool CPDFView::isZoomInEnable()
00192 {
00193 return ctrl->channels.isZoomInEnable();
00194 }
00195
00196 GBool CPDFView::isZoomOutEnable()
00197 {
00198 return ctrl->channels.isZoomOutEnable();
00199 }
00200
00201 GBool CPDFView::isScribbleEnable()
00202 {
00203 return ctrl->channels.isScribbleEnable();
00204 }
00205
00206 GBool CPDFView::isEraseEnable()
00207 {
00208 return ctrl->channels.isEraseEnable();
00209 }
00210
00211 GBool CPDFView::isPageMode()
00212 {
00213 return (ctrl->settings.getMode() & ModePage);
00214 }
00215
00216 GBool CPDFView::isContinousMode()
00217 {
00218 return (ctrl->settings.getMode() & ModeContinous);
00219 }
00220
00221 void CPDFView::setPageMode()
00222 {
00223 ctrl->settings.setMode(ModePage);
00224 }
00225
00226 void CPDFView::setContinousMode()
00227 {
00228 ctrl->settings.setMode(ModeContinous);
00229 }
00230
00231 GBool CPDFView::isPortraitView()
00232 {
00233 return (ctrl->settings.getRotate() == 0 ||
00234 ctrl->settings.getRotate() == 180);
00235 }
00236
00237 GBool CPDFView::isLandscapeView()
00238 {
00239 return (ctrl->settings.getRotate() == 90 ||
00240 ctrl->settings.getRotate() == 270);
00241 }
00242
00244
00245 gboolean CPDFView::exposeCbk(GtkWidget * widget, GdkEventExpose * event, gpointer ptr)
00246 {
00247 CPDFView * view = (CPDFView *)ptr;
00248 if (view->isPortraitView())
00249 {
00250 if (!portraitView.isReady()) return TRUE;
00251 }
00252 else if (view->isLandscapeView())
00253 {
00254 if (!landscapeView.isReady()) return TRUE;
00255 }
00256
00257
00258 if (view->ctrl->settings.getCurrentPage() > 0)
00259 {
00260 view->displayPage(view->ctrl->settings.getCurrentPage(), ScrollRedraw);
00261 }
00262 return TRUE;
00263 }
00264
00265 gboolean CPDFView::buttonPressCbk(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
00266 {
00267 CPDFView *view = (CPDFView *)user_data;
00268 if (view->isPortraitView())
00269 {
00270 return portraitView.buttonPressCbk(event);
00271 }
00272 else if (view->isLandscapeView())
00273 {
00274 return landscapeView.buttonPressCbk(event);
00275 }
00276 return TRUE;
00277 }
00278
00279 gboolean CPDFView::buttonReleaseCbk(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
00280 {
00281 CPDFView *view = (CPDFView *)user_data;
00282 if (view->isPortraitView())
00283 {
00284 return portraitView.buttonReleaseCbk(event);
00285 }
00286 else if (view->isLandscapeView())
00287 {
00288 return landscapeView.buttonReleaseCbk(event);
00289 }
00290 return TRUE;
00291 }
00292
00293 gboolean CPDFView::motionNotifyCbk(GtkWidget * widget, GdkEventMotion * event, gpointer user_data)
00294 {
00295 CPDFView *view = (CPDFView *)user_data;
00296 if (view->isPortraitView())
00297 {
00298 return portraitView.motionNotifyCbk(event);
00299 }
00300 else if (view->isLandscapeView())
00301 {
00302 return landscapeView.motionNotifyCbk(event);
00303 }
00304 return TRUE;
00305 }
00306
00307 gboolean CPDFView::keyPressCbk(GtkWidget * widget, GdkEventKey * event, gpointer user_data)
00308 {
00309 CPDFView *view = (CPDFView *)user_data;
00310 if (view->isPortraitView())
00311 {
00312 return portraitView.keyPressCbk(event);
00313 }
00314 else if (view->isLandscapeView())
00315 {
00316 return landscapeView.keyPressCbk(event);
00317 }
00318 return FALSE;
00319 }
00320
00321 gboolean CPDFView::deleteCbk(GtkWidget * widget, GdkEvent * event, gpointer user_data)
00322 {
00323 return TRUE;
00324 }
00325
00327
00328
00329 double CPDFView::calRatio(rectangle & rect, GBool bZoomin)
00330 {
00331 double ratio = 1.0 , tmp = 1.0;
00332 int width = abs(rect.right - rect.left) + 1;
00333 int height = abs(rect.bottom - rect.top) + 1;
00334
00335 if (bZoomin)
00336 {
00337 ratio = (double)ctrl->settings.getScreenWidth() / (double)width;
00338 tmp = (double)ctrl->settings.getScreenHeight() / (double)height;
00339 }
00340 else
00341 {
00342 ratio = (double)width / (double)ctrl->settings.getScreenWidth();
00343 tmp = (double)height / (double)ctrl->settings.getScreenHeight();
00344 }
00345 if (ratio > tmp) return tmp;
00346 return ratio;
00347 }
00348
00350
00351
00352
00353
00355 void CPDFView::displayPage(const int pageNumber, const ContinousModeScroll mode)
00356 {
00357
00358 if (isPortraitView())
00359 {
00360 portraitView.displayPage(pageNumber, mode);
00361 }
00362 else if (isLandscapeView())
00363 {
00364 landscapeView.displayPage(pageNumber, mode);
00365 }
00366 }
00367
00368
00369 void CPDFView::issueItem(const int pn, GBool bHead, const int time)
00370 {
00371 if (pn < 1 || pn > ctrl->core->getNumPages())
00372 {
00373 PV_LOGPRINTF("Do not issue page %d", pn);
00374 return;
00375 }
00376 PV_LOGPRINTF("IssueItem %d\n", pn);
00377 TodoItem * item = new TodoItem;
00378 item->pageNumber = pn;
00379 item->rotate = ctrl->settings.getRotate();
00380 item->zoom = ctrl->calZoom(pn);
00381 item->timeStamp = ctrl->getTimeStamp() + time;
00382 ctrl->thread.addTodoItem(item, bHead);
00383 }
00384
00385 void CPDFView::issuePrevNextPages(const int width, const int from, const int timeOffset)
00386 {
00387 if (ctrl->settings.getRenderDir() == RenderPrev)
00388 {
00389 for(int i = width; i >= 1; --i)
00390 {
00391 issueItem(ctrl->settings.getCurrentPage() - from - i, gTrue, timeOffset);
00392 }
00393 }
00394 else if (ctrl->settings.getRenderDir() == RenderNext)
00395 {
00396 for(int i = width; i >= 1; --i)
00397 {
00398 issueItem(ctrl->settings.getCurrentPage() + from + i, gTrue, timeOffset);
00399 }
00400 }
00401 }
00402
00403 void CPDFView::issueLinks(CPageInfo *page)
00404 {
00405 if (NULL == page->links) return;
00406 int count = page->links->getNumLinks();
00407 PV_LOGPRINTF("Link count %d in page %d", count, page->pageNumber);
00408 for(int i = 0; i < count; ++i)
00409 {
00410 issueLink(page->links->getLink(i));
00411 }
00412 }
00413
00414 void CPDFView::issueLink(Link * p)
00415 {
00416 if (NULL == p) return;
00417 int pn = getLinkPage(p->getAction());
00418 if (pn >= 1)
00419 {
00420 PV_LOGPRINTF("Issue page %d", pn);
00421 issueItem(pn);
00422 return;
00423 }
00424 PV_LOGPRINTF("Invalid link page number %d!", pn);
00425 }
00426
00427 int CPDFView::getLinkPage(LinkAction *action)
00428 {
00429 if (NULL == action) return -1;
00430 LinkActionKind kind;
00431 LinkDest *dest = NULL;
00432 UGooString *namedDest = NULL;
00433
00434 switch (kind = action->getKind())
00435 {
00436 case actionGoTo:
00437 dest = ((LinkGoTo *)action)->getDest();
00438 namedDest = ((LinkGoTo *)action)->getNamedDest();
00439 if (dest && dest->isPageRef())
00440 {
00441 Ref pageRef = dest->getPageRef();
00442 return ctrl->core->getPDFDoc()->findPage(pageRef.num, pageRef.gen);
00443 }
00444 else if (namedDest)
00445 {
00446 dest = ctrl->core->getPDFDoc()->findDest(namedDest);
00447 if (dest)
00448 {
00449 Ref pageRef = dest->getPageRef();
00450 return ctrl->core->getPDFDoc()->findPage(pageRef.num, pageRef.gen);
00451 }
00452 }
00453 break;
00454 default:
00455 break;
00456 }
00457 return -1;
00458 }
00459
00461
00462
00463 void CPDFView::issueNewRequests()
00464 {
00465 CPageInfo * page = ctrl->pageList.getPage(ctrl->settings.getCurrentPage());
00466 PV_LOGPRINTF("Current page %d %p\n", ctrl->settings.getCurrentPage(), page);
00467 ctrl->thread.clearTodoList();
00468 if (page)
00469 {
00470 if (page->links)
00471 {
00472 int count = page->links->getNumLinks();
00473 if (count <= 0)
00474 {
00475 issuePrevNextPages(RenderWidth);
00476 }
00477 else
00478 {
00479
00480
00481
00482
00483 issuePrevNextPages(RenderWidth - RenderFrom, RenderFrom);
00484 issueLinks(page);
00485 issuePrevNextPages(RenderFrom, 0, TimeOffset);
00486 }
00487 }
00488 else
00489 {
00490 issuePrevNextPages(RenderWidth);
00491 }
00492 }
00493 else
00494 {
00495 issuePrevNextPages(RenderWidth);
00496 }
00497 ctrl->thread.signal();
00498 }
00499
00500
00501 void CPDFView::ipcCbk(gpointer client_data, gint * fd,
00502 GdkInputCondition id)
00503 {
00504 CPDFView *viewer = (CPDFView *)client_data;
00505 if (viewer->bAuth) return;
00506
00507 if (viewer->isPortraitView())
00508 {
00509 portraitView.ipcCbk(fd, id);
00510 }
00511 else if (viewer->isLandscapeView())
00512 {
00513 landscapeView.ipcCbk(fd, id);
00514 }
00515 }
00516
00518
00519
00520
00521
00522
00523
00524
00525 void CPDFView::rotatePageMode(const int angle)
00526 {
00527
00528 CPageInfo * page = ctrl->pageList.getPage(ctrl->settings.getCurrentPage());
00529
00530
00531 rectangle rect; rect.left = 0; rect.top = 0;
00532 rect.right = ctrl->settings.getScreenWidth();
00533 rect.bottom = ctrl->settings.getScreenHeight();
00534 if (ctrl->settings.getScreenX() > 0) rect.left = ctrl->settings.getScreenX();
00535 if (ctrl->settings.getScreenY() > 0) rect.top = ctrl->settings.getScreenY();
00536 if (rect.right > ctrl->settings.getScreenX() + page->bitmap->getWidth())
00537 {
00538 rect.right = ctrl->settings.getScreenX() + page->bitmap->getWidth();
00539 }
00540 if (rect.bottom > ctrl->settings.getScreenY() + page->bitmap->getHeight())
00541 {
00542 rect.bottom = ctrl->settings.getScreenY() + page->bitmap->getHeight();
00543 }
00544 point center;
00545 center.x = ((rect.left + rect.right) >> 1);
00546 center.y = ((rect.top + rect.bottom) >> 1);
00547 int distX = 0, distY = 0;
00548
00549
00550 if (angle == 90)
00551 {
00552 distX = center.x - ctrl->settings.getScreenX();
00553 distY = page->bitmap->getHeight() - center.y + ctrl->settings.getScreenY();
00554 ctrl->settings.setScreenX(center.x - distY);
00555 ctrl->settings.setScreenY(center.y - distX);
00556 }
00557 else if (angle == -90)
00558 {
00559 distX = page->bitmap->getWidth() - center.x + ctrl->settings.getScreenX();
00560 distY = center.y - ctrl->settings.getScreenY();
00561 ctrl->settings.setScreenX(center.x - distY);
00562 ctrl->settings.setScreenY(center.y - distX);
00563 }
00564 int rot = angle + ctrl->settings.getRotate();
00565 if (rot < 0) rot += 360;
00566 else if (rot >= 360) rot -= 360;
00567
00568 ctrl->settings.setRotate(rot);
00569 displayPage(ctrl->settings.getCurrentPage());
00570 }
00571
00572 void CPDFView::rotateContinousMode(const int angle)
00573 {
00574 int rot = ctrl->settings.getRotate();
00575 rot += angle;
00576 if (rot < 0) rot += 360;
00577 else if (rot >= 360) rot -= 360;
00578 ctrl->settings.setRotate(rot);
00579
00580
00581 if (ctrl->settings.getRotate() == 270 || ctrl->settings.getRotate() == 90)
00582 {
00583 int x = ctrl->settings.getScreenX();
00584 ctrl->settings.setScreenX(ctrl->settings.getScreenY());
00585 ctrl->settings.setScreenY(x);
00586 }
00587 else
00588 {
00589 int x = ctrl->settings.getScreenX();
00590 ctrl->settings.setScreenX(ctrl->settings.getScreenY());
00591 ctrl->settings.setScreenY(x);
00592 }
00593
00594
00595 ctrl->settings.disableZoomBack();
00596
00597 initializeViews();
00598 displayPage(ctrl->settings.getCurrentPage(), ScrollToPosition);
00599 }
00600
00601
00602 void CPDFView::refreshDeviceScreen(eDmQuality quality, GBool bOff)
00603 {
00604 dmDisplay(dmCmdPriorUrgent, quality);
00605 if (bOff)
00606 {
00607 ctrl->channels.busy_off();
00608 }
00609 }
00610
00611 void CPDFView::cvtDevToUser(CPageInfo *page, const int offsetX, const int offsetY, double & ux, double & uy)
00612 {
00613 ux = page->ictm[0] * (offsetX) +
00614 page->ictm[2] * (offsetY) + page->ictm[4];
00615 uy = page->ictm[1] * (offsetX) +
00616 page->ictm[3] * (offsetY) + page->ictm[5];
00617 }
00618
00619 GBool CPDFView::doLink(const int pn, int offsetX, int offsetY)
00620 {
00621 CPageInfo * page = ctrl->pageList.getPage(pn);
00622 if (NULL == page || NULL == page->links) return gFalse;
00623 double ux = 0.0, uy = 0.0;
00624 cvtDevToUser(page, offsetX, offsetY, ux, uy);
00625 LinkAction * action = page->links->find(ux, uy);
00626 if (NULL == action) return gFalse;
00627 return doAction(action);
00628 }
00629
00630 GBool CPDFView::doAction(LinkAction * action)
00631 {
00632 PV_LOGPRINTF("Do some action!");
00633 LinkActionKind kind;
00634 LinkDest *dest = NULL;
00635 UGooString *namedDest = NULL;
00636
00637 switch (kind = action->getKind())
00638 {
00639 case actionGoTo:
00640 ctrl->channels.busy_blink();
00641 PV_LOGPRINTF("actionGoTo");
00642 dest = ((LinkGoTo *)action)->getDest();
00643 namedDest = ((LinkGoTo *)action)->getNamedDest();
00644 if (dest && dest->isPageRef())
00645 {
00646 Ref pageRef = dest->getPageRef();
00647 int pageNumber = ctrl->core->getPDFDoc()->findPage(pageRef.num, pageRef.gen);
00648 PV_LOGPRINTF("Goto Page %d", pageNumber);
00649 displayPage(pageNumber);
00650 return gTrue;
00651 }
00652 else if (namedDest)
00653 {
00654 dest = ctrl->core->getPDFDoc()->findDest(namedDest);
00655 if (dest)
00656 {
00657 Ref pageRef = dest->getPageRef();
00658 int pageNumber = ctrl->core->getPDFDoc()->findPage(pageRef.num, pageRef.gen);
00659 PV_LOGPRINTF("Goto Page %d", pageNumber);
00660 displayPage(pageNumber);
00661 return gTrue;
00662 }
00663 }
00664 break;
00665 case actionLaunch:
00666 PV_LOGPRINTF("actionLaunch!");
00667 break;
00668
00669 case actionNamed:
00670 PV_LOGPRINTF("actionNamed!");
00671 break;
00672 case actionURI:
00673 PV_LOGPRINTF("actionURI!");
00674 break;
00675 case actionMovie:
00676 PV_LOGPRINTF("actionMovie!");
00677 break;
00678 default:
00679 PV_LOGPRINTF("unknown!");
00680 break;
00681 }
00682 return gFalse;
00683 }
00684
00686
00687 GooString *CPDFView::getPassword()
00688 {
00689
00690 dialogDone = -1;
00691 bAuth = gTrue;
00692 GtkAuthDialog dlg;
00693 gtk_window_fullscreen(GTK_WINDOW(drawArea));
00694 if (!dlg.popupAuthDialog(this))
00695 {
00696 if (password)
00697 {
00698 delete password;
00699 password = NULL;
00700 }
00701 }
00702 else
00703 {
00704 password = new GooString(dlg.getPassword());
00705 }
00706 return password;
00707 }
00708
00709 void CPDFView::quit()
00710 {
00711
00712 onClose();
00713
00714
00715 ctrl->channels.busy_blink();
00716 ctrl->app->quit(!bAuth);
00717 }
00718
00719