25 #include <QVBoxLayout>
59 if (!name.isEmpty() && (!isfile || name[0] ==
'\\'))
61 const QString expandedName = KShell::tildeExpand(name);
64 if (!expandedName.isEmpty())
72 class KNewFileMenuSingleton
75 KNewFileMenuSingleton()
83 ~KNewFileMenuSingleton()
103 enum EntryType {
Unknown, LinkToTemplate = 1, Template, Separator };
129 EntryList * templatesList;
136 int templatesVersion;
139 void KNewFileMenuSingleton::parseFiles()
143 KNewFileMenuSingleton::EntryList::iterator templ = templatesList->begin();
144 const KNewFileMenuSingleton::EntryList::iterator templ_end = templatesList->end();
145 for (; templ != templ_end; ++templ)
148 QString filePath = (*templ).filePath;
149 if (!filePath.isEmpty())
157 text = desktopFile.readName();
158 (*templ).icon = desktopFile.readIcon();
159 (*templ).comment = desktopFile.readComment();
160 QString type = desktopFile.readType();
163 templatePath = desktopFile.desktopGroup().readPathEntry(
"URL",
QString());
164 if (templatePath[0] !=
'/' && !templatePath.startsWith(
"__"))
166 if (templatePath.startsWith(
"file:/"))
171 QString linkDir = filePath.left(filePath.lastIndexOf(
'/') + 1 );
173 templatePath = linkDir + templatePath;
177 if (templatePath.isEmpty())
180 (*templ).entryType = KNewFileMenuSingleton::Template;
181 (*templ).templatePath = (*templ).filePath;
183 (*templ).entryType = KNewFileMenuSingleton::LinkToTemplate;
184 (*templ).templatePath = templatePath;
191 if (text.endsWith(
".desktop"))
192 text.truncate(text.length() - 8);
194 (*templ).text = text;
200 (*templ).entryType = KNewFileMenuSingleton::Separator;
207 class KNewFileMenuCopyData
210 KNewFileMenuCopyData() { m_isSymlink =
false;}
211 ~KNewFileMenuCopyData() {}
212 QString chosenFileName()
const {
return m_chosenFileName; }
215 QString sourceFileToCopy()
const {
return m_src; }
216 QString tempFileToDelete()
const {
return m_tempFileToDelete; }
225 class KNewFileMenuPrivate
229 : m_menuItemsVersion(0),
231 m_viewShowsHiddenFiles(false),
235 bool checkSourceExists(
const QString& src);
240 void confirmCreatingHiddenDir(
const QString& name);
245 void executeOtherDesktopFile(
const KNewFileMenuSingleton::Entry& entry);
250 void executeRealFileOrDir(
const KNewFileMenuSingleton::Entry& entry);
255 void executeStrategy();
260 void executeSymLink(
const KNewFileMenuSingleton::Entry& entry);
265 void executeUrlDesktopFile(
const KNewFileMenuSingleton::Entry& entry);
275 void _k_slotAbortDialog();
280 void _k_slotActionTriggered(
QAction* action);
285 void _k_slotCreateDirectory(
bool writeHiddenDir =
false);
291 void _k_slotCreateHiddenDirectory();
296 void _k_slotFillTemplates();
302 void _k_slotOtherDesktopFile();
308 void _k_slotRealFileOrDir();
314 void _k_slotTextChanged(
const QString & text);
320 void _k_slotSymLink();
326 void _k_slotUrlDesktopFile();
333 int m_menuItemsVersion;
340 QActionGroup* m_newMenuGroup;
352 bool m_viewShowsHiddenFiles;
356 KNewFileMenuCopyData m_copyData;
359 bool KNewFileMenuPrivate::checkSourceExists(
const QString& src)
361 if (!QFile::exists(src)) {
362 kWarning(1203) << src <<
"doesn't exist" ;
365 dialog->setCaption(
i18n(
"Sorry") );
366 dialog->setButtons( KDialog::Ok );
367 dialog->setObjectName(
"sorry" );
368 dialog->setModal(q->isModal());
369 dialog->setAttribute(Qt::WA_DeleteOnClose);
370 dialog->setDefaultButton( KDialog::Ok );
371 dialog->setEscapeButton( KDialog::Ok );
374 i18n(
"<qt>The template file <b>%1</b> does not exist.</qt>", src),
385 void KNewFileMenuPrivate::confirmCreatingHiddenDir(
const QString& name)
388 _k_slotCreateHiddenDirectory();
392 KGuiItem continueGuiItem(KStandardGuiItem::cont());
393 continueGuiItem.setText(
i18nc(
"@action:button",
"Create directory"));
394 KGuiItem cancelGuiItem(KStandardGuiItem::cancel());
395 cancelGuiItem.setText(
i18nc(
"@action:button",
"Enter a different name"));
398 confirmDialog->setCaption(
i18n(
"Create hidden directory?"));
399 confirmDialog->setModal(m_modal);
400 confirmDialog->setAttribute(Qt::WA_DeleteOnClose);
402 i18n(
"The name \"%1\" starts with a dot, so the directory will be hidden by default.", name),
404 i18n(
"Do not ask again"),
408 confirmDialog->setButtonGuiItem(KDialog::Ok, continueGuiItem);
409 confirmDialog->setButtonGuiItem(KDialog::Cancel, cancelGuiItem);
411 QObject::connect(confirmDialog, SIGNAL(accepted()), q, SLOT(_k_slotCreateHiddenDirectory()));
412 QObject::connect(confirmDialog, SIGNAL(rejected()), q, SLOT(createDirectory()));
414 m_fileDialog = confirmDialog;
415 confirmDialog->show();
419 void KNewFileMenuPrivate::executeOtherDesktopFile(
const KNewFileMenuSingleton::Entry& entry)
421 if (!checkSourceExists(entry.templatePath)) {
425 KUrl::List::const_iterator it = m_popupFiles.constBegin();
426 for (; it != m_popupFiles.constEnd(); ++it)
430 text = text.trimmed();
434 KUrl defaultFile(*it);
435 defaultFile.addPath(KIO::encodeFileName(text));
436 if (defaultFile.isLocalFile() && QFile::exists(defaultFile.toLocalFile()))
439 const KUrl templateUrl(entry.templatePath);
442 dlg->setModal(q->isModal());
443 dlg->setAttribute(Qt::WA_DeleteOnClose);
444 QObject::connect(dlg, SIGNAL(applied()), q, SLOT(_k_slotOtherDesktopFile()));
450 void KNewFileMenuPrivate::executeRealFileOrDir(
const KNewFileMenuSingleton::Entry& entry)
456 text = text.trimmed();
457 m_copyData.m_src = entry.templatePath;
459 KUrl defaultFile(m_popupFiles.first());
460 defaultFile.
addPath(KIO::encodeFileName(text));
461 if (defaultFile.isLocalFile() && QFile::exists(defaultFile.toLocalFile()))
465 fileDialog->setAttribute(Qt::WA_DeleteOnClose);
466 fileDialog->setModal(q->isModal());
467 fileDialog->setButtons(KDialog::Ok | KDialog::Cancel);
470 QVBoxLayout *layout =
new QVBoxLayout(mainWidget);
480 _k_slotTextChanged(text);
481 QObject::connect(lineEdit, SIGNAL(textChanged(
QString)), q, SLOT(_k_slotTextChanged(
QString)));
483 layout->addWidget(label);
484 layout->addWidget(lineEdit);
486 fileDialog->setMainWidget(mainWidget);
487 QObject::connect(fileDialog, SIGNAL(accepted()), q, SLOT(_k_slotRealFileOrDir()));
488 QObject::connect(fileDialog, SIGNAL(rejected()), q, SLOT(_k_slotAbortDialog()));
491 lineEdit->selectAll();
492 lineEdit->setFocus();
495 void KNewFileMenuPrivate::executeSymLink(
const KNewFileMenuSingleton::Entry& entry)
498 dlg->setModal(q->isModal());
499 dlg->setAttribute(Qt::WA_DeleteOnClose);
500 dlg->setCaption(
i18n(
"Create Symlink"));
502 QObject::connect(dlg, SIGNAL(accepted()), q, SLOT(_k_slotSymLink()));
506 void KNewFileMenuPrivate::executeStrategy()
508 m_tempFileToDelete = m_copyData.tempFileToDelete();
509 const QString src = m_copyData.sourceFileToCopy();
515 if (uSrc.isLocalFile()) {
520 uSrc.setPath(item.linkDest());
522 if (!m_copyData.m_isSymlink) {
525 QFile srcFile(uSrc.toLocalFile());
526 if (srcFile.open(QIODevice::ReadOnly)) {
528 KMimeType::Ptr mime = KMimeType::findByNameAndContent(m_copyData.m_chosenFileName, srcFile.read(1024));
530 if (!mime->is(wantedMime->name()))
531 chosenFileName += wantedMime->mainExtension();
538 KUrl::List::const_iterator it = m_popupFiles.constBegin();
539 for (; it != m_popupFiles.constEnd(); ++it)
542 dest.addPath(KIO::encodeFileName(chosenFileName));
547 if (m_copyData.m_isSymlink) {
548 kjob = KIO::symlink(src, dest);
559 kjob->ui()->setWindow(m_parentWidget);
560 QObject::connect(kjob, SIGNAL(result(
KJob*)), q, SLOT(slotResult(
KJob*)));
564 void KNewFileMenuPrivate::executeUrlDesktopFile(
const KNewFileMenuSingleton::Entry& entry)
567 m_copyData.m_templatePath = entry.templatePath;
568 dlg->setModal(q->isModal());
569 dlg->setAttribute(Qt::WA_DeleteOnClose);
570 dlg->setCaption(
i18n(
"Create link to URL"));
572 QObject::connect(dlg, SIGNAL(accepted()), q, SLOT(_k_slotUrlDesktopFile()));
576 void KNewFileMenuPrivate::fillMenu()
578 QMenu* menu = q->menu();
580 m_menuDev->menu()->clear();
589 KNewFileMenuSingleton* s = kNewMenuGlobals;
591 KNewFileMenuSingleton::EntryList::iterator templ = s->templatesList->begin();
592 const KNewFileMenuSingleton::EntryList::iterator templ_end = s->templatesList->end();
593 for (; templ != templ_end; ++templ, ++i)
595 KNewFileMenuSingleton::Entry& entry = *templ;
596 if (entry.entryType != KNewFileMenuSingleton::Separator) {
603 const bool bSkip = seenTexts.contains(entry.text);
605 kDebug(1203) <<
"skipping" << entry.filePath;
607 seenTexts.insert(entry.text);
610 const QString templatePath = entry.templatePath;
612 if (templatePath.endsWith(
"emptydir")) {
614 m_newDirAction = act;
615 act->setIcon(
KIcon(entry.icon));
616 act->setText(
i18nc(
"@item:inmenu Create New",
"%1", entry.text));
617 act->setActionGroup(m_newMenuGroup);
618 menu->addAction(act);
621 sep->setSeparator(
true);
622 menu->addAction(sep);
625 if (!m_supportedMimeTypes.isEmpty()) {
629 const bool createSymlink = entry.templatePath ==
"__CREATE_SYMLINK__";
636 if (entry.mimeType.isEmpty()) {
637 mime = KMimeType::findByPath(entry.templatePath);
640 entry.mimeType = mime->name();
642 entry.mimeType = KMimeType::defaultMimeType();
645 mime = KMimeType::mimeType(entry.mimeType);
647 Q_FOREACH(
const QString& supportedMime, m_supportedMimeTypes) {
648 if (mime && mime->is(supportedMime)) {
663 act->setIcon(
KIcon(entry.icon));
664 act->setText(
i18nc(
"@item:inmenu Create New",
"%1", entry.text));
665 act->setActionGroup(m_newMenuGroup);
669 if (templatePath.endsWith(
"/URL.desktop")) {
671 }
else if (templatePath.endsWith(
"/Program.desktop")) {
673 }
else if (entry.filePath.endsWith(
"/linkPath.desktop")) {
677 if (df.readType() ==
"FSDevice")
678 m_menuDev->menu()->addAction(act);
680 menu->addAction(act);
684 menu->addAction(act);
689 Q_ASSERT(entry.entryType != 0);
692 sep->setSeparator(
true);
693 menu->addAction(sep);
697 if (m_supportedMimeTypes.isEmpty()) {
699 sep->setSeparator(
true);
700 menu->addAction(sep);
701 if (linkURL) menu->addAction(linkURL);
702 if (linkPath) menu->addAction(linkPath);
703 if (linkApp) menu->addAction(linkApp);
705 menu->addAction(m_menuDev);
709 void KNewFileMenuPrivate::_k_slotAbortDialog()
714 void KNewFileMenuPrivate::_k_slotActionTriggered(
QAction* action)
718 if (action == m_newDirAction) {
719 q->createDirectory();
722 const int id = action->data().toInt();
725 KNewFileMenuSingleton* s = kNewMenuGlobals;
726 const KNewFileMenuSingleton::Entry entry = s->templatesList->at(
id - 1);
728 const bool createSymlink = entry.templatePath ==
"__CREATE_SYMLINK__";
730 m_copyData = KNewFileMenuCopyData();
733 m_copyData.m_isSymlink =
true;
734 executeSymLink(entry);
738 if (df.readType() ==
"Link") {
739 executeUrlDesktopFile(entry);
741 executeOtherDesktopFile(entry);
745 executeRealFileOrDir(entry);
750 void KNewFileMenuPrivate::_k_slotCreateDirectory(
bool writeHiddenDir)
753 KUrl baseUrl = m_popupFiles.first();
754 bool askAgain =
false;
758 if (!name.isEmpty()) {
759 if ((name[0] ==
'/'))
762 if (!m_viewShowsHiddenFiles && name.startsWith(
'.')) {
763 if (!writeHiddenDir) {
764 confirmCreatingHiddenDir(name);
768 name = KIO::encodeFileName( name );
776 job->setProperty(
"isMkdirJob",
true);
777 job->ui()->setWindow(m_parentWidget);
778 job->ui()->setAutoErrorHandlingEnabled(
true);
783 job->ui()->setAutoErrorHandlingEnabled(
false);
784 QObject::connect(job, SIGNAL(result(
KJob*)), q, SLOT(slotResult(
KJob*)));
788 q->createDirectory();
790 _k_slotAbortDialog();
793 void KNewFileMenuPrivate::_k_slotCreateHiddenDirectory()
795 _k_slotCreateDirectory(
true);
798 void KNewFileMenuPrivate::_k_slotFillTemplates()
800 KNewFileMenuSingleton* s = kNewMenuGlobals;
806 for (QStringList::const_iterator it = dirs.constBegin() ; it != dirs.constEnd() ; ++it) {
808 s->dirWatch->addDir(*it);
810 QObject::connect(s->dirWatch, SIGNAL(dirty(
QString)),
811 q, SLOT(_k_slotFillTemplates()));
812 QObject::connect(s->dirWatch, SIGNAL(created(
QString)),
813 q, SLOT(_k_slotFillTemplates()));
814 QObject::connect(s->dirWatch, SIGNAL(deleted(
QString)),
815 q, SLOT(_k_slotFillTemplates()));
818 ++s->templatesVersion;
819 s->filesParsed =
false;
821 s->templatesList->clear();
824 const QStringList files = m_actionCollection->componentData().dirs()->findAllResources(
"templates");
826 Q_FOREACH(
const QString& file, files) {
828 if (file[0] !=
'.') {
829 KNewFileMenuSingleton::Entry e;
831 e.entryType = KNewFileMenuSingleton::Unknown;
839 if (file.endsWith(
"Directory.desktop")) {
841 }
else if (file.endsWith(
"TextFile.desktop")) {
846 slist.insert(key, e);
849 (*s->templatesList) += slist.values();
852 void KNewFileMenuPrivate::_k_slotOtherDesktopFile()
857 void KNewFileMenuPrivate::_k_slotRealFileOrDir()
859 m_copyData.m_chosenFileName = m_text;
860 _k_slotAbortDialog();
864 void KNewFileMenuPrivate::_k_slotSymLink()
868 m_copyData.m_chosenFileName = dlg->
name();
871 if (m_copyData.m_chosenFileName.isEmpty() || linkUrl.isEmpty())
874 if (linkUrl.isRelative())
875 m_copyData.m_src = linkUrl.
url();
880 dialog->setCaption(
i18n(
"Sorry") );
881 dialog->setButtons( KDialog::Ok );
882 dialog->setObjectName(
"sorry" );
883 dialog->setModal(m_modal);
884 dialog->setAttribute(Qt::WA_DeleteOnClose);
885 dialog->setDefaultButton( KDialog::Ok );
886 dialog->setEscapeButton( KDialog::Ok );
887 m_fileDialog = dialog;
890 i18n(
"Basic links can only point to local files or directories.\nPlease use \"Link to Location\" for remote URLs."),
900 void KNewFileMenuPrivate::_k_slotTextChanged(
const QString & text)
905 void KNewFileMenuPrivate::_k_slotUrlDesktopFile()
909 m_copyData.m_chosenFileName = dlg->
name();
921 linkUrl = uriData.
uri();
924 if (m_copyData.m_chosenFileName.isEmpty() || linkUrl.isEmpty())
930 tmpFile.setAutoRemove(
false);
931 if (!tmpFile.open()) {
932 kError() <<
"Couldn't create temp file!";
936 if (!checkSourceExists(m_copyData.m_templatePath)) {
941 QFile file(m_copyData.m_templatePath);
942 if (!file.open(QIODevice::ReadOnly)) {
943 kError() <<
"Couldn't open template" << m_copyData.m_templatePath;
946 const QByteArray data = file.readAll();
948 const QString tempFileName = tmpFile.fileName();
949 Q_ASSERT(!tempFileName.isEmpty());
959 m_copyData.m_src = tempFileName;
960 m_copyData.m_tempFileToDelete = tempFileName;
967 d(new KNewFileMenuPrivate(this))
971 d->m_newMenuGroup =
new QActionGroup(
this);
973 d->m_actionCollection = collection;
974 d->m_parentWidget = qobject_cast<
QWidget*>(parent);
975 d->m_newDirAction = 0;
977 d->m_actionCollection->addAction(name,
this);
990 KNewFileMenuSingleton* s = kNewMenuGlobals;
993 if (d->m_menuItemsVersion < s->templatesVersion || s->templatesVersion == 0) {
997 foreach (
QAction* action, d->m_newMenuGroup->actions())
1000 if (!s->templatesList) {
1002 d->_k_slotFillTemplates();
1008 if (!s->filesParsed) {
1014 d->m_menuItemsVersion = s->templatesVersion;
1020 if (d->m_popupFiles.isEmpty())
1023 KUrl baseUrl = d->m_popupFiles.first();
1024 QString name = d->m_text.isEmpty()?
i18nc(
"Default name for a new folder",
"New Folder") :
1031 fileDialog->setModal(
isModal());
1032 fileDialog->setAttribute(Qt::WA_DeleteOnClose);
1033 fileDialog->setButtons(KDialog::Ok | KDialog::Cancel);
1034 fileDialog->setCaption(
i18nc(
"@title:window",
"New Folder"));
1037 QVBoxLayout *layout =
new QVBoxLayout(mainWidget);
1047 d->_k_slotTextChanged(name);
1048 connect(lineEdit, SIGNAL(textChanged(
QString)),
this, SLOT(_k_slotTextChanged(
QString)));
1049 layout->addWidget(label);
1050 layout->addWidget(lineEdit);
1052 fileDialog->setMainWidget(mainWidget);
1053 connect(fileDialog, SIGNAL(accepted()),
this, SLOT(_k_slotCreateDirectory()));
1054 connect(fileDialog, SIGNAL(rejected()),
this, SLOT(_k_slotAbortDialog()));
1056 d->m_fileDialog = fileDialog;
1059 lineEdit->selectAll();
1060 lineEdit->setFocus();
1070 return d->m_popupFiles;
1080 d->m_popupFiles = files;
1081 if (files.isEmpty()) {
1082 d->m_newMenuGroup->setEnabled(
false);
1084 KUrl firstUrl = files.first();
1086 d->m_newMenuGroup->setEnabled(
true);
1087 if (d->m_newDirAction) {
1091 d->m_newMenuGroup->setEnabled(
true);
1099 d->m_parentWidget = parentWidget;
1104 d->m_supportedMimeTypes = mime;
1109 d->m_viewShowsHiddenFiles = b;
1115 static_cast<KIO::Job*
>(job)->ui()->showErrorMessage();
1127 }
else if (
KIO::SimpleJob* simpleJob = ::qobject_cast<KIO::SimpleJob*>(job)) {
1129 if (simpleJob->property(
"isMkdirJob").toBool() ==
true) {
1130 kDebug() <<
"Emit directoryCreated" << simpleJob->url();
1137 if (!d->m_tempFileToDelete.isEmpty())
1138 QFile::remove(d->m_tempFileToDelete);
1144 return d->m_supportedMimeTypes;
1148 #include "knewfilemenu.moc"