konqmainwindow.cpp 217 KB
Newer Older
1
/* This file is part of the KDE project
2
   Copyright (C) 1998, 1999 Simon Hausmann <hausmann@kde.org>
3
   Copyright (C) 2000 Carsten Pfeiffer <pfeiffer@kde.org>
4
   Copyright (C) 2000-2005 David Faure <faure@kde.org>
5 6
   Copyright (C) 2007 Eduardo Robles Elvira <edulix@gmail.com>
   Copyright (C) 2007 Daniel García Moreno <danigm@gmail.com>
7

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

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

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

24
#include "konqmainwindow.h"
25
#include "konqmouseeventfilter.h"
26
#include "konqclosedwindowsmanager.h"
27 28
#include "konqsessionmanager.h"
#include "konqsessiondlg.h"
29
#include "konqdraggablelabel.h"
30
#include "konqcloseditem.h"
31 32
#include "konqapplication.h"
#include "konqguiclients.h"
33
#include "konqmainwindowfactory.h"
34
#include "KonqMainWindowAdaptor.h"
35
#include "KonquerorAdaptor.h"
36 37 38 39 40 41 42
#include "konqview.h"
#include "konqrun.h"
#include "konqmisc.h"
#include "konqviewmanager.h"
#include "konqframestatusbar.h"
#include "konqtabs.h"
#include "konqactions.h"
Rafael Fernández López's avatar
Rafael Fernández López committed
43
#include "konqsettingsxt.h"
44
#include "konqextensionmanager.h"
45
#include "konqueror_interface.h"
46
#include "delayedinitializer.h"
47 48
#include "konqextendedbookmarkowner.h"
#include "konqframevisitor.h"
49
#include "konqbookmarkbar.h"
50
#include "konqundomanager.h"
51
#include "konqhistorydialog.h"
52
#include <config-konqueror.h>
53
#include <kstringhandler.h>
54
#include "konqurl.h"
55 56

#include <konq_events.h>
57
#include <konqpixmapprovider.h>
58
#include <kbookmarkmanager.h>
59
#include <klineedit.h>
60
#include <kzip.h>
61
#include <pwd.h>
62 63 64 65 66
// we define STRICT_ANSI to get rid of some warnings in glibc
#ifndef __STRICT_ANSI__
#define __STRICT_ANSI__
#define _WE_DEFINED_IT_
#endif
67
#include <netdb.h>
68 69 70 71
#ifdef _WE_DEFINED_IT_
#undef __STRICT_ANSI__
#undef _WE_DEFINED_IT_
#endif
72 73
#include <assert.h>
#include <stdlib.h>
Peter Kelly's avatar
compile  
Peter Kelly committed
74
#include <time.h>
75 76
#include <sys/types.h>
#include <sys/stat.h>
77
#include <KIO/ApplicationLauncherJob>
78
#include <KIO/OpenUrlJob>
79

80 81
#include <QDesktopServices>
#include <QFile>
82
#include <QClipboard>
83
#include <QStackedWidget>
84
#include <QFileInfo>
85
#if KONQ_HAVE_X11
86
#include <QX11Info>
87
#endif
88
#include <QEvent>
89
#include <QKeyEvent>
90 91
#include <QByteRef>
#include <QList>
92 93
#include <QPixmap>
#include <QLineEdit>
94
#include <QNetworkProxy>
95

96
#include <kaboutdata.h>
97
#include <ktoolbar.h>
Daniel Teske's avatar
Daniel Teske committed
98
#include <konqbookmarkmenu.h>
99
#include <kcmultidialog.h>
David Faure's avatar
David Faure committed
100
#include "konqdebug.h"
101
#include <kdesktopfile.h>
102
#include <kedittoolbar.h>
103
#include <klocalizedstring.h>
104
#include <kmessagebox.h>
105
#include <knewfilemenu.h>
106
#include <konq_popupmenu.h>
107
#include "konqsettings.h"
108
#include "konqanimatedlogo_p.h"
109
#include <kprotocolinfo.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
110
#include <kprotocolmanager.h>
Aaron J. Seigo's avatar
build  
Aaron J. Seigo committed
111
#include <kstandardshortcut.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
112
#include <kstandardaction.h>
113
#include <ksycoca.h>
114
#include <QTemporaryFile>
115
#include <ktogglefullscreenaction.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
116
#include <ktoolbarpopupaction.h>
117
#include <kurlcompletion.h>
Holger Freyther's avatar
Holger Freyther committed
118
#include <kurlrequesterdialog.h>
Alexander Neundorf's avatar
 
Alexander Neundorf committed
119
#include <kurlrequester.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
120
#include <kmimetypetrader.h>
121
#include <KJobWidgets>
Laurent Montel's avatar
Laurent Montel committed
122
#include <KLocalizedString>
Laurent Montel's avatar
Laurent Montel committed
123
#include <QIcon>
David Faure's avatar
David Faure committed
124
#include <kiconloader.h>
Laurent Montel's avatar
Laurent Montel committed
125
#include <QMenu>
Christian Ehrlicher's avatar
Christian Ehrlicher committed
126
#include <kprocess.h>
127
#include <kio/scheduler.h>
128
#include <KIO/JobUiDelegate>
129
#include <KIO/CopyJob>
130
#include <KIO/Job>
131
#include <KIO/FileUndoManager>
132
#include <kparts/browseropenorsavequestion.h>
133 134 135
#include <KParts/OpenUrlEvent>
#include <KParts/BrowserHostExtension>
#include <KCompletionMatches>
Laurent Montel's avatar
Laurent Montel committed
136
#include <kacceleratormanager.h>
137
#include <kuser.h>
138
#include <kxmlguifactory.h>
139
#include <sonnet/configdialog.h>
140 141
#include <kwindowsystem.h>
#include <netwm.h>
142

Laurent Montel's avatar
Laurent Montel committed
143
#include <kauthorized.h>
144 145
#include <QDBusConnection>
#include <QDBusMessage>
146
#include <kconfiggroup.h>
147
#include <kurlauthorized.h>
Laurent Montel's avatar
Laurent Montel committed
148
#include <QFontDatabase>
149
#include <QMenuBar>
150 151
#include <QStandardPaths>
#include <KSharedConfig>
152

153 154
#include <KProtocolManager>

155 156
template class QList<QPixmap *>;
template class QList<KToggleAction *>;
157

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
158 159 160 161
static KBookmarkManager *s_bookmarkManager = nullptr;
QList<KonqMainWindow *> *KonqMainWindow::s_lstMainWindows = nullptr;
KConfig *KonqMainWindow::s_comboConfig = nullptr;
KCompletion *KonqMainWindow::s_pCompletion = nullptr;
162

163 164
KonqOpenURLRequest KonqOpenURLRequest::null;

165
static const unsigned short int s_closedItemsListLength = 10;
166

167
static void raiseWindow(KonqMainWindow *window)
168
{
169
    if (!window) {
170
        return;
171
    }
172 173 174 175 176 177 178 179

    if (window->isMinimized()) {
        KWindowSystem::unminimizeWindow(window->winId());
    }
    window->activateWindow();
    window->raise();
}

180 181
KonqExtendedBookmarkOwner::KonqExtendedBookmarkOwner(KonqMainWindow *w)
{
182
    m_pKonqMainWindow = w;
183 184
}

185
KonqMainWindow::KonqMainWindow(const QUrl &initialURL)
186
    : KParts::MainWindow()
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
187
    , m_paClosedItems(nullptr)
188
    , m_fullyConstructed(false)
Nick Shaforostoff's avatar
Nick Shaforostoff committed
189 190 191
    , m_bLocationBarConnected(false)
    , m_bURLEnterLock(false)
    , m_urlCompletionStarted(false)
192
    , m_fullScreenData{FullScreenState::NoFullScreen, FullScreenState::NoFullScreen, true, true, false}
Nick Shaforostoff's avatar
Nick Shaforostoff committed
193
    , m_goBuffer(0)
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
194 195 196
    , m_pBookmarkMenu(nullptr)
    , m_configureDialog(nullptr)
    , m_pURLCompletion(nullptr)
197
    , m_isPopupWithProxyWindow(false)
198
{
David Faure's avatar
David Faure committed
199 200
    if (!s_lstMainWindows) {
        s_lstMainWindows = new QList<KonqMainWindow *>;
201
    }
202

David Faure's avatar
David Faure committed
203
    s_lstMainWindows->append(this);
204

205
    KonqMouseEventFilter::self(); // create it
206

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
207 208
    m_pChildFrame = nullptr;
    m_pActiveChild = nullptr;
209 210
    m_workingTab = 0;
    (void) new KonqMainWindowAdaptor(this);
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
211
    m_paBookmarkBar = nullptr;
212

213 214 215 216 217
    m_viewModesGroup = new QActionGroup(this);
    m_viewModesGroup->setExclusive(true);
    connect(m_viewModesGroup, SIGNAL(triggered(QAction*)),
            this, SLOT(slotViewModeTriggered(QAction*)),
            Qt::QueuedConnection); // Queued so that we don't delete the action from the code that triggered it.
218

219
    // This has to be called before any action is created for this mainwindow
220
    setComponentData(KAboutData::applicationData(), false /*don't load plugins yet*/);
221

222
    m_pViewManager = new KonqViewManager(this);
Simon Hausmann's avatar
Simon Hausmann committed
223

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
224 225 226 227
    m_viewModeMenu = nullptr;
    m_openWithMenu = nullptr;
    m_paCopyFiles = nullptr;
    m_paMoveFiles = nullptr;
228
    m_bookmarkBarInitialized = false;
229

230
    m_toggleViewGUIClient = new ToggleViewGUIClient(this);
231

232
    m_pBookmarksOwner = new KonqExtendedBookmarkOwner(this);
233

234 235 236
    // init history-manager, load history, get completion object
    if (!s_pCompletion) {
        s_bookmarkManager = KBookmarkManager::userBookmarksManager();
237

238
        // let the KBookmarkManager know that we are a browser, equals to "keditbookmarks --browser"
239
        s_bookmarkManager->setEditorOptions(QStringLiteral("konqueror"), true);
240

241 242
        KonqHistoryManager *mgr = new KonqHistoryManager(s_bookmarkManager);
        s_pCompletion = mgr->completionObject();
243

244 245 246 247 248 249
        // setup the completion object before createGUI(), so that the combo
        // picks up the correct mode from the HistoryManager (in slotComboPlugged)
        int mode = KonqSettings::settingsCompletionMode();
        s_pCompletion->setCompletionMode(static_cast<KCompletion::CompletionMode>(mode));
    }
    connect(KParts::HistoryProvider::self(), &KParts::HistoryProvider::cleared, this, &KonqMainWindow::slotClearComboHistory);
250

251 252
    KonqPixmapProvider *prov = KonqPixmapProvider::self();
    if (!s_comboConfig) {
253
        s_comboConfig = new KConfig(QStringLiteral("konq_history"), KConfig::NoGlobals);
254 255
        KonqCombo::setConfig(s_comboConfig);
        KConfigGroup locationBarGroup(s_comboConfig, "Location Bar");
256
        prov->load(locationBarGroup, QStringLiteral("ComboIconCache"));
257
    }
258

259
    connect(prov, SIGNAL(changed()), SLOT(slotIconsChanged()));
260

261
    m_pUndoManager = new KonqUndoManager(KonqClosedWindowsManager::self(), this);
262 263
    connect(m_pUndoManager, SIGNAL(undoAvailable(bool)),
            this, SLOT(slotUndoAvailable(bool)));
264

265 266
    initCombo();
    initActions();
267

268
    setXMLFile(QStringLiteral("konqueror.rc"));
269

270
    setStandardToolBarMenuEnabled(true);
271

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
272
    createGUI(nullptr);
David Faure's avatar
David Faure committed
273

274
    m_combo->setParent(toolBar(QStringLiteral("locationToolBar")));
275
    m_combo->show();
276

277
    checkDisableClearButton();
David Faure's avatar
David Faure committed
278

279
    connect(toolBarMenuAction(), SIGNAL(triggered()), this, SLOT(slotForceSaveMainWindowSettings()));
David Faure's avatar
David Faure committed
280

281
    if (!m_toggleViewGUIClient->empty()) {
282
        plugActionList(QStringLiteral("toggleview"), m_toggleViewGUIClient->actions());
283 284
    } else {
        delete m_toggleViewGUIClient;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
285
        m_toggleViewGUIClient = nullptr;
286
    }
287

288
    m_bNeedApplyKonqMainWindowSettings = true;
289

290 291 292 293 294 295
    if (!initialURL.isEmpty()) {
        openFilteredUrl(initialURL.url());
    } else {
        // silent
        m_bNeedApplyKonqMainWindowSettings = false;
    }
296

297
    resize(700, 480);
298 299 300 301

    updateProxyForWebEngine(false);
    QDBusConnection::sessionBus().connect("", QStringLiteral("/KIO/Scheduler"), QStringLiteral("org.kde.KIO.Scheduler"),
                                          QStringLiteral("reparseSlaveConfiguration"), this, SLOT(updateProxyForWebEngine()));
Albert Astals Cid's avatar
Albert Astals Cid committed
302
    setAutoSaveSettings();
303

David Faure's avatar
David Faure committed
304
    //qCDebug(KONQUEROR_LOG) << this << "created";
Laurent Montel's avatar
Laurent Montel committed
305

306 307
    KonqSessionManager::self();
    m_fullyConstructed = true;
308
}
Matthias Welk's avatar
Matthias Welk committed
309

310
KonqMainWindow::~KonqMainWindow()
311
{
David Faure's avatar
David Faure committed
312
    //qCDebug(KONQUEROR_LOG) << this;
Doug Hanley's avatar
 
Doug Hanley committed
313

314
    delete m_pViewManager;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
315
    m_pViewManager = nullptr;
Doug Hanley's avatar
 
Doug Hanley committed
316

David Faure's avatar
David Faure committed
317 318 319 320
    if (s_lstMainWindows) {
        s_lstMainWindows->removeAll(this);
        if (s_lstMainWindows->isEmpty()) {
            delete s_lstMainWindows;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
321
            s_lstMainWindows = nullptr;
322
        }
Simon Hausmann's avatar
Simon Hausmann committed
323
    }
324

325 326
    qDeleteAll(m_openWithActions);
    m_openWithActions.clear();
327

328 329 330 331 332 333
    delete m_pBookmarkMenu;
    delete m_paBookmarkBar;
    delete m_pBookmarksOwner;
    delete m_pURLCompletion;
    delete m_paClosedItems;

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
334
    if (s_lstMainWindows == nullptr) {
335
        delete s_comboConfig;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
336
        s_comboConfig = nullptr;
337 338 339
    }

    delete m_configureDialog;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
340
    m_configureDialog = nullptr;
341
    delete m_combo;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
342
    m_combo = nullptr;
343
    delete m_locationLabel;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
344
    m_locationLabel = nullptr;
345 346
    m_pUndoManager->disconnect();
    delete m_pUndoManager;
347

David Faure's avatar
David Faure committed
348
    //qCDebug(KONQUEROR_LOG) << this << "deleted";
349 350
}

351
QWidget *KonqMainWindow::createContainer(QWidget *parent, int index, const QDomElement &element, QAction *&containerAction)
352
{
353
    QWidget *res = KParts::MainWindow::createContainer(parent, index, element, containerAction);
354

355 356 357
    static QString nameBookmarkBar = QStringLiteral("bookmarkToolBar");
    static QString tagToolBar = QStringLiteral("ToolBar");
    if (res && (element.tagName() == tagToolBar) && (element.attribute(QStringLiteral("name")) == nameBookmarkBar)) {
358
        Q_ASSERT(::qobject_cast<KToolBar *>(res));
359
        if (!KAuthorized::authorizeAction(QStringLiteral("bookmarks"))) {
360
            delete res;
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
361
            return nullptr;
362
        }
363

364 365 366 367 368 369 370
        if (!m_bookmarkBarInitialized) {
            // The actual menu needs a different action collection, so that the bookmarks
            // don't appear in kedittoolbar
            m_bookmarkBarInitialized = true;
            DelayedInitializer *initializer = new DelayedInitializer(QEvent::Show, res);
            connect(initializer, &DelayedInitializer::initialize, this, &KonqMainWindow::initBookmarkBar);
        }
371
    }
372

373
    if (res && element.tagName() == QLatin1String("Menu")) {
374 375
        const QString &menuName = element.attribute(QStringLiteral("name"));
        if (menuName == QLatin1String("edit") || menuName == QLatin1String("tools")) {
376 377 378 379
            Q_ASSERT(qobject_cast<QMenu *>(res));
            KAcceleratorManager::manage(static_cast<QMenu *>(res));
        }
    }
380

381
    return res;
382
}
383

Maks Orlovich's avatar
 
Maks Orlovich committed
384 385
void KonqMainWindow::initBookmarkBar()
{
David Faure's avatar
David Faure committed
386
    KToolBar *bar = this->findChild<KToolBar *>(QStringLiteral("bookmarkToolBar"));
387

388 389 390
    if (!bar) {
        return;
    }
391

392
    const bool wasVisible = bar->isVisible();
393

394 395
    delete m_paBookmarkBar;
    m_paBookmarkBar = new KBookmarkBar(s_bookmarkManager, m_pBookmarksOwner, bar, this);
Maks Orlovich's avatar
 
Maks Orlovich committed
396

397 398 399 400
    // hide if empty
    if (bar->actions().count() == 0 || !wasVisible) {
        bar->hide();
    }
Maks Orlovich's avatar
 
Maks Orlovich committed
401 402
}

403
void KonqMainWindow::removeContainer(QWidget *container, QWidget *parent, QDomElement &element, QAction *containerAction)
404
{
405 406
    static QString nameBookmarkBar = QStringLiteral("bookmarkToolBar");
    static QString tagToolBar = QStringLiteral("ToolBar");
407

408
    if (element.tagName() == tagToolBar && element.attribute(QStringLiteral("name")) == nameBookmarkBar) {
409 410 411 412 413
        Q_ASSERT(::qobject_cast<KToolBar *>(container));
        if (m_paBookmarkBar) {
            m_paBookmarkBar->clear();
        }
    }
414

415
    KParts::MainWindow::removeContainer(container, parent, element, containerAction);
416 417
}

418 419 420
// Detect a name filter (e.g. *.txt) in the url.
// Note that KShortURIFilter does the same, but we have no way of getting it from there
//
421
// Note: this removes the filter from the URL.
422
QString KonqMainWindow::detectNameFilter(QUrl &url)
423
{
424
    if (!KProtocolManager::supportsListing(url)) {
Laurent Montel's avatar
Laurent Montel committed
425
        return QString();
426
    }
427

428 429
    // Look for wildcard selection
    QString nameFilter;
430
    QString path = url.path();
431 432 433
    int lastSlash = path.lastIndexOf('/');
    if (lastSlash > -1) {
        if (!url.query().isEmpty() && lastSlash == path.length() - 1) {  //  In /tmp/?foo, foo isn't a query
434 435
            path += url.query(); // includes the '?'
        }
436 437
        QString fileName = path.mid(lastSlash + 1);
        if (fileName.indexOf('*') != -1 || fileName.indexOf('[') != -1 || fileName.indexOf('?') != -1) {
438
            // Check that a file or dir with all the special chars in the filename doesn't exist
439 440 441 442 443
            if (url.isLocalFile()) {
                if (!QFile(url.toLocalFile()).exists()) {
                    nameFilter = fileName;
                }
            } else { // not a local file
444
                KIO::StatJob *job = KIO::statDetails(url, KIO::StatJob::DestinationSide, KIO::StatBasic, KIO::HideProgressInfo);
445 446 447 448 449
                // if there's an error stat'ing url, then assume it doesn't exist
                nameFilter = !job->exec() ? fileName : QString();
            }

            if (!nameFilter.isEmpty()) {
450
                url = url.adjusted(QUrl::RemoveFilename | QUrl::RemoveQuery);
David Faure's avatar
David Faure committed
451
                qCDebug(KONQUEROR_LOG) << "Found wildcard. nameFilter=" << nameFilter << "  New url=" << url;
452
            }
453
        }
454
    }
455

456 457 458
    return nameFilter;
}

459
void KonqMainWindow::openFilteredUrl(const QString &url, const KonqOpenURLRequest &req)
460
{
461
    // Filter URL to build a correct one
462 463 464
    if (m_currentDir.isEmpty() && m_currentView) {
        m_currentDir = m_currentView->url();
    }
465

466
    QUrl filteredURL(KonqMisc::konqFilteredURL(this, url, m_currentDir));
David Faure's avatar
David Faure committed
467
    qCDebug(KONQUEROR_LOG) << "url" << url << "filtered into" << filteredURL;
468

469
    if (filteredURL.isEmpty()) { // initially empty, or error (e.g. ~unknown_user)
470
        return;
471
    }
472

Laurent Montel's avatar
Laurent Montel committed
473
    m_currentDir.clear();
474

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
475
    openUrl(nullptr, filteredURL, QString(), req);
476 477 478

    // #4070: Give focus to view after URL was entered manually
    // Note: we do it here if the view mode (i.e. part) wasn't changed
479
    // If it is changed, then it's done in KonqViewManager::doSetActivePart
480
    if (m_currentView) {
481
        m_currentView->setFocus();
482
    }
483 484
}

485
void KonqMainWindow::openFilteredUrl(const QString &_url, bool inNewTab, bool tempFile)
486
{
487
    KonqOpenURLRequest req(_url);
488
    req.browserArgs.setNewTab(inNewTab);
489 490
    req.newTabInFront = true;
    req.tempFile = tempFile;
491

492
    openFilteredUrl(_url, req);
493 494
}

495
void KonqMainWindow::openFilteredUrl(const QString &_url,  const QString &_mimeType, bool inNewTab, bool tempFile)
496
{
497
    KonqOpenURLRequest req(_url);
498 499 500 501 502
    req.browserArgs.setNewTab(inNewTab);
    req.newTabInFront = true;
    req.tempFile = tempFile;
    req.args.setMimeType(_mimeType);

503
    openFilteredUrl(_url, req);
504 505
}

506
void KonqMainWindow::openUrl(KonqView *_view, const QUrl &_url,
507
                             const QString &_mimeType, const KonqOpenURLRequest &_req,
David Faure's avatar
David Faure committed
508
                             bool trustedSource)
509
{
510
#ifndef NDEBUG // needed for req.debug()
David Faure's avatar
David Faure committed
511
    qCDebug(KONQUEROR_LOG) << "url=" << _url << "mimeType=" << _mimeType
512
             << "_req=" << _req.debug() << "view=" << _view;
513
#endif
David Faure's avatar
David Faure committed
514
    // We like modifying args in this method :)
515
    QUrl url(_url);
David Faure's avatar
David Faure committed
516 517 518
    QString mimeType(_mimeType);
    KonqOpenURLRequest req(_req);

519
    if (mimeType.isEmpty()) {
520
        mimeType = req.args.mimeType();
521
    }
David Faure's avatar
David Faure committed
522 523 524 525 526 527
    if (!url.isValid()) {
        // I think we can't really get here anymore; I tried and didn't succeed.
        // URL filtering catches this case before hand, and in cases without filtering
        // (e.g. HTML link), the url is empty here, not invalid.
        // But just to be safe, let's keep this code path
        url = KParts::BrowserRun::makeErrorUrl(KIO::ERR_MALFORMED_URL, url.url(), url);
528
    } else if (!KProtocolInfo::isKnownProtocol(url) && url.scheme() != QLatin1String("error") && !KonqUrl::hasKonqScheme(url) && url.scheme() != QLatin1String("mailto")) {
David Faure's avatar
David Faure committed
529
        url = KParts::BrowserRun::makeErrorUrl(KIO::ERR_UNSUPPORTED_PROTOCOL, url.scheme(), url);
530
    }
531

532
    if (KonqUrl::isKonqBlank(url) || url.scheme() == QLatin1String("error")) {
533
        mimeType = QStringLiteral("text/html");
534
    }
535

536 537
    const QString nameFilter = detectNameFilter(url);
    if (!nameFilter.isEmpty()) {
538 539
        req.nameFilter = nameFilter;
        url = url.adjusted(QUrl::RemoveFilename);
540
    }
541

542
    QLineEdit *edit = comboEdit();
543
    if (edit) {
544
        edit->setModified(false);
545
    }
546

547
    KonqView *view = _view;
548

549 550
    // When clicking a 'follow active' view (e.g. view is the sidebar),
    // open the URL in the active view
551
    if (view && view->isFollowActive()) {
552
        view = m_currentView;
553
    }
554

555 556 557
    if (!view && !req.browserArgs.newTab()) {
        view = m_currentView;    /* Note, this can be 0, e.g. on startup */
    } else if (!view && req.browserArgs.newTab()) {
558

559 560 561 562 563
        // The URL should be opened in a new tab. Let's create the tab right away,
        // it gives faster user feedback (#163628). For a short while (kde-4.1-beta1)
        // I removed this entire block so that we wouldn't end up with a useless tab when
        // launching an external application for this mimetype. But user feedback
        // in all cases is more important than empty tabs in some cases.
564
        view = m_pViewManager->addTab(QStringLiteral("text/html"),
565
                                      QString(),
566 567 568
                                      false,
                                      req.openAfterCurrentPage);
        if (view) {
569
            view->setCaption(i18nc("@title:tab", "Loading..."));
570
            view->setLocationBarURL(_url);
571 572 573
            if (!req.browserArgs.frameName.isEmpty()) {
                view->setViewName(req.browserArgs.frameName);    // #44961
            }
574

575
            if (req.newTabInFront) {
576
                m_pViewManager->showTab(view);
577
            }
578 579 580

            updateViewActions(); //A new tab created -- we may need to enable the "remove tab" button (#56318)
        } else {
581
            req.browserArgs.setNewTab(false);
582 583
        }
    }
584

585 586 587 588 589 590 591 592 593
    const QString oldLocationBarURL = locationBarURL();
    if (view) {
        if (view == m_currentView) {
            //will do all the stuff below plus GUI stuff
            abortLoading();
        } else {
            view->stop();
            // Don't change location bar if not current view
        }
594
    }
595

596
    // Fast mode for local files: do the stat ourselves instead of letting OpenUrlJob do it.
597
    if (mimeType.isEmpty() && url.isLocalFile()) {
598 599
        QMimeDatabase db;
        mimeType = db.mimeTypeForFile(url.toLocalFile()).name();
600
    }
601

602 603 604 605 606 607 608 609 610 611
    if (url.isLocalFile()) {
        // Generic mechanism for redirecting to tar:/<path>/ when clicking on a tar file,
        // zip:/<path>/ when clicking on a zip file, etc.
        // The .protocol file specifies the mimetype that the kioslave handles.
        // Note that we don't use mimetype inheritance since we don't want to
        // open OpenDocument files as zip folders...
        // Also note that we do this here and not in openView anymore,
        // because in the case of foo.bz2 we don't know the final mimetype, we need a konqrun...
        const QString protocol = KProtocolManager::protocolForArchiveMimetype(mimeType);
        if (!protocol.isEmpty() && KonqFMSettings::settings()->shouldEmbed(mimeType)) {
612
            url.setScheme(protocol);
613
            if (mimeType == QLatin1String("application/x-webarchive")) {
614
                url.setPath(url.path() + "/index.html");
615
                mimeType = QStringLiteral("text/html");
616 617
            } else {
                if (KProtocolManager::outputType(url) == KProtocolInfo::T_FILESYSTEM) {
618
                    if (!url.path().endsWith('/')) {
619
                        url.setPath(url.path() + '/');
620
                    }
621
                    mimeType = QStringLiteral("inode/directory");
622
                } else {
623
                    mimeType.clear();
624
                }
625 626
            }
        }
627 628

        // Redirect to the url in Type=Link desktop files
629
        if (mimeType == QLatin1String("application/x-desktop")) {
630 631
            KDesktopFile df(url.toLocalFile());
            if (df.hasLinkType()) {
632
                url = QUrl(df.readUrl());
633 634 635
                mimeType.clear(); // to be determined again
            }
        }
636 637
    }

638
    const bool hasMimeType = (!mimeType.isEmpty() && mimeType != QLatin1String("application/octet-stream"));
David Faure's avatar
David Faure committed
639 640 641
    KService::Ptr offer;
    bool associatedAppIsKonqueror = false;
    if (hasMimeType) {
642
        offer = KMimeTypeTrader::self()->preferredService(mimeType, QStringLiteral("Application"));
David Faure's avatar
David Faure committed
643
        associatedAppIsKonqueror = isMimeTypeAssociatedWithSelf(mimeType, offer);
644 645 646 647
        // If the associated app is konqueror itself, then make sure we try to embed before bailing out.
        if (associatedAppIsKonqueror) {
            req.forceAutoEmbed = true;
        }