plugin_part.cpp 11.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
  Netscape Plugin Loader KPart

  Copyright (c) 2000 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
                     Stefan Schimanski <1Stein@gmx.de>
  Copyright (c) 2002-2005 George Staikos <staikos@kde.org>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
Dirk Mueller's avatar
Dirk Mueller committed
20
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21
22
*/

23
#include <dcopclient.h>
24
#include <kaboutdata.h>
25
26
#include <kaction.h>
#include <kapplication.h>
27
#include <kdebug.h>
28
29
30
#include <kfiledialog.h>
#include <kio/netaccess.h>
#include <klocale.h>
George Staikos's avatar
George Staikos committed
31
#include <kparts/browserinterface.h>
32
#include <kparts/browserextension.h>
George Staikos's avatar
George Staikos committed
33

34
#include <qlabel.h>
35

36
#include "nspluginloader.h"
37
38
#include "plugin_part.h"

39

40
41
class PluginBrowserExtension : public KParts::BrowserExtension
{
42
    friend class PluginPart;
43
public:
Stephan Kulow's avatar
Stephan Kulow committed
44
45
    PluginBrowserExtension( KParts::ReadOnlyPart *parent )
        : KParts::BrowserExtension( parent ) {}
46
    ~PluginBrowserExtension() {}
George Staikos's avatar
George Staikos committed
47
48

    // ATTENTION: you -CANNOT- add data members here
49
50
51
};


52
PluginLiveConnectExtension::PluginLiveConnectExtension(PluginPart* part) 
53
: KParts::LiveConnectExtension(part), _part(part), _retval(0L) {
54
55
56
57
58
}

PluginLiveConnectExtension::~PluginLiveConnectExtension() {
}

59
bool PluginLiveConnectExtension::get(const unsigned long, const QString &field, Type &type, unsigned long &retobj, QString &value) {
60
61
62
Q_UNUSED(type);
Q_UNUSED(retobj);
Q_UNUSED(value);
Laurent Montel's avatar
Laurent Montel committed
63
    kDebug(1432) << "PLUGIN:LiveConnect::get " << field << endl;
64
65
66
67
    return false;
}

bool PluginLiveConnectExtension::call(const unsigned long, const QString &func, const QStringList &args, Type &type, unsigned long &retobjid, QString &value) {
68
69
70
Q_UNUSED(type);
Q_UNUSED(retobjid);
Q_UNUSED(value);
Laurent Montel's avatar
Laurent Montel committed
71
    kDebug(1432) << "PLUGIN:LiveConnect::call " << func << " args: " << args << endl;
72
    return false;
73
74
}

75
bool PluginLiveConnectExtension::put( const unsigned long, const QString &field, const QString &value) {
Laurent Montel's avatar
Laurent Montel committed
76
    kDebug(1432) << "PLUGIN:LiveConnect::put " << field << " " << value << endl;
77
78
    if (_retval && field == "__nsplugin") {
        *_retval = value;
79
        return true;
Tobias Koenig's avatar
Tobias Koenig committed
80
    } else if (field.toLower() == "src") {
81
82
        _part->changeSrc(value);
        return true;
83
84
85
86
87
88
    }
    return false;
}

QString PluginLiveConnectExtension::evalJavaScript( const QString & script )
{
Laurent Montel's avatar
Laurent Montel committed
89
    kDebug(1432) << "PLUGIN:LiveConnect::evalJavaScript " << script << endl;
90
91
    ArgList args;
    QString jscode;
92
    jscode.sprintf("this.__nsplugin=eval(\"%s\")", qPrintable( QString(script).replace('\\', "\\\\").replace('"', "\\\"")));
Laurent Montel's avatar
Laurent Montel committed
93
    //kDebug(1432) << "String is [" << jscode << "]" << endl;
94
    args.push_back(qMakePair(KParts::LiveConnectExtension::TypeString, jscode));
95
96
    QString nsplugin("Undefined");
    _retval = &nsplugin;
97
    emit partEvent(0, "eval", args);
98
99
    _retval = 0L;
    return nsplugin;
100
}
101

102
103
104
105
106
107
108
extern "C"
{
  /**
   * This function is the 'main' function of this part.  It takes
   * the form 'void *init_lib<library name>()  It always returns a
   * new factory object
   */
109

Dirk Mueller's avatar
Dirk Mueller committed
110
   K_EXPORT_COMPONENT_FACTORY(libnsplugin,PluginFactory)
Dirk Mueller's avatar
Dirk Mueller committed
111
}
112
113


114
115
116
NSPluginCallback::NSPluginCallback(PluginPart *part)
  : DCOPObject()
{
117
    _part = part;
118
119
120
}


121
122
123
124
125
126
void NSPluginCallback::postURL(QString url, QString target, QByteArray data, QString mime)
{
    _part->postURL( url, target, data, mime );
}


127
void NSPluginCallback::requestURL(QString url, QString target)
128
{
129
    _part->requestURL( url, target );
130
131
132
133
134
135
}


void NSPluginCallback::statusMessage( QString msg )
{
    _part->statusMessage( msg );
136
137
138
}


139
void NSPluginCallback::evalJavaScript( int id, QString script )
140
{
141
    _part->evalJavaScript( id, script );
142
}
143
144
145
146
147
/**
 * We need one static instance of the factory for our C 'main'
 * function
 */
KInstance *PluginFactory::s_instance = 0L;
148

149
150
151

PluginFactory::PluginFactory()
{
Laurent Montel's avatar
Laurent Montel committed
152
    kDebug(1432) << "PluginFactory::PluginFactory" << endl;
153
    s_instance = 0;
154

155
156
    // preload plugin loader
    _loader = NSPluginLoader::instance();
157
158
159
160
161
}


PluginFactory::~PluginFactory()
{
Laurent Montel's avatar
Laurent Montel committed
162
   kDebug(1432) << "PluginFactory::~PluginFactory" << endl;
163

164
   _loader->release();
165

166
167
168
169
170
   if ( s_instance ) {
       delete s_instance->aboutData();
       delete s_instance;
   }
   s_instance = 0;
171
172
}

Simon Hausmann's avatar
Simon Hausmann committed
173
KParts::Part * PluginFactory::createPartObject(QWidget *parentWidget, const char *widgetName,
174
                                         QObject *parent, const char *name,
175
                                         const char *classname, const QStringList &args)
176
{
177
    Q_UNUSED(classname)
Laurent Montel's avatar
Laurent Montel committed
178
    kDebug(1432) << "PluginFactory::create" << endl;
179
180
    KParts::Part *obj = new PluginPart(parentWidget, widgetName, parent, name, args);
    return obj;
181
182
183
184
185
}


KInstance *PluginFactory::instance()
{
Laurent Montel's avatar
Laurent Montel committed
186
    kDebug(1432) << "PluginFactory::instance" << endl;
187

188
189
190
    if ( !s_instance )
        s_instance = new KInstance( aboutData() );
    return s_instance;
191
192
}

Simon Hausmann's avatar
Simon Hausmann committed
193
194
KAboutData *PluginFactory::aboutData()
{
195
196
    KAboutData *about = new KAboutData("plugin", I18N_NOOP("plugin"), "1.99");
    return about;
197
}
198

Simon Hausmann's avatar
Simon Hausmann committed
199

200
/**************************************************************************/
Simon Hausmann's avatar
Simon Hausmann committed
201

202

203
PluginPart::PluginPart(QWidget *parentWidget, const char *widgetName, QObject *parent,
Tobias Koenig's avatar
Tobias Koenig committed
204
                       const char*, const QStringList &args)
Stephan Kulow's avatar
Stephan Kulow committed
205
    : KParts::ReadOnlyPart(parent), _widget(0), _args(args),
206
      _destructed(0L)
207
208
{
    setInstance(PluginFactory::instance());
Laurent Montel's avatar
Laurent Montel committed
209
    kDebug(1432) << "PluginPart::PluginPart" << endl;
210
211
212

    // we have to keep the class name of KParts::PluginBrowserExtension
    // to let khtml find it
George Staikos's avatar
George Staikos committed
213
    _extension = static_cast<PluginBrowserExtension*>(new KParts::BrowserExtension(this));
214
    _liveconnect = new PluginLiveConnectExtension(this);
215

216
217
218
    // Only create this if we have no parent since the parent part is
    // responsible for "Save As" then
    if (!parent || !parent->inherits("Part")) {
Stephan Kulow's avatar
Stephan Kulow committed
219
220
221
        KAction *action = new KAction(i18n("&Save As..."), actionCollection(), "saveDocument");
        connect(action, SIGNAL(triggered(bool) ), SLOT(saveAs()));
        action->setShortcut(Qt::CTRL+Qt::Key_S);
222
223
224
        setXMLFile("nspluginpart.rc");
    }

225
226
227
228
229
    // create
    _loader = NSPluginLoader::instance();
    _callback = new NSPluginCallback(this);

    // create a canvas to insert our widget
Stephan Kulow's avatar
Stephan Kulow committed
230
231
    _canvas = new PluginCanvasWidget( parentWidget );
    _canvas->setObjectName( widgetName );
232
    //_canvas->setFocusPolicy( QWidget::ClickFocus );
233
    _canvas->setFocusPolicy( Qt::WheelFocus );
234
    setWidget(_canvas);
235
    _canvas->show();
236
237
    QObject::connect( _canvas, SIGNAL(resized(int,int)),
                      this, SLOT(pluginResized(int,int)) );
238
239
240
241
242
}


PluginPart::~PluginPart()
{
Laurent Montel's avatar
Laurent Montel committed
243
    kDebug(1432) << "PluginPart::~PluginPart" << endl;
244

245
246
    delete _callback;
    _loader->release();
247
    if (_destructed)
248
        *_destructed = true;
249
250
251
}


Laurent Montel's avatar
Laurent Montel committed
252
bool PluginPart::openURL(const KUrl &url)
253
{
254
    closeURL();
Laurent Montel's avatar
Laurent Montel committed
255
    kDebug(1432) << "-> PluginPart::openURL" << endl;
256
257
258
259

    m_url = url;
    QString surl = url.url();
    QString smime = _extension->urlArgs().serviceType;
260
    bool reload = _extension->urlArgs().reload;
261
262
263
264
265
266
267
268
    bool embed = false;

    // handle arguments
    QStringList argn, argv;

    QStringList::Iterator it = _args.begin();
    for ( ; it != _args.end(); ) {

Tobias Koenig's avatar
Tobias Koenig committed
269
        int equalPos = (*it).indexOf("=");
270
271
        if (equalPos>0) {

Tobias Koenig's avatar
Tobias Koenig committed
272
            QString name = (*it).left(equalPos).toUpper();
273
274
275
            QString value = (*it).mid(equalPos+1);
            if (value[0] == '"' && value[value.length()-1] == '"')
                value = value.mid(1, value.length()-2);
276

Laurent Montel's avatar
Laurent Montel committed
277
            kDebug(1432) << "name=" << name << " value=" << value << endl;
278
279
280

            if (!name.isEmpty()) {
                // hack to pass view mode from khtml
281
                if ( name=="__KHTML__PLUGINEMBED" ) {
282
                    embed = true;
Laurent Montel's avatar
Laurent Montel committed
283
                    kDebug(1432) << "__KHTML__PLUGINEMBED found" << endl;
284
285
286
287
288
289
290
291
292
293
294
                } else {
                    argn << name;
                    argv << value;
                }
            }
        }

        it++;
    }

    if (surl.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
295
        kDebug(1432) << "<- PluginPart::openURL - false (no url passed to nsplugin)" << endl;
296
297
298
299
300
        return false;
    }

    // status messages
    emit setWindowCaption( url.prettyURL() );
301
    emit setStatusBarText( i18n("Loading Netscape plugin for %1", url.prettyURL()) );
302
303

    // create plugin widget
George Staikos's avatar
George Staikos committed
304
305
306
    NSPluginInstance *inst = _loader->newInstance( _canvas, surl, smime, embed,
                                                   argn, argv,
                                                   kapp->dcopClient()->appId(),
307
                                                   _callback->objId(), reload);
George Staikos's avatar
George Staikos committed
308

309
310
311
    if ( inst ) {
        _widget = inst;
    } else {
312
        QLabel *label = new QLabel( i18n("Unable to load Netscape plugin for %1", url.url()), _canvas );
Tobias Koenig's avatar
Tobias Koenig committed
313
314
        label->setAlignment( Qt::AlignCenter );
        label->setWordWrap( true );
315
316
317
        _widget = label;
    }

318
    _widget->resize(_canvas->width(), _canvas->height());
George Staikos's avatar
George Staikos committed
319
320
    _widget->show();

Laurent Montel's avatar
Laurent Montel committed
321
    kDebug(1432) << "<- PluginPart::openURL = " << (inst!=0) << endl;
322
    return inst != 0L;
323
324
325
326
327
}


bool PluginPart::closeURL()
{
Laurent Montel's avatar
Laurent Montel committed
328
    kDebug(1432) << "PluginPart::closeURL" << endl;
329
330
    delete _widget;
    _widget = 0;
331
    return true;
332
333
334
}


335
336
void PluginPart::reloadPage()
{
Laurent Montel's avatar
Laurent Montel committed
337
    kDebug(1432) << "PluginPart::reloadPage()" << endl;
338
339
340
    _extension->browserInterface()->callMethod("goHistory(int)", 0);
}

341
342
void PluginPart::postURL(const QString& url, const QString& target, const QByteArray& data, const QString& mime)
{
Laurent Montel's avatar
Laurent Montel committed
343
    kDebug(1432) << "PluginPart::postURL( url=" << url
344
345
                  << ", target=" << target << endl;

Laurent Montel's avatar
Laurent Montel committed
346
    KUrl new_url(this->url(), url);
347
348
349
350
351
352
    KParts::URLArgs args;
    args.setDoPost(true);
    args.frameName = target;
    args.postData = data;
    args.setContentType(mime);

353
    emit _extension->openURLRequest(new_url, args);
354
355
}

George Staikos's avatar
George Staikos committed
356
void PluginPart::requestURL(const QString& url, const QString& target)
357
{
Laurent Montel's avatar
Laurent Montel committed
358
    kDebug(1432) << "PluginPart::requestURL( url=" << url
359
                  << ", target=" << target << endl;
George Staikos's avatar
George Staikos committed
360

Laurent Montel's avatar
Laurent Montel committed
361
    KUrl new_url(this->url(), url);
362
363
    KParts::URLArgs args;
    args.frameName = target;
364
    args.setDoPost(false);
365

366
    emit _extension->openURLRequest(new_url, args);
367
368
}

369
void PluginPart::evalJavaScript(int id, const QString & script)
370
{
Laurent Montel's avatar
Laurent Montel committed
371
    kDebug(1432) <<"evalJavascript: before widget check"<<endl;
372
    if (_widget) {
373
374
        bool destructed = false;
        _destructed = &destructed;
Laurent Montel's avatar
Laurent Montel committed
375
	kDebug(1432) <<"evalJavascript: there is a widget" <<endl;	
376
        QString rc = _liveconnect->evalJavaScript(script);
377
378
379
        if (destructed)
            return;
        _destructed = 0L;
Laurent Montel's avatar
Laurent Montel committed
380
        kDebug(1432) << "Liveconnect: script [" << script << "] evaluated to [" << rc << "]" << endl;
381
382
383
        NSPluginInstance *ni = dynamic_cast<NSPluginInstance*>(_widget.operator->());
        if (ni)
            ni->javascriptResult(id, rc);
384
    }
385
}
386

387
void PluginPart::statusMessage(QString msg)
388
{
Laurent Montel's avatar
Laurent Montel committed
389
    kDebug(1422) << "PluginPart::statusMessage " << msg << endl;
390
    emit setStatusBarText(msg);
391
392
}

393

394
395
void PluginPart::pluginResized(int w, int h)
{
Laurent Montel's avatar
Laurent Montel committed
396
    kDebug(1432) << "PluginPart::pluginResized()" << endl;
397

398
399
400
    if (_widget) {
        _widget->resize(w, h);
    }
401
402
403
}


404
405
void PluginPart::changeSrc(const QString& url) {
    closeURL();
Laurent Montel's avatar
KURL--    
Laurent Montel committed
406
    openURL(KUrl( url ));
407
408
}

409
410

void PluginPart::saveAs() {
Laurent Montel's avatar
Laurent Montel committed
411
    KUrl savefile = KFileDialog::getSaveURL(QString(), QString(), _widget);
412
413
414
415
    KIO::NetAccess::copy(m_url, savefile, _widget);
}


416
417
void PluginCanvasWidget::resizeEvent(QResizeEvent *ev)
{
418
419
    QWidget::resizeEvent(ev);
    emit resized(width(), height());
420
}
421

422

423
#include "plugin_part.moc"