1 | /* This file is part of the KDE project |
2 | Copyright (C) 2000 Simon Hausmann <hausmann@kde.org> |
3 | |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2 of the License, or (at your option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "khtmlimage.h" |
21 | #include "khtmlview.h" |
22 | #include "khtml_ext.h" |
23 | #include "xml/dom_docimpl.h" |
24 | #include "html/html_documentimpl.h" |
25 | #include "html/html_elementimpl.h" |
26 | #include "rendering/render_image.h" |
27 | #include "misc/loader.h" |
28 | |
29 | |
30 | #include <QtCore/QTimer> |
31 | |
32 | #include <kjobuidelegate.h> |
33 | #include <kio/job.h> |
34 | #include <kcomponentdata.h> |
35 | #include <kmimetype.h> |
36 | #include <klocale.h> |
37 | #include <kvbox.h> |
38 | #include <kactioncollection.h> |
39 | |
40 | KComponentData *KHTMLImageFactory::s_componentData = 0; |
41 | |
42 | KHTMLImageFactory::KHTMLImageFactory() |
43 | { |
44 | s_componentData = new KComponentData( "khtmlimage" ); |
45 | } |
46 | |
47 | KHTMLImageFactory::~KHTMLImageFactory() |
48 | { |
49 | delete s_componentData; |
50 | } |
51 | |
52 | QObject * KHTMLImageFactory::create(const char* iface, |
53 | QWidget *parentWidget, |
54 | QObject *parent, |
55 | const QVariantList& args, |
56 | const QString &keyword) |
57 | { |
58 | Q_UNUSED(keyword); |
59 | KHTMLPart::GUIProfile prof = KHTMLPart::DefaultGUI; |
60 | if (strcmp( iface, "Browser/View" ) == 0) // old hack, now unused - KDE5: remove |
61 | prof = KHTMLPart::BrowserViewGUI; |
62 | if (args.contains("Browser/View" )) |
63 | prof = KHTMLPart::BrowserViewGUI; |
64 | return new KHTMLImage( parentWidget, parent, prof ); |
65 | } |
66 | |
67 | KHTMLImage::KHTMLImage( QWidget *parentWidget, |
68 | QObject *parent, KHTMLPart::GUIProfile prof ) |
69 | : KParts::ReadOnlyPart( parent ), m_image( 0 ) |
70 | { |
71 | KHTMLPart* parentPart = qobject_cast<KHTMLPart*>( parent ); |
72 | setComponentData( KHTMLImageFactory::componentData(), prof == KHTMLPart::BrowserViewGUI && !parentPart ); |
73 | |
74 | KVBox *box = new KVBox( parentWidget ); |
75 | box->setAcceptDrops( true ); |
76 | |
77 | m_khtml = new KHTMLPart( box, this, prof ); |
78 | m_khtml->setAutoloadImages( true ); |
79 | |
80 | // We do not want our subpart to be destroyed when its widget is, |
81 | // since that may cause all KHTMLParts to die when we're dealing |
82 | // with |
83 | m_khtml->setAutoDeletePart( false ); |
84 | |
85 | connect( m_khtml->view(), SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition()) ); |
86 | |
87 | setWidget( box ); |
88 | |
89 | // VBox can't take focus, so pass it on to sub-widget |
90 | box->setFocusProxy( m_khtml->widget() ); |
91 | |
92 | m_ext = new KHTMLImageBrowserExtension( this ); |
93 | m_ext->setObjectName( "be" ); |
94 | |
95 | m_sbExt = new KParts::StatusBarExtension( this ); |
96 | m_sbExt->setObjectName( "sbe" ); |
97 | |
98 | // Remove unnecessary actions. |
99 | delete actionCollection()->action( "setEncoding" ); |
100 | delete actionCollection()->action( "viewDocumentSource" ); |
101 | delete actionCollection()->action( "selectAll" ); |
102 | |
103 | // forward important signals from the khtml part |
104 | |
105 | // forward opening requests to parent frame (if existing) |
106 | KHTMLPart *p = qobject_cast<KHTMLPart*>(parent); |
107 | KParts::BrowserExtension *be = p ? p->browserExtension() : m_ext; |
108 | connect(m_khtml->browserExtension(), SIGNAL(openUrlRequestDelayed(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)), |
109 | be, SIGNAL(openUrlRequestDelayed(KUrl,KParts::OpenUrlArguments,KParts::BrowserArguments))); |
110 | |
111 | connect(m_khtml->browserExtension(), SIGNAL(popupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), |
112 | this, SLOT(slotPopupMenu(QPoint,KUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); |
113 | |
114 | connect( m_khtml->browserExtension(), SIGNAL(enableAction(const char*,bool)), |
115 | m_ext, SIGNAL(enableAction(const char*,bool)) ); |
116 | |
117 | m_ext->setURLDropHandlingEnabled( true ); |
118 | } |
119 | |
120 | KHTMLImage::~KHTMLImage() |
121 | { |
122 | disposeImage(); |
123 | |
124 | // important: delete the html part before the part or qobject destructor runs. |
125 | // we now delete the htmlpart which deletes the part's widget which makes |
126 | // _OUR_ m_widget 0 which in turn avoids our part destructor to delete the |
127 | // widget ;-) |
128 | // ### additional note: it _can_ be that the part has been deleted before: |
129 | // when we're in a html frameset and the view dies first, then it will also |
130 | // kill the htmlpart |
131 | if ( m_khtml ) |
132 | delete static_cast<KHTMLPart *>( m_khtml ); |
133 | } |
134 | |
135 | bool KHTMLImage::openUrl( const KUrl &url ) |
136 | { |
137 | static const QString &html = KGlobal::staticQString( "<html><body><img src=\"%1\"></body></html>" ); |
138 | |
139 | // Propagate statusbar to our kid part. |
140 | KParts::StatusBarExtension::childObject( m_khtml )->setStatusBar( m_sbExt->statusBar() ); |
141 | |
142 | disposeImage(); |
143 | |
144 | setUrl(url); |
145 | |
146 | emit started( 0 ); |
147 | |
148 | KParts::OpenUrlArguments args = arguments(); |
149 | m_mimeType = args.mimeType(); |
150 | |
151 | emit setWindowCaption( url.prettyUrl() ); |
152 | |
153 | // Need to keep a copy of the offsets since they are cleared when emitting completed |
154 | m_xOffset = args.xOffset(); |
155 | m_yOffset = args.yOffset(); |
156 | |
157 | m_khtml->begin( this->url() ); |
158 | m_khtml->setAutoloadImages( true ); |
159 | |
160 | DOM::DocumentImpl *impl = dynamic_cast<DOM::DocumentImpl *>( m_khtml->document().handle() ); // ### hack ;-) |
161 | if (!impl) return false; |
162 | |
163 | if ( arguments().reload() ) |
164 | impl->docLoader()->setCachePolicy( KIO::CC_Reload ); |
165 | |
166 | khtml::DocLoader *dl = impl->docLoader(); |
167 | m_image = dl->requestImage( this->url().url() ); |
168 | if ( m_image ) |
169 | m_image->ref( this ); |
170 | |
171 | m_khtml->write( html.arg( this->url().url() ) ); |
172 | m_khtml->end(); |
173 | |
174 | /* |
175 | connect( khtml::Cache::loader(), SIGNAL(requestDone(khtml::DocLoader*,khtml::CachedObject*)), |
176 | this, SLOT(updateWindowCaption()) ); |
177 | */ |
178 | return true; |
179 | } |
180 | |
181 | bool KHTMLImage::closeUrl() |
182 | { |
183 | disposeImage(); |
184 | return m_khtml->closeUrl(); |
185 | } |
186 | |
187 | // This can happen after openUrl returns, or directly from m_image->ref() |
188 | void KHTMLImage::notifyFinished( khtml::CachedObject *o ) |
189 | { |
190 | if ( !m_image || o != m_image ) |
191 | return; |
192 | |
193 | //const QPixmap &pix = m_image->pixmap(); |
194 | QString caption; |
195 | |
196 | KMimeType::Ptr mimeType; |
197 | if ( !m_mimeType.isEmpty() ) |
198 | mimeType = KMimeType::mimeType(m_mimeType, KMimeType::ResolveAliases); |
199 | |
200 | if ( mimeType ) { |
201 | if ( !m_image->suggestedTitle().isEmpty() ) { |
202 | caption = i18n( "%1 (%2 - %3x%4 Pixels)" , m_image->suggestedTitle(), mimeType->comment(), m_image->pixmap_size().width(), m_image->pixmap_size().height() ); |
203 | } else { |
204 | caption = i18n( "%1 - %2x%3 Pixels" , mimeType->comment() , |
205 | m_image->pixmap_size().width() , m_image->pixmap_size().height() ); |
206 | } |
207 | } else { |
208 | if ( !m_image->suggestedTitle().isEmpty() ) { |
209 | caption = i18n( "%1 (%2x%3 Pixels)" , m_image->suggestedTitle(), m_image->pixmap_size().width() , m_image->pixmap_size().height() ); |
210 | } else { |
211 | caption = i18n( "Image - %1x%2 Pixels" , m_image->pixmap_size().width() , m_image->pixmap_size().height() ); |
212 | } |
213 | } |
214 | |
215 | emit setWindowCaption( caption ); |
216 | emit completed(); |
217 | emit setStatusBarText(i18n("Done." )); |
218 | } |
219 | |
220 | void KHTMLImage::restoreScrollPosition() |
221 | { |
222 | if ( m_khtml->view()->contentsY() == 0 ) { |
223 | m_khtml->view()->setContentsPos( m_xOffset, m_yOffset ); |
224 | } |
225 | } |
226 | |
227 | void KHTMLImage::guiActivateEvent( KParts::GUIActivateEvent *e ) |
228 | { |
229 | // prevent the base implementation from emitting setWindowCaption with |
230 | // our url. It destroys our pretty, previously caption. Konq saves/restores |
231 | // the caption for us anyway. |
232 | if ( e->activated() ) |
233 | return; |
234 | KParts::ReadOnlyPart::guiActivateEvent(e); |
235 | } |
236 | |
237 | /* |
238 | void KHTMLImage::slotImageJobFinished( KIO::Job *job ) |
239 | { |
240 | if ( job->error() ) |
241 | { |
242 | job->uiDelegate()->showErrorMessage(); |
243 | emit canceled( job->errorString() ); |
244 | } |
245 | else |
246 | { |
247 | emit completed(); |
248 | QTimer::singleShot( 0, this, SLOT(updateWindowCaption()) ); |
249 | } |
250 | } |
251 | |
252 | void KHTMLImage::updateWindowCaption() |
253 | { |
254 | if ( !m_khtml ) |
255 | return; |
256 | |
257 | DOM::HTMLDocumentImpl *impl = dynamic_cast<DOM::HTMLDocumentImpl *>( m_khtml->document().handle() ); |
258 | if ( !impl ) |
259 | return; |
260 | |
261 | DOM::HTMLElementImpl *body = impl->body(); |
262 | if ( !body ) |
263 | return; |
264 | |
265 | DOM::NodeImpl *image = body->firstChild(); |
266 | if ( !image ) |
267 | return; |
268 | |
269 | khtml::RenderImage *renderImage = dynamic_cast<khtml::RenderImage *>( image->renderer() ); |
270 | if ( !renderImage ) |
271 | return; |
272 | |
273 | QPixmap pix = renderImage->pixmap(); |
274 | |
275 | QString caption; |
276 | |
277 | KMimeType::Ptr mimeType; |
278 | if ( !m_mimeType.isEmpty() ) |
279 | mimeType = KMimeType::mimeType( m_mimeType, KMimeType::ResolveAliases ); |
280 | |
281 | if ( mimeType ) |
282 | caption = i18n( "%1 - %2x%3 Pixels" ).arg( mimeType->comment() ) |
283 | .arg( pix.width() ).arg( pix.height() ); |
284 | else |
285 | caption = i18n( "Image - %1x%2 Pixels" ).arg( pix.width() ).arg( pix.height() ); |
286 | |
287 | emit setWindowCaption( caption ); |
288 | emit completed(); |
289 | emit setStatusBarText(i18n("Done.")); |
290 | } |
291 | */ |
292 | |
293 | void KHTMLImage::disposeImage() |
294 | { |
295 | if ( !m_image ) |
296 | return; |
297 | |
298 | m_image->deref( this ); |
299 | m_image = 0; |
300 | } |
301 | |
302 | KHTMLImageBrowserExtension::KHTMLImageBrowserExtension( KHTMLImage *parent ) |
303 | : KParts::BrowserExtension( parent ) |
304 | { |
305 | m_imgPart = parent; |
306 | } |
307 | |
308 | int KHTMLImageBrowserExtension::xOffset() |
309 | { |
310 | return m_imgPart->doc()->view()->contentsX(); |
311 | } |
312 | |
313 | int KHTMLImageBrowserExtension::yOffset() |
314 | { |
315 | return m_imgPart->doc()->view()->contentsY(); |
316 | } |
317 | |
318 | void KHTMLImageBrowserExtension::print() |
319 | { |
320 | static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->print(); |
321 | } |
322 | |
323 | void KHTMLImageBrowserExtension::reparseConfiguration() |
324 | { |
325 | static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->reparseConfiguration(); |
326 | m_imgPart->doc()->setAutoloadImages( true ); |
327 | } |
328 | |
329 | |
330 | void KHTMLImageBrowserExtension::disableScrolling() |
331 | { |
332 | static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->disableScrolling(); |
333 | } |
334 | |
335 | void KHTMLImage::( const QPoint &global, const KUrl &url, mode_t mode, |
336 | const KParts::OpenUrlArguments &origArgs, |
337 | const KParts::BrowserArguments &browserArgs, |
338 | KParts::BrowserExtension::PopupFlags flags, |
339 | const KParts::BrowserExtension::ActionGroupMap& actionGroups ) |
340 | { |
341 | KParts::OpenUrlArguments args = origArgs; |
342 | args.setMimeType(m_mimeType); |
343 | m_ext->popupMenu(global, url, mode, args, browserArgs, flags, actionGroups); |
344 | } |
345 | |
346 | #include "khtmlimage.moc" |
347 | |