Added very basic sharing functionality.
[grr] / src / contentwindow.cpp
1 #include <QMenuBar>
2 #include <QDebug>
3 #include <QDesktopServices>
4 #include <QtGui>
5 #include <QtWebKit>
6
7 #include <QtGui/QX11Info>
8 #include <X11/Xlib.h>
9 #include <X11/Xatom.h>
10
11 #include "contentwindow.h"
12
13 /* Got ViewportItem and GraphicsView from maemobrowser in the qt examples. The
14  * whole point of this is to get a finger friendly web widget */
15
16 class ViewportItem : public QGraphicsWidget, public QAbstractKineticScroller {
17         Q_OBJECT
18
19         public:
20                 ViewportItem() : QGraphicsWidget(), QAbstractKineticScroller(), m_widget(0), m_ignoreEvents(false) {
21                         setFlag(QGraphicsItem::ItemHasNoContents, true);
22                         setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
23                         setFlag(QGraphicsItem::ItemClipsToShape, true);
24                         setAttribute(Qt::WA_OpaquePaintEvent, true);
25                         setFiltersChildEvents(true);
26                 }
27
28                 void setWidget(QGraphicsWidget *widget) {
29                         if (m_widget) {
30                                 m_widget->setParentItem(0);
31                                 delete m_widget;
32                         }
33                         m_widget = widget;
34                         if (m_widget) {
35                                 m_widget->setParentItem(this);
36                                 m_widget->setAttribute(Qt::WA_OpaquePaintEvent, true);
37
38                                 if (qgraphicsitem_cast<QGraphicsWebView *>(m_widget)) {
39                                         connect(m_widget, SIGNAL(loadProgress(int)), this, SLOT(resizeWebViewToFrame()));
40                                         connect(m_widget, SIGNAL(loadFinished(bool)), this, SLOT(resizeWebViewToFrame()));
41                                         resizeWebViewToFrame();
42                                 }
43                         }
44                 }
45
46         protected:
47                 bool sceneEventFilter(QGraphicsItem *i, QEvent *e) {
48                         bool res = false;
49                         if (i && (i == m_widget) && !m_ignoreEvents && m_widget->isEnabled()) {
50                                 switch (e->type()) {
51                                 case QEvent::GraphicsSceneMousePress:
52                                 case QEvent::GraphicsSceneMouseMove:
53                                 case QEvent::GraphicsSceneMouseRelease:
54                                         res = handleMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
55                                         break;
56                                 default:
57                                         break;
58                                 }
59                         }
60                         // prevent text selection and image dragging
61                         if (e->type() == QEvent::GraphicsSceneMouseMove)
62                                 return true;
63                         return res ? true : QGraphicsWidget::sceneEventFilter(i, e);
64                 }
65
66                 void keyPressEvent(QKeyEvent *e) {
67                         int x, y, w, h;
68
69                         switch(e->key()) {
70                         case Qt::Key_Down:
71                                 y = m_widget->y() - 50;
72                                 h = (m_widget->size() - size()).height();
73                                 m_widget->setY(y < -h ? -h : y);
74                                 break;
75
76                         case Qt::Key_Up:
77                                 y = m_widget->y() + 50;
78                                 m_widget->setY(y > 0 ? 0 : y);
79                                 break;
80
81                         case Qt::Key_Right:
82                                 x = m_widget->x() - 50;
83                                 w = (m_widget->size() - size()).width();
84                                 m_widget->setX(x < -w ? -w : x);
85                                 break;
86
87                         case Qt::Key_Left:
88                                 x = m_widget->x() + 50;
89                                 m_widget->setX(x > 0 ? 0 : x);
90                                 break;
91
92                         case Qt::Key_F7:
93                                 if(qgraphicsitem_cast<QGraphicsWebView *>(m_widget)) {
94                                         QGraphicsWebView *wv = (QGraphicsWebView *)m_widget;
95                                         wv->setZoomFactor(wv->zoomFactor() * 1.25);
96                                         resizeWebViewToFrame();
97                                 }
98                                 break;
99
100                         case Qt::Key_F8:
101                                 if(qgraphicsitem_cast<QGraphicsWebView *>(m_widget)) {
102                                         QGraphicsWebView *wv = (QGraphicsWebView *)m_widget;
103                                         wv->setZoomFactor(wv->zoomFactor() / 1.25);
104                                         resizeWebViewToFrame();
105                                 }
106                                 break;
107                         }
108                 }
109
110                 QSize viewportSize() const {
111                         return size().toSize();
112                 }
113
114                 QPoint maximumScrollPosition() const {
115                         QSizeF s = m_widget ? m_widget->size() - size() : QSize(0, 0);
116                         return QPoint(qMax(0, int(s.width())), qMax(0, int(s.height())));
117                 }
118
119                 QPoint scrollPosition() const {
120                         return m_widget ? -m_widget->pos().toPoint() + m_overShoot : QPoint();
121                 }
122
123                 void setScrollPosition(const QPoint &p, const QPoint &overShoot) {
124                         m_overShoot = overShoot;
125                         if (m_widget)
126                                 m_widget->setPos(-p + m_overShoot);
127                 }
128
129                 void cancelLeftMouseButtonPress(const QPoint & /*globalPressPos*/) {
130                 }
131
132                 void sendEvent(QGraphicsItem *i, QEvent *e) {
133                         m_ignoreEvents = true;
134                         scene()->sendEvent(i, e);
135                         m_ignoreEvents = false;
136                 }
137
138         private slots:
139                 void resizeWebViewToFrame() {
140                         if (QGraphicsWebView *view = qgraphicsitem_cast<QGraphicsWebView *>(m_widget)) {
141                                 if (view->page() && view->page()->mainFrame()) {
142                                         QSizeF s = view->page()->mainFrame()->contentsSize();
143                                         /* TODO: Figure out the proper way to
144                                          * get this 800 pixels. */
145                                         QSizeF s2 = size();
146                                         s2.setWidth(800);
147                                         s = s.expandedTo(s2);
148                                         view->setGeometry(QRectF(view->geometry().topLeft(), s));
149                                 }
150                         }
151                 }
152
153         private:
154                 QGraphicsWidget *m_widget;
155                 bool m_ignoreEvents;
156                 QPoint m_overShoot;
157 };
158
159 class GraphicsView : public QGraphicsView {
160         Q_OBJECT
161         
162         public:
163                 GraphicsView() : QGraphicsView(new QGraphicsScene()), viewport(0) {
164                         setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
165                         setOptimizationFlags(QGraphicsView::DontSavePainterState);
166
167                         setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
168                         setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
169
170                         setFrameShape(QFrame::NoFrame);
171                         setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
172
173                         viewport = new ViewportItem();
174                         scene()->addItem(viewport);
175                 }
176
177                 ViewportItem *viewportItem() const {
178                         return viewport;
179                 }
180
181         protected:
182                 void resizeEvent(QResizeEvent *e) {
183                         QGraphicsView::resizeEvent(e);
184                         setUpdatesEnabled(false);
185
186                         if (!viewport)
187                                 return;
188
189                         QRectF rect(QPointF(0, 0), size());
190                         scene()->setSceneRect(rect);
191
192                         viewport->setGeometry(rect);
193                         setUpdatesEnabled(true);
194                         update();
195                 }
196
197         private:
198                 ViewportItem *viewport;
199 };
200
201 ContentWindow::ContentWindow(QWidget *parent, Entry *e) : QMainWindow(parent) {
202         setAttribute(Qt::WA_Maemo5StackedWindow);
203
204         QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
205
206         entry = e;
207
208         starred = new QAction(tr("Starred"), this);
209         starred->setCheckable(true);
210         starred->setChecked((entry->flags & ENTRY_FLAG_STARRED));
211         menuBar()->addAction(starred);
212
213         shared = new QAction(tr("Shared"), this);
214         shared->setCheckable(true);
215         shared->setChecked((entry->flags & ENTRY_FLAG_SHARED));
216         menuBar()->addAction(shared);
217
218         keepUnread = new QAction(tr("Keep unread"), this);
219         keepUnread->setCheckable(true);
220         keepUnread->setEnabled((entry->flags & ENTRY_FLAG_LOCKED) == 0);
221         menuBar()->addAction(keepUnread);
222
223         menuBar()->addAction(tr("See original"), this, SLOT(seeOriginal()));
224
225         setWindowTitle(entry->title);
226
227         GraphicsView *gv = new GraphicsView();
228         webview = new QGraphicsWebView();
229         gv->viewportItem()->setWidget(webview);
230
231         /* TODO: Configurable text size ?? */
232         webview->settings()->setFontSize(QWebSettings::MinimumFontSize, 22);
233
234         connect(webview, SIGNAL(loadFinished(bool)), SLOT(loadFinished(bool)));
235         connect(webview, SIGNAL(loadStarted()), SLOT(loadStarted()));
236
237         webview->setHtml(entry->content);
238
239         setCentralWidget(gv);
240         gv->viewportItem()->setFocus();
241         gv->viewportItem()->grabKeyboard();
242
243         grabZoomKeys(true);
244 }
245
246 ContentWindow::~ContentWindow() {
247         delete(webview);
248 }
249
250 void ContentWindow::loadStarted() {
251         setAttribute(Qt::WA_Maemo5ShowProgressIndicator, true);
252 }
253
254 void ContentWindow::loadFinished(bool) {
255         setAttribute(Qt::WA_Maemo5ShowProgressIndicator, false);
256 }
257
258 void ContentWindow::seeOriginal() {
259         /* Attempt to launch external browser */
260         if(!QDesktopServices::openUrl(entry->link))
261                 webview->setUrl(entry->link); /* Failed... Show inline */
262 }
263
264 void ContentWindow::closeEvent(QCloseEvent *event) {
265         grabZoomKeys(false);
266         entry->markRead(!keepUnread->isChecked());
267         entry->markStar(starred->isChecked());
268         entry->markShared(shared->isChecked());
269         QMainWindow::closeEvent(event);
270 }
271
272 void ContentWindow::grabZoomKeys(bool grab) {
273         if(!winId())
274                 return;
275
276         unsigned long val = (grab) ? 1 : 0;
277         Atom atom = XInternAtom(QX11Info::display(), "_HILDON_ZOOM_KEY_ATOM", False);
278         if(!atom)
279                 return;
280
281         XChangeProperty (QX11Info::display(), winId(), atom, XA_INTEGER, 32, PropModeReplace,
282                 reinterpret_cast<unsigned char *>(&val), 1);
283 }
284
285 #include "contentwindow.moc"