konq_mainwindow.cc 201 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
7
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
8
9
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
10

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

16
17
   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
18
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Dirk Mueller's avatar
Dirk Mueller committed
19
   Boston, MA 02110-1301, USA.
20
*/
21

22
#include "konq_mainwindow.h"
23
#include "konq_guiclients.h"
24
#include "KonqMainWindowIface.h"
David Faure's avatar
David Faure committed
25
#include "konq_view.h"
26
#include "konq_run.h"
27
#include "konq_misc.h"
28
#include "konq_viewmgr.h"
29
#include "konq_frame.h"
30
#include "konq_tabs.h"
31
32
#include "konq_events.h"
#include "konq_actions.h"
33
#include "konq_settingsxt.h"
34
#include "konq_extensionmanager.h"
35
#include "delayedinitializer.h"
36
#include <konq_pixmapprovider.h>
Alexander Neundorf's avatar
   
Alexander Neundorf committed
37
#include <konq_operations.h>
Carsten Pfeiffer's avatar
Carsten Pfeiffer committed
38
#include <konqbookmarkmanager.h>
Nadeem Hasan's avatar
Nadeem Hasan committed
39
#include <kinputdialog.h>
40
#include <kzip.h>
41
#include <config.h>
42
#include <pwd.h>
43
44
45
46
47
// we define STRICT_ANSI to get rid of some warnings in glibc
#ifndef __STRICT_ANSI__
#define __STRICT_ANSI__
#define _WE_DEFINED_IT_
#endif
48
#include <netdb.h>
49
50
51
52
#ifdef _WE_DEFINED_IT_
#undef __STRICT_ANSI__
#undef _WE_DEFINED_IT_
#endif
53
54
#include <assert.h>
#include <stdlib.h>
Peter Kelly's avatar
compile    
Peter Kelly committed
55
#include <time.h>
Laurent Montel's avatar
Laurent Montel committed
56
#include <kde_file.h>
57
58
#include <sys/types.h>
#include <sys/stat.h>
Luboš Luňák's avatar
Luboš Luňák committed
59
#include <time.h>
60
#include <unistd.h>
61

Alexander Kellett's avatar
Alexander Kellett committed
62
#include <qfile.h>
63
#include <qclipboard.h>
64
#include <qmetaobject.h>
65
#include <qlayout.h>
66
#include <qfileinfo.h>
67
#ifdef Q_WS_X11
68
#include <QX11Info>
69
#endif
70
71
72
73
74
//Added by qt3to4:
#include <QCustomEvent>
#include <QFocusEvent>
#include <QKeyEvent>
#include <QEvent>
Pascal Létourneau's avatar
Porting    
Pascal Létourneau committed
75
#include <QByteArray>
Pascal Létourneau's avatar
Pascal Létourneau committed
76
#include <QList>
77
78
#include <QCloseEvent>
#include <QPixmap>
79

80
#include <dcopclient.h>
81
#include <kaboutdata.h>
82
#include <kbookmarkbar.h>
83
#include <ktoolbar.h>
84
#include <kbookmarkmenu.h>
85
#include <kcmultidialog.h>
86
#include <kdebug.h>
87
88
89
#include <kedittoolbar.h>
#include <kkeydialog.h>
#include <kmenubar.h>
90
91
#include <kmessagebox.h>
#include <knewmenu.h>
92
#include <konq_defaults.h>
93
#include <konq_dirpart.h>
94
95
#include <konq_popupmenu.h>
#include <konq_settings.h>
Laurent Montel's avatar
Laurent Montel committed
96
#include "konq_main.h"
Simon Hausmann's avatar
- undo    
Simon Hausmann committed
97
#include <konq_undo.h>
98
#include <kprotocolinfo.h>
99
#include <kstdaccel.h>
100
#include <kstdaction.h>
David Faure's avatar
David Faure committed
101
#include <kstandarddirs.h>
102
#include <ksycoca.h>
103
#include <ktempfile.h>
Wilco Greven's avatar
Wilco Greven committed
104
#include <kurlrequesterdlg.h>
Alexander Neundorf's avatar
   
Alexander Neundorf committed
105
#include <kurlrequester.h>
106
#include <kuserprofile.h>
107
#include <kwin.h>
Alexander Neundorf's avatar
   
Alexander Neundorf committed
108
#include <kfiledialog.h>
David Faure's avatar
David Faure committed
109
110
#include <klocale.h>
#include <kiconloader.h>
Laurent Montel's avatar
Laurent Montel committed
111
#include <kmenu.h>
112
#include <kprocess.h>
113
#include <kio/scheduler.h>
114
#include <kio/netaccess.h>
Laurent Montel's avatar
Laurent Montel committed
115
#include <kacceleratormanager.h>
116
#include <kuser.h>
117
#include <netwm.h>
118

119
120
121
122
123
124
125
#ifdef KDE_MALLINFO_STDLIB
#include <stdlib.h>
#endif
#ifdef KDE_MALLINFO_MALLOC
#include <malloc.h>
#endif

126
#include <sys/time.h>
127
128
#ifdef Q_WS_X11
#include <X11/Xlib.h>
129
#include <X11/Xatom.h>
130
#include <fixx11h.h>
131
#endif
Laurent Montel's avatar
Laurent Montel committed
132
#include <kauthorized.h>
133
#include <ktoolinvocation.h>
134

Pascal Létourneau's avatar
Pascal Létourneau committed
135
136
template class QList<QPixmap*>;
template class QList<KToggleAction*>;
137

Pascal Létourneau's avatar
Pascal Létourneau committed
138
QList<KonqMainWindow*> *KonqMainWindow::s_lstViews = 0;
139
KConfig * KonqMainWindow::s_comboConfig = 0;
140
KCompletion * KonqMainWindow::s_pCompletion = 0;
Alexander Kellett's avatar
Alexander Kellett committed
141
QFile * KonqMainWindow::s_crashlog_file = 0;
142
143
bool KonqMainWindow::s_preloaded = false;
KonqMainWindow* KonqMainWindow::s_preloadedWindow = 0;
144
145
146
147
int KonqMainWindow::s_initialMemoryUsage = -1;
time_t KonqMainWindow::s_startupTime;
int KonqMainWindow::s_preloadUsageCount;

148
149
KonqOpenURLRequest KonqOpenURLRequest::null;

150
static int current_memory_usage( int* limit = NULL );
151

152
153
154
155
156
157
158
#include "konq_mainwindow_p.h"

KonqExtendedBookmarkOwner::KonqExtendedBookmarkOwner(KonqMainWindow *w)
{
   m_pKonqMainWindow = w;
}

Laurent Montel's avatar
Laurent Montel committed
159
KonqMainWindow::KonqMainWindow( const KUrl &initialURL, bool openInitialURL, const char *name, const QString& xmluiFile)
160
 : KParts::MainWindow( NoDCOPObject, 0L, name, Qt::WDestructiveClose | Qt::WStyle_ContextHelp )
161
{
162
  setPreloadedFlag( false );
163

Simon Hausmann's avatar
Simon Hausmann committed
164
  if ( !s_lstViews )
Pascal Létourneau's avatar
Pascal Létourneau committed
165
    s_lstViews = new QList<KonqMainWindow*>;
166

Simon Hausmann's avatar
Simon Hausmann committed
167
  s_lstViews->append( this );
168

169
170
  m_urlCompletionStarted = false;

171
  m_currentView = 0L;
Doug Hanley's avatar
   
Doug Hanley committed
172
  m_pChildFrame = 0L;
Doug Hanley's avatar
   
Doug Hanley committed
173
  m_pActiveChild = 0L;
Doug Hanley's avatar
   
Doug Hanley committed
174
  m_pWorkingTab = 0L;
175
  m_initialKonqRun = 0L;
176
  m_pBookmarkMenu = 0L;
177
  m_dcopObject = new KonqMainWindowIface( this );
178
  m_combo = 0L;
179
  m_bURLEnterLock = false;
180
  m_bLocationBarConnected = false;
181
  m_paBookmarkBar = 0L;
182
  m_pURLCompletion = 0L;
183
  m_goBuffer = 0;
184
  m_configureDialog = 0L;
185

186
  m_bViewModeToggled = false;
187

188
189
190
191
192
  m_viewModesGroup = new QActionGroup(this);
  m_viewModesGroup->setExclusive(true);
  m_toolBarViewModesGroup = new QActionGroup(this);
  m_toolBarViewModesGroup->setExclusive(true);

Doug Hanley's avatar
   
Doug Hanley committed
193
  m_pViewManager = new KonqViewManager( this );
Simon Hausmann's avatar
Simon Hausmann committed
194

195
  m_toggleViewGUIClient = new ToggleViewGUIClient( this );
David Faure's avatar
David Faure committed
196

Laurent Montel's avatar
Laurent Montel committed
197
198
  //m_openWithActions.setAutoDelete( true );
  //m_toolBarViewModeActions.setAutoDelete( true );
199
  m_viewModeMenu = 0;
200
201
  m_paCopyFiles = 0;
  m_paMoveFiles = 0;
202
  m_paDelete = 0;
203
  m_paNewDir = 0;
204
  m_bookmarkBarActionCollection = 0L;
205
206
  KonqExtendedBookmarkOwner *extOwner = new KonqExtendedBookmarkOwner( this );
  m_pBookmarksOwner = extOwner;
207
  connect( extOwner,
208
209
210
           SIGNAL( signalFillBookmarksList(KExtendedBookmarkOwner::QStringPairList &) ),
           extOwner,
           SLOT( slotFillBookmarksList(KExtendedBookmarkOwner::QStringPairList &) ) );
211

212
213
  // init history-manager, load history, get completion object
  if ( !s_pCompletion ) {
214
215
    KonqHistoryManager *mgr = new KonqHistoryManager( kapp, "history mgr" );
    s_pCompletion = mgr->completionObject();
216

217

218
219
    // setup the completion object before createGUI(), so that the combo
    // picks up the correct mode from the HistoryManager (in slotComboPlugged)
220
    int mode = KonqSettings::settingsCompletionMode();
221
222
    s_pCompletion->setCompletionMode( (KGlobalSettings::Completion) mode );
  }
223
224
  connect(KParts::HistoryProvider::self(), SIGNAL(cleared()), SLOT(slotClearComboHistory()));

225
226
227
228
  KonqPixmapProvider *prov = KonqPixmapProvider::self();
  if ( !s_comboConfig ) {
      s_comboConfig = new KConfig( "konq_history", false, false );
      KonqCombo::setConfig( s_comboConfig );
229
230
      KConfigGroup locationBarGroup( s_comboConfig, "Location Bar" );
      prov->load( locationBarGroup, "ComboIconCache" );
231
232
  }
  connect( prov, SIGNAL( changed() ), SLOT( slotIconsChanged() ) );
233

234
  initCombo();
235
236
237
238
239
240
241
242
243
  initActions();

  setInstance( KGlobal::instance() );

  connect( KSycoca::self(), SIGNAL( databaseChanged() ),
           this, SLOT( slotDatabaseChanged() ) );

  connect( kapp, SIGNAL( kdisplayFontChanged()), SLOT(slotReconfigure()));

244
245
  //load the xmlui file specified in the profile or the default konqueror.rc
  setXMLFile( xmluiFile );
246

247
248
  setStandardToolBarMenuEnabled( true );

249
250
  createGUI( 0L );

David Faure's avatar
David Faure committed
251
252
  connect(toolBarMenuAction(),SIGNAL(activated()),this,SLOT(slotForceSaveMainWindowSettings()) );

253
  if ( !m_toggleViewGUIClient->empty() )
Laurent Montel's avatar
Laurent Montel committed
254
    plugActionList( QLatin1String( "toggleview" ), m_toggleViewGUIClient->actions() );
255
256
257
258
259
  else
  {
    delete m_toggleViewGUIClient;
    m_toggleViewGUIClient = 0;
  }
260

261
  // Those menus are created by konqueror.rc so their address will never change
262
  QMenu *popup = static_cast<QMenu*>(factory()->container("edit",this));
263
264
  if (popup)
    KAcceleratorManager::manage(popup);
265
  popup = static_cast<QMenu*>(factory()->container("tools",this));
266
267
268
  if (popup)
    KAcceleratorManager::manage(popup);

269
270
  m_bSaveViewPropertiesLocally = KonqSettings::saveViewPropertiesLocally();
  m_bHTMLAllowed = KonqSettings::htmlAllowed();
271

272
  m_ptaUseHTML->setChecked( m_bHTMLAllowed );
273
  m_paSaveViewPropertiesLocally->setChecked( m_bSaveViewPropertiesLocally );
274

275
276
277
278
  KonqUndoManager::incRef();

  connect( KonqUndoManager::self(), SIGNAL( undoAvailable( bool ) ),
           this, SLOT( slotUndoAvailable( bool ) ) );
279
  m_bNeedApplyKonqMainWindowSettings = true;
280

Simon Hausmann's avatar
Simon Hausmann committed
281
  if ( !initialURL.isEmpty() )
282
  {
283
    openFilteredUrl( initialURL.url() );
284
  }
Simon Hausmann's avatar
Simon Hausmann committed
285
286
  else if ( openInitialURL )
  {
Laurent Montel's avatar
Laurent Montel committed
287
    KUrl homeURL;
Laurent Montel's avatar
Laurent Montel committed
288
    homeURL.setPath( QDir::homePath() );
289
    openURL( 0L, homeURL );
Simon Hausmann's avatar
Simon Hausmann committed
290
  }
291
292
  else
      // silent
293
      m_bNeedApplyKonqMainWindowSettings = false;
294

295
  // Read basic main-view settings, and set to autosave
296
  setAutoSaveSettings( "KonqMainWindow", false );
297

298
299
  if ( !initialGeometrySet() )
      resize( 700, 480 );
Laurent Montel's avatar
Laurent Montel committed
300
  //kDebug(1202) << "KonqMainWindow::KonqMainWindow " << this << " done" << endl;
Laurent Montel's avatar
Laurent Montel committed
301

302
303
304
305
306
307
  if( s_initialMemoryUsage == -1 )
  {
      s_initialMemoryUsage = current_memory_usage();
      s_startupTime = time( NULL );
      s_preloadUsageCount = 0;
  }
308
}
Matthias Welk's avatar
Matthias Welk committed
309

310
KonqMainWindow::~KonqMainWindow()
311
{
Laurent Montel's avatar
Laurent Montel committed
312
  kDebug(1202) << "KonqMainWindow::~KonqMainWindow " << this << endl;
Doug Hanley's avatar
   
Doug Hanley committed
313
314
315

  delete m_pViewManager;

Simon Hausmann's avatar
Simon Hausmann committed
316
317
  if ( s_lstViews )
  {
Pascal Létourneau's avatar
Pascal Létourneau committed
318
    s_lstViews->removeAll( this );
Simon Hausmann's avatar
Simon Hausmann committed
319
320
321
322
323
324
    if ( s_lstViews->count() == 0 )
    {
      delete s_lstViews;
      s_lstViews = 0;
    }
  }
325

326
327
  saveToolBarServicesMap();

328
  //  createShellGUI( false );
329

330
  delete m_pBookmarkMenu;
331
  delete m_paBookmarkBar;
332
  delete m_pURLCompletion;
333

Simon Hausmann's avatar
- undo    
Simon Hausmann committed
334
335
  KonqUndoManager::decRef();

336
  if ( s_lstViews == 0 ) {
337
      delete KonqPixmapProvider::self();
338
339
340
      delete s_comboConfig;
      s_comboConfig = 0L;
  }
341

342
343
  delete m_configureDialog;
  m_configureDialog = 0L;
George Staikos's avatar
George Staikos committed
344
345
  delete m_dcopObject;
  m_dcopObject = 0L;
George Staikos's avatar
George Staikos committed
346
347
  delete m_combo;
  m_combo = 0L;
348
349
  delete m_locationLabel;
  m_locationLabel = 0L;
George Staikos's avatar
George Staikos committed
350

Laurent Montel's avatar
Laurent Montel committed
351
  kDebug(1202) << "KonqMainWindow::~KonqMainWindow " << this << " done" << endl;
352
353
}

Simon Hausmann's avatar
Simon Hausmann committed
354
QWidget * KonqMainWindow::createContainer( QWidget *parent, int index, const QDomElement &element, int &id )
355
{
Laurent Montel's avatar
Laurent Montel committed
356
357
  static QString nameBookmarkBar = QLatin1String( "bookmarkToolBar" );
  static QString tagToolBar = QLatin1String( "ToolBar" );
358

Simon Hausmann's avatar
Simon Hausmann committed
359
  QWidget *res = KParts::MainWindow::createContainer( parent, index, element, id );
360

Waldo Bastian's avatar
Waldo Bastian committed
361
  if ( res && (element.tagName() == tagToolBar) && (element.attribute( "name" ) == nameBookmarkBar) )
362
363
  {
    assert( res->inherits( "KToolBar" ) );
Laurent Montel's avatar
Laurent Montel committed
364
    if (!KAuthorized::authorizeKAction("bookmarks"))
Waldo Bastian's avatar
Waldo Bastian committed
365
366
367
368
    {
        delete res;
        return 0;
    }
369

370
371
372
373
    if ( !m_bookmarkBarActionCollection )
    {
        // The actual menu needs a different action collection, so that the bookmarks
        // don't appear in kedittoolbar
David Faure's avatar
David Faure committed
374
        m_bookmarkBarActionCollection = new KActionCollection( static_cast<QWidget *>(this) );
375
376
377
        DelayedInitializer *initializer = new DelayedInitializer( QEvent::Show, res );
        connect( initializer, SIGNAL( initialize() ), this, SLOT(initBookmarkBar()) );
    }
378
  }
379

380
  return res;
381
}
382

Maks Orlovich's avatar
   
Maks Orlovich committed
383
384
385
void KonqMainWindow::initBookmarkBar()
{
  KToolBar * bar = static_cast<KToolBar *>( child( "bookmarkToolBar", "KToolBar" ) );
386

Maks Orlovich's avatar
   
Maks Orlovich committed
387
  if (!bar) return;
388

389
  delete m_paBookmarkBar;
390
  m_paBookmarkBar = new KBookmarkBar( KonqBookmarkManager::self(), m_pBookmarksOwner, bar, m_bookmarkBarActionCollection, this );
391
  connect( m_paBookmarkBar,
392
393
           SIGNAL( aboutToShowContextMenu(const KBookmark &, QMenu*) ),
           this, SLOT( slotFillContextMenu(const KBookmark &, QMenu*) ));
394
  connect( m_paBookmarkBar,
395
396
	   SIGNAL( openBookmark(const QString &, Qt::MouseButtons, Qt::KeyboardModifiers) ),
	   this, SLOT( slotOpenBookmarkUrl(const QString &, Qt::MouseButtons, Qt::KeyboardModifiers) ));
Maks Orlovich's avatar
   
Maks Orlovich committed
397
398

  // hide if empty
399
  if (bar->actions().count() == 0 )
Waldo Bastian's avatar
Waldo Bastian committed
400
     bar->hide();
Maks Orlovich's avatar
   
Maks Orlovich committed
401
402
}

403
404
void KonqMainWindow::removeContainer( QWidget *container, QWidget *parent, QDomElement &element, int id )
{
Laurent Montel's avatar
Laurent Montel committed
405
406
  static QString nameBookmarkBar = QLatin1String( "bookmarkToolBar" );
  static QString tagToolBar = QLatin1String( "ToolBar" );
407
408
409
410

  if ( element.tagName() == tagToolBar && element.attribute( "name" ) == nameBookmarkBar )
  {
    assert( container->inherits( "KToolBar" ) );
411
412
    if (m_paBookmarkBar)
      m_paBookmarkBar->clear();
413
414
415
416
417
  }

  KParts::MainWindow::removeContainer( container, parent, element, id );
}

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.
Laurent Montel's avatar
Laurent Montel committed
422
QString KonqMainWindow::detectNameFilter( KUrl & url )
423
{
424
    if ( !KProtocolInfo::supportsListing(url) )
Laurent Montel's avatar
Laurent Montel committed
425
        return QString();
426

427
428
    // Look for wildcard selection
    QString nameFilter;
429
    QString path = url.path();
430
    int lastSlash = path.lastIndexOf( '/' );
431
    if ( lastSlash > -1 )
432
    {
433
434
        if ( !url.query().isEmpty() && lastSlash == (int)path.length()-1 ) {  //  In /tmp/?foo, foo isn't a query
            path += url.query(); // includes the '?'
Laurent Montel's avatar
Laurent Montel committed
435
            url.setQuery( QString() );
436
437
438
        }
        QString fileName = path.mid( lastSlash + 1 );
        QString testPath = path.left( lastSlash + 1 );
439
        if ( fileName.indexOf( '*' ) != -1 || fileName.indexOf( '[' ) != -1 || fileName.indexOf( '?' ) != -1 )
440
        {
441
442
443
444
445
            // Check that a file or dir with all the special chars in the filename doesn't exist
            if ( url.isLocalFile() ? !QFile::exists( path ) : !KIO::NetAccess::exists( url, false, this ) )
            {
                nameFilter = fileName;
                url.setFileName( QString() );
Laurent Montel's avatar
Laurent Montel committed
446
                kDebug(1202) << "Found wildcard. nameFilter=" << nameFilter << "  New url=" << url << endl;
447
            }
448
        }
449
    }
450

451
452
453
    return nameFilter;
}

454
void KonqMainWindow::openFilteredUrl( const QString & url, KonqOpenURLRequest & req )
455
{
456
    // Filter URL to build a correct one
457
458
    if (m_currentDir.isEmpty() && m_currentView)
       m_currentDir = m_currentView->url().path(1);
459

Laurent Montel's avatar
Laurent Montel committed
460
    KUrl filteredURL ( KonqMisc::konqFilteredURL( this, url, m_currentDir ) );
Laurent Montel's avatar
Laurent Montel committed
461
    kDebug(1202) << "url " << url << " filtered into " << filteredURL.prettyURL() << endl;
462

463
464
    if ( filteredURL.isEmpty() ) // initially empty, or error (e.g. ~unknown_user)
        return;
465

Laurent Montel's avatar
Laurent Montel committed
466
    m_currentDir.clear();
467

Laurent Montel's avatar
Laurent Montel committed
468
    openURL( 0L, filteredURL, QString(), req );
469
470
471
472
473
474
475

    // #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
    // If it is changed, then it's done in KonqView::changeViewMode
    if ( m_currentView && m_currentView->part() )
      m_currentView->part()->widget()->setFocus();

476
477
}

478
void KonqMainWindow::openFilteredUrl( const QString & _url, bool inNewTab, bool tempFile )
479
480
481
482
483
{
    KonqOpenURLRequest req( _url );
    req.newTab = inNewTab;
    req.newTabInFront = true;
    req.tempFile = tempFile;
484

485
    openFilteredUrl( _url, req );
486
487
}

Laurent Montel's avatar
Laurent Montel committed
488
void KonqMainWindow::openURL( KonqView *_view, const KUrl &_url,
489
                              const QString &_serviceType, KonqOpenURLRequest& req,
490
                              bool trustedSource )
491
{
492
#ifndef NDEBUG // needed for req.debug()
Laurent Montel's avatar
Laurent Montel committed
493
  kDebug(1202) << "KonqMainWindow::openURL : url = '" << _url << "'  "
494
495
496
                << "serviceType='" << _serviceType << " req=" << req.debug()
                << "' view=" << _view << endl;
#endif
497

Laurent Montel's avatar
Laurent Montel committed
498
  KUrl url( _url );
499
  QString serviceType( _serviceType );
Doug Hanley's avatar
   
Doug Hanley committed
500
501
502
503
  if ( url.url() == "about:blank" )
  {
    serviceType = "text/html";
  }
504
  else if ( !url.isValid() )
505
  {
506
      KMessageBox::error(0, i18n("Malformed URL\n%1", url.url()));
507
508
      return;
  }
Wilco Greven's avatar
Wilco Greven committed
509
  else if ( !KProtocolInfo::isKnownProtocol( url ) && url.protocol() != "about" )
510
  {
511
      KMessageBox::error(0, i18n("Protocol not supported\n%1", url.protocol()));
512
      return;
513
514
  }

515
516
  QString nameFilter = detectNameFilter( url );
  if ( !nameFilter.isEmpty() )
517
  {
518
    req.nameFilter = nameFilter;
Laurent Montel's avatar
Laurent Montel committed
519
    url.setFileName( QString() );
520
521
  }

522
  KonqView *view = _view;
523

524
525
526
527
  // When clicking a 'follow active' view (e.g. view is the sidebar),
  // open the URL in the active view
  if ( view && view->isFollowActive() )
    view = m_currentView;
528

529
  if ( !view  && !req.newTab )
David Faure's avatar
David Faure committed
530
    view = m_currentView; /* Note, this can be 0L, e.g. on startup */
531
  else if ( !view && req.newTab ) {
Laurent Montel's avatar
Laurent Montel committed
532
533
    view = m_pViewManager->addTab(QString(),
                                  QString(),
534
                                  false,
535
                                  req.openAfterCurrentPage);
536
    if (view) {
537
      view->setCaption( _url.host() );
538
      view->setLocationBarURL( _url );
539
540
      if ( !req.args.frameName.isEmpty() )
          view->setViewName( req.args.frameName ); // #44961
Simon Hausmann's avatar
Simon Hausmann committed
541

542
543
      if ( req.newTabInFront )
        m_pViewManager->showTab( view );
544

545
      updateViewActions(); //A new tab created -- we may need to enable the "remove tab" button (#56318)
546
547
548
    }
    else
      req.newTab = false;
549
  }
550

551
  const QString oldLocationBarURL = m_combo->currentText();
Alexander Kellett's avatar
Alexander Kellett committed
552
  if ( view )
Simon Hausmann's avatar
Simon Hausmann committed
553
  {
554
    if ( view == m_currentView )
555
    {
556
      //will do all the stuff below plus GUI stuff
557
      abortLoading();
558
    }
559
    else
560
    {
561
      view->stop();
562
563
      // Don't change location bar if not current view
    }
564
  }
565

566
  // Fast mode for local files: do the stat ourselves instead of letting KRun do it.
567
  if ( serviceType.isEmpty() && url.isLocalFile() )
568
  {
Pascal Létourneau's avatar
Porting    
Pascal Létourneau committed
569
    QByteArray _path( QFile::encodeName(url.path()));
570
571
572
573
574
    KDE_struct_stat buff;
    if ( KDE_stat( _path.data(), &buff ) != -1 )
        serviceType = KMimeType::findByURL( url, buff.st_mode )->name();
  }

Laurent Montel's avatar
Laurent Montel committed
575
  kDebug(1202) << "trying openView for " << url << " (serviceType " << serviceType << ")" << endl;
576
577
  if ( ( !serviceType.isEmpty() && serviceType != "application/octet-stream") ||
         url.url() == "about:konqueror" || url.url() == "about:plugins" )
578
  {
579
580
581
582
583
    KService::Ptr offer = KServiceTypeProfile::preferredService(serviceType, "Application");
    // If the associated app is konqueror itself, then make sure we try to embed before bailing out.
    if ( isMimeTypeAssociatedWithSelf( serviceType, offer ) )
      req.forceAutoEmbed = true;

584
    // Built-in view ?
585
    if ( !openView( serviceType, url, view /* can be 0L */, req ) )
David Faure's avatar
David Faure committed
586
    {
Laurent Montel's avatar
Laurent Montel committed
587
        //kDebug(1202) << "KonqMainWindow::openURL : openView returned false" << endl;
588
589
        // Are we following another view ? Then forget about this URL. Otherwise fire app.
        if ( !req.followMode )
590
        {
Laurent Montel's avatar
Laurent Montel committed
591
            //kDebug(1202) << "KonqMainWindow::openURL : we were not following. Fire app." << endl;
592
            // We know the servicetype, let's try its preferred service
593
            if ( isMimeTypeAssociatedWithSelf( serviceType, offer ) ) {
594
                KMessageBox::error( this, i18n("There appears to be a configuration error. You have associated Konqueror with %1, but it cannot handle this file type.", serviceType));
Simon Hausmann's avatar
Simon Hausmann committed
595
                return;
596
597
598
            }
            if ( !url.isLocalFile() && KonqRun::isTextExecutable( serviceType ) )
                serviceType = "text/plain"; // view, don't execute
599
            // Remote URL: save or open ?
600
601
            QString protClass = KProtocolInfo::protocolClass(url.protocol());
            bool open = url.isLocalFile() || protClass==":local";
602
603
604
            if ( !open ) {
                KParts::BrowserRun::AskSaveResult res = KonqRun::askSave( url, offer, serviceType );
                if ( res == KParts::BrowserRun::Save )
Laurent Montel's avatar
Laurent Montel committed
605
                    KParts::BrowserRun::simpleSave( url, QString(), this );
606
607
                open = ( res == KParts::BrowserRun::Open );
            }
608
            if ( open )
609
            {
Laurent Montel's avatar
Laurent Montel committed
610
                KUrl::List lst;
611
                lst.append(url);
Laurent Montel's avatar
Laurent Montel committed
612
                //kDebug(1202) << "Got offer " << (offer ? offer->name().toLatin1() : "0") << endl;
613
614
615
                if ( ( trustedSource || KonqRun::allowExecution( serviceType, url ) ) &&
                     ( KonqRun::isExecutable( serviceType ) || !offer || !KRun::run( *offer, lst ) ) )
                {
616
                    setLocationBarURL( oldLocationBarURL ); // Revert to previous locationbar URL
617
                    (void)new KRun( url, this );
618
                }
619
            }
620
        }
David Faure's avatar
David Faure committed
621
    }
622
  }
623
  else // no known serviceType, use KonqRun
624
  {
625
626
627
628
629
      if ( ( view && view == m_currentView ) ||
              ( !view && !req.newTab ) ) // startup with argument
      {
          // Show it for now in the location bar, but we'll need to store it in the view
          // later on (can't do it yet since either view == 0 or updateHistoryEntry will be called).
Laurent Montel's avatar
Laurent Montel committed
630
          kDebug(1202) << "setLocationBarURL : url = " << url << endl;
631
          setLocationBarURL( url );
632
633
      }

Laurent Montel's avatar
Laurent Montel committed
634
      kDebug(1202) << "Creating new konqrun for " << url << " req.typedURL=" << req.typedURL << endl;
George Staikos's avatar
   
George Staikos committed
635

636
      KonqRun * run = new KonqRun( this, view /* can be 0L */, url, req, trustedSource );
637
638
639
640

      // Never start in external browser
      run->setEnableExternalBrowser(false);

641
642
      if ( view )
        view->setRun( run );
643
      else if ( !req.newTab )
644
      {
645
        // there can be only one :) (when not a new tab)
Laurent Montel's avatar
Laurent Montel committed
646
647
          delete m_initialKonqRun;
          m_initialKonqRun = run;
648
      }
649

650
651
      if ( view == m_currentView )
        startAnimation();
652
653

      connect( run, SIGNAL( finished() ), this, SLOT( slotRunFinished() ) );
654
  }
655
656
}

Laurent Montel's avatar
Laurent Montel committed
657
bool KonqMainWindow::openView( QString serviceType, const KUrl &_url, KonqView *childView, KonqOpenURLRequest& req )
658
{
659
  // Second argument is referring URL
Laurent Montel's avatar
KURL--    
Laurent Montel committed
660
  if ( !KAuthorized::authorizeURLAction("open", childView ? childView->url() : KUrl(), _url) )
661
662
663
664
665
666
  {
     QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, _url.prettyURL());
     KMessageBox::queuedMessageBox( this, KMessageBox::Error, msg );
     return true; // Nothing else to do.
  }

David Faure's avatar
David Faure committed
667
  if ( KonqRun::isExecutable( serviceType ) )
668
     return false; // execute, don't open
669
670
  // Contract: the caller of this method should ensure the view is stopped first.

671
#ifndef NDEBUG
Laurent Montel's avatar
Laurent Montel committed
672
  kDebug(1202) << "KonqMainWindow::openView " << serviceType << " " << _url << " " << childView << " req:" << req.debug() << endl;
673
#endif
674
  bool bOthersFollowed = false;
675

676
677
678
679
680
681
682
683
684
685
686
  if ( childView )
  {
    // If we're not already following another view (and if we are not reloading)
    if ( !req.followMode && !req.args.reload && !m_pViewManager->isLoadingProfile() )
    {
      // When clicking a 'follow active' view (e.g. childView is the sidebar),
      // open the URL in the active view
      // (it won't do anything itself, since it's locked to its location)
      if ( childView->isFollowActive() && childView != m_currentView )
      {
        abortLoading();
687
        setLocationBarURL( _url );
688
689
690
691
692
693
694
695
696
697
698
        KonqOpenURLRequest newreq;
        newreq.followMode = true;
        newreq.args = req.args;
        bOthersFollowed = openView( serviceType, _url, m_currentView, newreq );
      }
      // "link views" feature, and "sidebar follows active view" feature
      bOthersFollowed = makeViewsFollow(_url, req.args, serviceType, childView) || bOthersFollowed;
    }
    if ( childView->isLockedLocation() && !req.args.reload /* allow to reload a locked view*/ )
      return bOthersFollowed;
  }
699

700
701
  QString indexFile;

Laurent Montel's avatar
Laurent Montel committed
702
  KUrl url( _url );
703

704
705
706
707
  // Generic mechanism for redirecting to tar:/<path>/ when clicking on a tar file,
  // zip:/<path>/ when clicking on a zip file, etc.
  // The name of the protocol to redirect to, is read from the mimetype's .desktop file
  if ( url.isLocalFile() )
708
  {
709
    KServiceType::Ptr ptr = KServiceType::serviceType( serviceType );
710
    if ( ptr )
711
    {
712
      const QString protocol = ptr->property("X-KDE-LocalProtocol").toString();
713
      if ( !protocol.isEmpty() && KonqFMSettings::settings()->shouldEmbed( serviceType ) )
714
715
716
717
718
719
720
721
722
723
724
725
726
      {
        url.setProtocol( protocol );
        if ( serviceType == "application/x-webarchive" )
        {
          url.setPath( url.path() + "/index.html" );
          serviceType = "text/html";
        }
        else
        {
          url.setPath( url.path() + '/' );
          serviceType = "inode/directory";
        }
      }
727
728
    }
  }
729
730
731

  ///////////

732
733
734
735
  // In case we open an index.html, we want the location bar
  // to still display the original URL (so that 'up' uses that URL,
  // and since that's what the user entered).
  // changeViewMode will take care of setting and storing that url.
736
  QString originalURL = url.pathOrURL();
737
  if ( !req.nameFilter.isEmpty() ) // keep filter in location bar
738
  {
Helge Deller's avatar
Helge Deller committed
739
    if (!originalURL.endsWith("/"))
740
        originalURL += '/';
741
    originalURL += req.nameFilter;
742
  }