Fix crash if key bindings specified in profile cannot be found. Improve
[personal-kdebase.git] / apps / lib / konq / knewmenu.cpp
blob9e7a8763c0fa7b2c49fc217954c7adddbe8fc465
1 /* This file is part of the KDE project
2 Copyright (C) 1998, 1999 David Faure <faure@kde.org>
3 2003 Sven Leiber <s.leiber@web.de>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
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.
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.
20 #include "knewmenu.h"
21 #include "knewmenu_p.h"
22 #include "konq_operations.h"
24 #include <QDir>
25 #include <QVBoxLayout>
26 #include <QList>
27 #include <kactioncollection.h>
28 #include <kdebug.h>
29 #include <kdesktopfile.h>
30 #include <kdirwatch.h>
31 #include <kicon.h>
32 #include <kcomponentdata.h>
33 #include <kinputdialog.h>
34 #include <klocale.h>
35 #include <kmessagebox.h>
36 #include <kstandarddirs.h>
37 #include <kprotocolinfo.h>
38 #include <kprotocolmanager.h>
39 #include <kmenu.h>
40 #include <krun.h>
41 #include <kio/copyjob.h>
42 #include <kio/jobuidelegate.h>
43 #include <kio/renamedialog.h>
44 #include <kio/netaccess.h>
45 #include <kio/fileundomanager.h>
47 #include <kpropertiesdialog.h>
48 #include <ktemporaryfile.h>
49 #include <utime.h>
51 // For KUrlDesktopFileDlg
52 #include <QLayout>
53 #include <klineedit.h>
54 #include <kurlrequester.h>
55 #include <QLabel>
57 // Singleton, with data shared by all KNewMenu instances
58 class KNewMenuSingleton
60 public:
61 KNewMenuSingleton()
62 : templatesList(0),
63 templatesVersion(0),
64 filesParsed(false),
65 dirWatch(0)
68 ~KNewMenuSingleton()
70 delete templatesList;
71 delete dirWatch;
74 struct Entry {
75 QString text;
76 QString filePath; // empty for SEPARATOR
77 QString templatePath; // same as filePath for TEMPLATE
78 QString icon;
79 int entryType;
80 QString comment;
82 // NOTE: only filePath is known before we call parseFiles
84 /**
85 * List of all template files. It is important that they are in
86 * the same order as the 'New' menu.
88 typedef QList<Entry> EntryList;
89 EntryList * templatesList;
91 /**
92 * Is increased when templatesList has been updated and
93 * menu needs to be re-filled. Menus have their own version and compare it
94 * to templatesVersion before showing up
96 int templatesVersion;
98 /**
99 * Set back to false each time new templates are found,
100 * and to true on the first call to parseFiles
102 bool filesParsed;
103 KDirWatch * dirWatch;
106 K_GLOBAL_STATIC(KNewMenuSingleton, kNewMenuGlobals)
108 class KNewMenu::KNewMenuPrivate
110 public:
111 KNewMenuPrivate()
112 : menuItemsVersion(0)
114 KActionCollection * m_actionCollection;
115 QWidget *m_parentWidget;
116 KActionMenu *m_menuDev;
117 QAction* m_newDirAction;
119 int menuItemsVersion;
122 * When the user pressed the right mouse button over an URL a popup menu
123 * is displayed. The URL belonging to this popup menu is stored here.
125 KUrl::List popupFiles;
128 * True when a desktop file with Type=URL is being copied
130 bool m_isUrlDesktopFile;
131 QString m_tempFileToDelete; // set when a tempfile was created for a Type=URL desktop file
134 * The action group that our actions belong to
136 QActionGroup* m_newMenuGroup;
139 KNewMenu::KNewMenu( KActionCollection *parent, QWidget* parentWidget, const QString& name )
140 : KActionMenu( KIcon("document-new"), i18n( "Create New" ), parentWidget )
142 // Don't fill the menu yet
143 // We'll do that in slotCheckUpToDate (should be connected to aboutToShow)
144 d = new KNewMenuPrivate;
145 d->m_newMenuGroup = new QActionGroup(this);
146 connect(d->m_newMenuGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotActionTriggered(QAction*)));
147 d->m_actionCollection = parent;
148 d->m_parentWidget = parentWidget;
150 d->m_actionCollection->addAction( name, this );
152 makeMenus();
155 KNewMenu::~KNewMenu()
157 //kDebug(1203) << "KNewMenu::~KNewMenu " << this;
158 delete d;
161 void KNewMenu::makeMenus()
163 d->m_menuDev = new KActionMenu( KIcon("drive-removable-media"), i18n( "Link to Device" ), this );
166 void KNewMenu::slotCheckUpToDate( )
168 KNewMenuSingleton* s = kNewMenuGlobals;
169 //kDebug(1203) << "KNewMenu::slotCheckUpToDate() " << this
170 // << " : menuItemsVersion=" << d->menuItemsVersion
171 // << " s->templatesVersion=" << s->templatesVersion;
172 if (d->menuItemsVersion < s->templatesVersion || s->templatesVersion == 0) {
173 //kDebug(1203) << "KNewMenu::slotCheckUpToDate() : recreating actions";
174 // We need to clean up the action collection
175 // We look for our actions using the group
176 foreach (QAction* action, d->m_newMenuGroup->actions())
177 delete action;
179 if (!s->templatesList) { // No templates list up to now
180 s->templatesList = new KNewMenuSingleton::EntryList;
181 slotFillTemplates();
182 parseFiles();
185 // This might have been already done for other popupmenus,
186 // that's the point in s->filesParsed.
187 if ( !s->filesParsed )
188 parseFiles();
190 fillMenu();
192 d->menuItemsVersion = s->templatesVersion;
196 void KNewMenu::parseFiles()
198 KNewMenuSingleton* s = kNewMenuGlobals;
199 //kDebug(1203) << "KNewMenu::parseFiles()";
200 s->filesParsed = true;
201 KNewMenuSingleton::EntryList::iterator templ = s->templatesList->begin();
202 const KNewMenuSingleton::EntryList::iterator templ_end = s->templatesList->end();
203 for ( ; templ != templ_end; ++templ )
205 QString iconname;
206 QString filePath = (*templ).filePath;
207 if ( !filePath.isEmpty() )
209 QString text;
210 QString templatePath;
211 // If a desktop file, then read the name from it.
212 // Otherwise (or if no name in it?) use file name
213 if ( KDesktopFile::isDesktopFile( filePath ) ) {
214 KDesktopFile desktopFile( filePath );
215 const KConfigGroup config = desktopFile.desktopGroup();
216 text = config.readEntry("Name");
217 (*templ).icon = config.readEntry("Icon");
218 (*templ).comment = config.readEntry("Comment");
219 QString type = config.readEntry( "Type" );
220 if ( type == "Link" )
222 templatePath = config.readPathEntry("URL", QString());
223 if ( templatePath[0] != '/' )
225 if ( templatePath.startsWith("file:/") )
226 templatePath = KUrl(templatePath).path();
227 else
229 // A relative path, then (that's the default in the files we ship)
230 QString linkDir = filePath.left( filePath.lastIndexOf( '/' ) + 1 /*keep / */ );
231 //kDebug(1203) << "linkDir=" << linkDir;
232 templatePath = linkDir + templatePath;
236 if ( templatePath.isEmpty() )
238 // No dest, this is an old-style template
239 (*templ).entryType = TEMPLATE;
240 (*templ).templatePath = (*templ).filePath; // we'll copy the file
241 } else {
242 (*templ).entryType = LINKTOTEMPLATE;
243 (*templ).templatePath = templatePath;
247 if (text.isEmpty())
249 text = KUrl(filePath).fileName();
250 if ( text.endsWith(".desktop") )
251 text.truncate( text.length() - 8 );
253 (*templ).text = text;
254 /*kDebug(1203) << "Updating entry with text=" << text
255 << "entryType=" << (*templ).entryType
256 << "templatePath=" << (*templ).templatePath;*/
258 else {
259 (*templ).entryType = SEPARATOR;
264 void KNewMenu::fillMenu()
266 //kDebug(1203) << "KNewMenu::fillMenu()";
267 menu()->clear();
268 d->m_menuDev->menu()->clear();
269 d->m_newDirAction = 0;
271 QSet<QString> seenTexts;
272 QAction *linkURL = 0, *linkApp = 0; // these shall be put at special positions
274 KNewMenuSingleton* s = kNewMenuGlobals;
275 int i = 1;
276 KNewMenuSingleton::EntryList::const_iterator templ = s->templatesList->constBegin();
277 const KNewMenuSingleton::EntryList::const_iterator templ_end = s->templatesList->constEnd();
278 for ( ; templ != templ_end; ++templ, ++i)
280 if ( (*templ).entryType != SEPARATOR )
282 // There might be a .desktop for that one already, if it's a kdelnk
283 // This assumes we read .desktop files before .kdelnk files ...
285 // In fact, we skip any second item that has the same text as another one.
286 // Duplicates in a menu look bad in any case.
288 bool bSkip = seenTexts.contains((*templ).text);
289 if ( bSkip ) {
290 kDebug(1203) << "KNewMenu: skipping" << (*templ).filePath;
291 } else {
292 seenTexts.insert((*templ).text);
293 const KNewMenuSingleton::Entry entry = s->templatesList->at( i-1 );
295 // The best way to identify the "Create Directory", "Link to Location", "Link to Application" was the template
296 if ( (*templ).templatePath.endsWith( "emptydir" ) )
298 QAction * act = new QAction( this );
299 d->m_newDirAction = act;
300 act->setIcon( KIcon((*templ).icon) );
301 act->setText( (*templ).text );
302 act->setActionGroup( d->m_newMenuGroup );
303 menu()->addAction( act );
305 QAction *sep = new QAction(this);
306 sep->setSeparator( true );
307 menu()->addAction( sep );
309 else
311 QAction * act = new QAction(this);
312 act->setData( i );
313 act->setIcon( KIcon((*templ).icon) );
314 act->setText( (*templ).text );
315 act->setActionGroup( d->m_newMenuGroup );
317 if ( (*templ).templatePath.endsWith( "URL.desktop" ) )
319 linkURL = act;
321 else if ( (*templ).templatePath.endsWith( "Program.desktop" ) )
323 linkApp = act;
325 else if ( KDesktopFile::isDesktopFile( entry.templatePath ) )
327 KDesktopFile df( entry.templatePath );
328 if(df.readType() == "FSDevice")
329 d->m_menuDev->menu()->addAction( act );
330 else
331 menu()->addAction( act );
333 else
335 menu()->addAction( act );
339 } else { // Separate system from personal templates
340 Q_ASSERT( (*templ).entryType != 0 );
342 QAction *sep = new QAction( this );
343 sep->setSeparator( true );
344 menu()->addAction( sep );
348 QAction *sep = new QAction( this );
349 sep->setSeparator( true );
350 menu()->addAction( sep );
351 if ( linkURL ) menu()->addAction( linkURL );
352 if ( linkApp ) menu()->addAction( linkApp );
353 Q_ASSERT(d->m_menuDev);
354 menu()->addAction( d->m_menuDev );
358 void KNewMenu::slotFillTemplates()
360 KNewMenuSingleton* s = kNewMenuGlobals;
361 //kDebug(1203) << "KNewMenu::slotFillTemplates()";
362 // Ensure any changes in the templates dir will call this
363 if ( ! s->dirWatch ) {
364 s->dirWatch = new KDirWatch;
365 const QStringList dirs = d->m_actionCollection->componentData().dirs()->resourceDirs("templates");
366 for ( QStringList::const_iterator it = dirs.constBegin() ; it != dirs.constEnd() ; ++it ) {
367 //kDebug(1203) << "Templates resource dir:" << *it;
368 s->dirWatch->addDir( *it );
370 connect ( s->dirWatch, SIGNAL( dirty( const QString & ) ),
371 this, SLOT ( slotFillTemplates() ) );
372 connect ( s->dirWatch, SIGNAL( created( const QString & ) ),
373 this, SLOT ( slotFillTemplates() ) );
374 connect ( s->dirWatch, SIGNAL( deleted( const QString & ) ),
375 this, SLOT ( slotFillTemplates() ) );
376 // Ok, this doesn't cope with new dirs in KDEDIRS, but that's another story
378 ++s->templatesVersion;
379 s->filesParsed = false;
381 s->templatesList->clear();
383 // Look into "templates" dirs.
384 const QStringList files = d->m_actionCollection->componentData().dirs()->findAllResources("templates");
385 QMap<QString, KNewMenuSingleton::Entry> slist; // used for sorting
386 for ( QStringList::const_iterator it = files.constBegin() ; it != files.constEnd() ; ++it )
388 //kDebug(1203) << *it;
389 if ( (*it)[0] != '.' )
391 KNewMenuSingleton::Entry e;
392 e.filePath = *it;
393 e.entryType = 0; // not parsed yet
394 // put Directory etc. with special order (see fillMenu()) first in the list (a bit hacky)
395 if ( (*it).endsWith( "Directory.desktop" ) ||
396 (*it).endsWith( "linkProgram.desktop" ) ||
397 (*it).endsWith( "linkURL.desktop" ) )
398 s->templatesList->prepend( e );
399 else
401 KDesktopFile config( *it );
403 // tricky solution to ensure that TextFile is at the beginning
404 // because this filetype is the most used (according kde-core discussion)
405 QString key = config.desktopGroup().readEntry("Name");
406 if ( (*it).endsWith( "TextFile.desktop" ) )
407 key.prepend( '1' );
408 else
409 key.prepend( '2' );
411 slist.insert( key, e );
415 (*s->templatesList) += slist.values();
418 void KNewMenu::newDir()
420 if (d->popupFiles.isEmpty())
421 return;
423 KIO::SimpleJob* job = KonqOperations::newDir(d->m_parentWidget, d->popupFiles.first());
424 if (job) {
425 // We want the error handling to be done by slotResult so that subclasses can reimplement it
426 job->ui()->setAutoErrorHandlingEnabled(false);
427 connect( job, SIGNAL( result( KJob * ) ),
428 SLOT( slotResult( KJob * ) ) );
433 void KNewMenu::slotActionTriggered(QAction* action)
435 trigger(); // for KDIconView::slotNewMenuActivated()
437 if (action == d->m_newDirAction) {
438 newDir();
439 return;
441 const int id = action->data().toInt();
442 Q_ASSERT(id > 0);
444 KNewMenuSingleton* s = kNewMenuGlobals;
445 const KNewMenuSingleton::Entry entry = s->templatesList->at( id - 1 );
446 //kDebug(1203) << "sFile=" << sFile;
448 if ( !QFile::exists( entry.templatePath ) ) {
449 kWarning(1203) << entry.templatePath << "doesn't exist" ;
450 KMessageBox::sorry( 0L, i18n("<qt>The template file <b>%1</b> does not exist.</qt>", entry.templatePath));
451 return;
454 // true when a desktop file with Type=URL is being copied
455 d->m_isUrlDesktopFile = false;
456 KUrl linkUrl; // the url to put in the file
458 QString name;
459 if ( KDesktopFile::isDesktopFile( entry.templatePath ) )
461 KDesktopFile df( entry.templatePath );
462 //kDebug(1203) << df.readType();
463 if ( df.readType() == "Link" )
465 d->m_isUrlDesktopFile = true;
466 // entry.comment contains i18n("Enter link to location (URL):"). JFYI :)
467 KUrlDesktopFileDlg dlg( i18n("File name:"), entry.comment, d->m_parentWidget );
468 // TODO dlg.setCaption( i18n( ... ) );
469 if ( dlg.exec() )
471 name = dlg.fileName();
472 linkUrl = dlg.url();
473 if ( name.isEmpty() || linkUrl.isEmpty() )
474 return;
475 if ( !name.endsWith( ".desktop" ) )
476 name += ".desktop";
478 else
479 return;
481 else // any other desktop file (Device, App, etc.)
483 KUrl::List::Iterator it = d->popupFiles.begin();
484 for ( ; it != d->popupFiles.end(); ++it )
486 //kDebug(1203) << "first arg=" << entry.templatePath;
487 //kDebug(1203) << "second arg=" << (*it).url();
488 //kDebug(1203) << "third arg=" << entry.text;
489 QString text = entry.text;
490 text.replace( "...", QString() ); // the ... is fine for the menu item but not for the default filename
492 KUrl defaultFile( *it );
493 defaultFile.addPath( KIO::encodeFileName( text ) );
494 if ( defaultFile.isLocalFile() && QFile::exists( defaultFile.path() ) )
495 text = KIO::RenameDialog::suggestName( *it, text);
497 KUrl templateUrl( entry.templatePath );
498 KPropertiesDialog dlg( templateUrl, *it, text, d->m_parentWidget );
499 dlg.exec();
501 return; // done, exit.
504 else
506 // The template is not a desktop file
507 // Show the small dialog for getting the destination filename
508 bool ok;
509 QString text = entry.text;
510 text.replace( "...", QString() ); // the ... is fine for the menu item but not for the default filename
512 KUrl defaultFile( *(d->popupFiles.begin()) );
513 defaultFile.addPath( KIO::encodeFileName( text ) );
514 if ( defaultFile.isLocalFile() && QFile::exists( defaultFile.path() ) )
515 text = KIO::RenameDialog::suggestName( *(d->popupFiles.begin()), text);
517 name = KInputDialog::getText( QString(), entry.comment,
518 text, &ok, d->m_parentWidget );
519 if ( !ok )
520 return;
523 QString src = entry.templatePath;
525 if (d->m_isUrlDesktopFile) {
526 // It's a "URL" desktop file; we need to make a temp copy of it, to modify it
527 // before copying it to the final destination [which could be a remote protocol]
528 KTemporaryFile tmpFile;
529 tmpFile.setAutoRemove(false); // done below
530 if (!tmpFile.open()) {
531 kError() << "Couldn't create temp file!";
532 return;
534 // First copy the template into the temp file
535 QFile file(src);
536 if (!file.open(QIODevice::ReadOnly)) {
537 kError() << "Couldn't open template" << src;
538 return;
540 const QByteArray data = file.readAll();
541 tmpFile.write(data);
542 const QString tempFileName = tmpFile.fileName();
543 Q_ASSERT(!tempFileName.isEmpty());
544 tmpFile.close();
546 KDesktopFile df(tempFileName);
547 KConfigGroup group = df.desktopGroup();
548 group.writeEntry("Icon", KProtocolInfo::icon(linkUrl.protocol()));
549 group.writePathEntry("URL", linkUrl.prettyUrl());
550 df.sync();
551 src = tempFileName;
552 d->m_tempFileToDelete = tempFileName;
555 // The template is not a desktop file [or it's a URL one]
556 // Copy it.
557 KUrl::List::const_iterator it = d->popupFiles.constBegin();
558 for ( ; it != d->popupFiles.constEnd(); ++it )
560 KUrl dest( *it );
561 dest.addPath( KIO::encodeFileName(name) ); // Chosen destination file name
563 KUrl uSrc(src);
564 //kDebug(1203) << "KNewMenu : KIO::copyAs(" << uSrc.url() << "," << dest.url() << ")";
565 KIO::CopyJob * job = KIO::copyAs( uSrc, dest );
566 job->setDefaultPermissions( true );
567 job->ui()->setWindow( d->m_parentWidget );
568 connect( job, SIGNAL( result( KJob * ) ),
569 SLOT( slotResult( KJob * ) ) );
570 KUrl::List lst;
571 lst.append(uSrc);
572 KIO::FileUndoManager::self()->recordJob(KIO::FileUndoManager::Copy, lst, dest, job);
576 void KNewMenu::slotResult( KJob * job )
578 if (job->error()) {
579 static_cast<KIO::Job*>( job )->ui()->showErrorMessage();
580 } else {
581 // Was this a copy or a mkdir?
582 KIO::CopyJob* copyJob = ::qobject_cast<KIO::CopyJob*>(job);
583 if (copyJob) {
584 const KUrl destUrl = copyJob->destUrl();
585 const KUrl localUrl = KIO::NetAccess::mostLocalUrl(destUrl, d->m_parentWidget);
586 if (localUrl.isLocalFile()) {
587 // Normal (local) file. Need to "touch" it, kio_file copied the mtime.
588 (void) ::utime(QFile::encodeName(localUrl.path()), 0);
592 if (!d->m_tempFileToDelete.isEmpty())
593 QFile::remove(d->m_tempFileToDelete);
596 void KNewMenu::setPopupFiles(const KUrl::List& files)
598 d->popupFiles = files;
599 if (files.isEmpty()) {
600 d->m_newMenuGroup->setEnabled(false);
601 } else {
602 KUrl firstUrl = files.first();
603 if (KProtocolManager::supportsWriting(firstUrl)) {
604 d->m_newMenuGroup->setEnabled(true);
605 if (d->m_newDirAction) {
606 d->m_newDirAction->setEnabled(KProtocolManager::supportsMakeDir(firstUrl)); // e.g. trash:/
608 } else {
609 d->m_newMenuGroup->setEnabled(true);
614 //////////
616 KUrlDesktopFileDlg::KUrlDesktopFileDlg( const QString& textFileName, const QString& textUrl, QWidget *parent )
617 : KDialog( parent )
619 setButtons( Ok | Cancel | User1 );
620 setButtonGuiItem( User1, KStandardGuiItem::clear() );
621 showButtonSeparator( true );
623 initDialog( textFileName, QString(), textUrl, QString() );
626 void KUrlDesktopFileDlg::initDialog( const QString& textFileName, const QString& defaultName, const QString& textUrl, const QString& defaultUrl )
628 QFrame *plainPage = new QFrame( this );
629 setMainWidget( plainPage );
631 QVBoxLayout * topLayout = new QVBoxLayout( plainPage );
632 topLayout->setMargin( 0 );
633 topLayout->setSpacing( spacingHint() );
635 // First line: filename
636 KHBox * fileNameBox = new KHBox( plainPage );
637 topLayout->addWidget( fileNameBox );
639 QLabel * label = new QLabel( textFileName, fileNameBox );
640 m_leFileName = new KLineEdit( fileNameBox );
641 m_leFileName->setMinimumWidth(m_leFileName->sizeHint().width() * 3);
642 label->setBuddy(m_leFileName); // please "scheck" style
643 m_leFileName->setText( defaultName );
644 m_leFileName->setSelection(0, m_leFileName->text().length()); // autoselect
645 connect( m_leFileName, SIGNAL(textChanged(const QString&)),
646 SLOT(slotNameTextChanged(const QString&)) );
648 // Second line: url
649 KHBox * urlBox = new KHBox( plainPage );
650 topLayout->addWidget( urlBox );
651 label = new QLabel( textUrl, urlBox );
652 m_urlRequester = new KUrlRequester( defaultUrl, urlBox);
653 m_urlRequester->setMode( KFile::File | KFile::Directory );
655 m_urlRequester->setMinimumWidth( m_urlRequester->sizeHint().width() * 3 );
656 connect( m_urlRequester->lineEdit(), SIGNAL(textChanged(const QString&)),
657 SLOT(slotURLTextChanged(const QString&)) );
658 label->setBuddy(m_urlRequester); // please "scheck" style
660 m_urlRequester->setFocus();
661 enableButtonOk( !defaultName.isEmpty() && !defaultUrl.isEmpty() );
662 connect( this, SIGNAL(user1Clicked()), this, SLOT(slotClear()) );
663 m_fileNameEdited = false;
666 KUrl KUrlDesktopFileDlg::url() const
668 if ( result() == QDialog::Accepted )
669 return m_urlRequester->url();
670 else
671 return KUrl();
674 QString KUrlDesktopFileDlg::fileName() const
676 if ( result() == QDialog::Accepted )
677 return m_leFileName->text();
678 else
679 return QString();
682 void KUrlDesktopFileDlg::slotClear()
684 m_leFileName->clear();
685 m_urlRequester->clear();
686 m_fileNameEdited = false;
689 void KUrlDesktopFileDlg::slotNameTextChanged( const QString& )
691 kDebug() ;
692 m_fileNameEdited = true;
693 enableButtonOk( !m_leFileName->text().isEmpty() && !m_urlRequester->url().isEmpty() );
696 void KUrlDesktopFileDlg::slotURLTextChanged( const QString& )
698 if ( !m_fileNameEdited )
700 // use URL as default value for the filename
701 // (we copy only its filename if protocol supports listing,
702 // but for HTTP we don't want tons of index.html links)
703 KUrl url( m_urlRequester->url() );
704 if (KProtocolManager::supportsListing(url) && !url.fileName().isEmpty())
705 m_leFileName->setText( url.fileName() );
706 else
707 m_leFileName->setText( url.url() );
708 m_fileNameEdited = false; // slotNameTextChanged set it to true erroneously
710 enableButtonOk( !m_leFileName->text().isEmpty() && !m_urlRequester->url().isEmpty() );
714 #include "knewmenu.moc"
715 #include "knewmenu_p.moc"