libkonq Library API Documentation

knewmenu.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00016    Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include <qdir.h>
00020 
00021 #include <kdebug.h>
00022 #include <kdesktopfile.h>
00023 #include <kdirwatch.h>
00024 #include <kinstance.h>
00025 #include <klineeditdlg.h>
00026 #include <klocale.h>
00027 #include <kmessagebox.h>
00028 #include <kstandarddirs.h>
00029 #include <kprotocolinfo.h>
00030 #include <kpopupmenu.h>
00031 
00032 #include <kio/job.h>
00033 
00034 #include <kpropertiesdialog.h>
00035 //#include <konq_dirwatcher_stub.h>
00036 #include "konq_undo.h"
00037 #include "knewmenu.h"
00038 #include <utime.h>
00039 
00040 // For KURLDesktopFileDlg
00041 #include <qlayout.h>
00042 #include <qhbox.h>
00043 #include <klineedit.h>
00044 #include <kurlrequester.h>
00045 #include <qlabel.h>
00046 
00047 QValueList<KNewMenu::Entry> * KNewMenu::s_templatesList = 0L;
00048 int KNewMenu::s_templatesVersion = 0;
00049 bool KNewMenu::s_filesParsed = false;
00050 KDirWatch * KNewMenu::s_pDirWatch = 0L;
00051 
00052 class KNewMenu::KNewMenuPrivate
00053 {
00054 public:
00055     KNewMenuPrivate() : m_parentWidget(0) {}
00056     KActionCollection * m_actionCollection;
00057     QString m_destPath;
00058     QWidget *m_parentWidget;
00059 };
00060 
00061 KNewMenu::KNewMenu( KActionCollection * _collec, const char *name ) :
00062   KActionMenu( i18n( "Create Ne&w" ), "filenew", _collec, name ),
00063   menuItemsVersion( 0 )
00064 {
00065     //kdDebug(1203) << "KNewMenu::KNewMenu " << this << endl;
00066   // Don't fill the menu yet
00067   // We'll do that in slotCheckUpToDate (should be connected to abouttoshow)
00068     d = new KNewMenuPrivate;
00069     d->m_actionCollection = _collec;
00070 }
00071 
00072 KNewMenu::KNewMenu( KActionCollection * _collec, QWidget *parentWidget, const char *name ) :
00073   KActionMenu( i18n( "Create Ne&w" ), "filenew", _collec, name ),
00074   menuItemsVersion( 0 )
00075 {
00076     d = new KNewMenuPrivate;
00077     d->m_actionCollection = _collec;
00078     d->m_parentWidget = parentWidget;
00079 }
00080 
00081 KNewMenu::~KNewMenu()
00082 {
00083     //kdDebug(1203) << "KNewMenu::~KNewMenu " << this << endl;
00084     delete d;
00085 }
00086 
00087 void KNewMenu::slotCheckUpToDate( )
00088 {
00089     //kdDebug(1203) << "KNewMenu::slotCheckUpToDate() " << this
00090     //              << " : menuItemsVersion=" << menuItemsVersion
00091     //              << " s_templatesVersion=" << s_templatesVersion << endl;
00092     if (menuItemsVersion < s_templatesVersion || s_templatesVersion == 0)
00093     {
00094         //kdDebug(1203) << "KNewMenu::slotCheckUpToDate() : recreating actions" << endl;
00095         // We need to clean up the action collection
00096         // We look for our actions using the group
00097         QValueList<KAction*> actions = d->m_actionCollection->actions( "KNewMenu" );
00098         for( QValueListIterator<KAction*> it = actions.begin(); it != actions.end(); ++it )
00099         {
00100             remove( *it );
00101             d->m_actionCollection->remove( *it );
00102         }
00103 
00104         if (!s_templatesList) { // No templates list up to now
00105             s_templatesList = new QValueList<Entry>();
00106             slotFillTemplates();
00107             parseFiles();
00108         }
00109 
00110         // This might have been already done for other popupmenus,
00111         // that's the point in s_filesParsed.
00112         if ( !s_filesParsed )
00113             parseFiles();
00114 
00115         fillMenu();
00116 
00117         menuItemsVersion = s_templatesVersion;
00118     }
00119 }
00120 
00121 void KNewMenu::parseFiles()
00122 {
00123     //kdDebug(1203) << "KNewMenu::parseFiles()" << endl;
00124     s_filesParsed = true;
00125     QValueList<Entry>::Iterator templ = s_templatesList->begin();
00126     for ( /*++templ*/; templ != s_templatesList->end(); ++templ)
00127     {
00128         QString iconname;
00129         QString filePath = (*templ).filePath;
00130         if ( !filePath.isEmpty() )
00131         {
00132             QString text;
00133             QString templatePath;
00134             // If a desktop file, then read the name from it.
00135             // Otherwise (or if no name in it?) use file name
00136             if ( KDesktopFile::isDesktopFile( filePath ) ) {
00137                 KSimpleConfig config( filePath, true );
00138                 config.setDesktopGroup();
00139                 text = config.readEntry("Name");
00140                 (*templ).icon = config.readEntry("Icon");
00141                 (*templ).comment = config.readEntry("Comment");
00142                 QString type = config.readEntry( "Type" );
00143                 if ( type == "Link" )
00144                 {
00145                     templatePath = config.readPathEntry("URL");
00146                     if ( templatePath[0] != '/' )
00147                     {
00148                         if ( templatePath.left(6) == "file:/" )
00149                             templatePath = templatePath.right( templatePath.length() - 6 );
00150                         else
00151                         {
00152                             // A relative path, then (that's the default in the files we ship)
00153                             QString linkDir = filePath.left( filePath.findRev( '/' ) + 1 /*keep / */ );
00154                             //kdDebug(1203) << "linkDir=" << linkDir << endl;
00155                             templatePath = linkDir + templatePath;
00156                         }
00157                     }
00158                 }
00159                 if ( templatePath.isEmpty() )
00160                 {
00161                     // No dest, this is an old-style template
00162                     (*templ).entryType = TEMPLATE;
00163                     (*templ).templatePath = (*templ).filePath; // we'll copy the file
00164                 } else {
00165                     (*templ).entryType = LINKTOTEMPLATE;
00166                     (*templ).templatePath = templatePath;
00167                 }
00168 
00169             }
00170             if (text.isEmpty())
00171             {
00172                 text = KURL(filePath).fileName();
00173                 if ( text.right(8) == ".desktop" )
00174                     text.truncate( text.length() - 8 );
00175                 else if ( text.right(7) == ".kdelnk" )
00176                     text.truncate( text.length() - 7 );
00177             }
00178             (*templ).text = text;
00179             /*kdDebug(1203) << "Updating entry with text=" << text
00180                           << " entryType=" << (*templ).entryType
00181                           << " templatePath=" << (*templ).templatePath << endl;*/
00182         }
00183         else {
00184             (*templ).entryType = SEPARATOR;
00185         }
00186     }
00187 }
00188 
00189 void KNewMenu::fillMenu()
00190 {
00191     //kdDebug(1203) << "KNewMenu::fillMenu()" << endl;
00192     popupMenu()->clear();
00193     //KAction * act = new KAction( i18n( "Folder" ), 0, this, SLOT( slotNewFile() ),
00194     //                              d->m_actionCollection, QString("newmenu1") );
00195 
00196     //act->setGroup( "KNewMenu" );
00197     //act->plug( popupMenu() );
00198 
00199     int i = 1; // was 2 when there was Folder
00200     QValueList<Entry>::Iterator templ = s_templatesList->begin();
00201     for ( ; templ != s_templatesList->end(); ++templ, ++i)
00202     {
00203         if ( (*templ).entryType != SEPARATOR )
00204         {
00205             // There might be a .desktop for that one already, if it's a kdelnk
00206             // This assumes we read .desktop files before .kdelnk files ...
00207 
00208             // In fact, we skip any second item that has the same text as another one.
00209             // Duplicates in a menu look bad in any case.
00210 
00211             bool bSkip = false;
00212 
00213             QValueList<KAction*> actions = d->m_actionCollection->actions();
00214             QValueListIterator<KAction*> it = actions.begin();
00215             for( ; it != actions.end() && !bSkip; ++it )
00216             {
00217                 if ( (*it)->text() == (*templ).text )
00218                 {
00219                     kdDebug(1203) << "KNewMenu: skipping " << (*templ).filePath << endl;
00220                     bSkip = true;
00221                 }
00222             }
00223 
00224             if ( !bSkip )
00225             {
00226                 KAction * act = new KAction( (*templ).text+"...", (*templ).icon, 0, this, SLOT( slotNewFile() ),
00227                                              d->m_actionCollection, QCString().sprintf("newmenu%d", i ) );
00228                 act->setGroup( "KNewMenu" );
00229                 act->plug( popupMenu() );
00230             }
00231         } else { // Separate system from personal templates
00232             Q_ASSERT( (*templ).entryType != 0 );
00233 
00234             KActionSeparator * act = new KActionSeparator();
00235             act->plug( popupMenu() );
00236         }
00237     }
00238 }
00239 
00240 void KNewMenu::slotFillTemplates()
00241 {
00242     //kdDebug(1203) << "KNewMenu::slotFillTemplates()" << endl;
00243     // Ensure any changes in the templates dir will call this
00244     if ( ! s_pDirWatch )
00245     {
00246         s_pDirWatch = new KDirWatch;
00247         QStringList dirs = d->m_actionCollection->instance()->dirs()->resourceDirs("templates");
00248         for ( QStringList::Iterator it = dirs.begin() ; it != dirs.end() ; ++it )
00249         {
00250             //kdDebug(1203) << "Templates resource dir: " << *it << endl;
00251             s_pDirWatch->addDir( *it );
00252         }
00253         connect ( s_pDirWatch, SIGNAL( dirty( const QString & ) ),
00254                   this, SLOT ( slotFillTemplates() ) );
00255         connect ( s_pDirWatch, SIGNAL( created( const QString & ) ),
00256                   this, SLOT ( slotFillTemplates() ) );
00257         connect ( s_pDirWatch, SIGNAL( deleted( const QString & ) ),
00258                   this, SLOT ( slotFillTemplates() ) );
00259         // Ok, this doesn't cope with new dirs in KDEDIRS, but that's another story
00260     }
00261     s_templatesVersion++;
00262     s_filesParsed = false;
00263 
00264     s_templatesList->clear();
00265     //s_templatesList->append( "Folder" );
00266 
00267     // Look into "templates" dirs.
00268     QStringList files = d->m_actionCollection->instance()->dirs()->findAllResources("templates");
00269     for ( QStringList::Iterator it = files.begin() ; it != files.end() ; ++it )
00270     {
00271         //kdDebug(1203) << *it << endl;
00272         if ( (*it)[0] != '.' )
00273         {
00274             Entry e;
00275             e.filePath = *it;
00276             e.entryType = 0; // not parsed yet
00277             // put Directory first in the list (a bit hacky)
00278             if ( (*it).endsWith( "Directory.desktop" ) )
00279                 s_templatesList->prepend( e );
00280             else
00281                 s_templatesList->append( e );
00282         }
00283     }
00284 }
00285 
00286 void KNewMenu::slotNewFile()
00287 {
00288     int id = QString( sender()->name() + 7 ).toInt(); // skip "newmenu"
00289     if (id == 0) return;
00290 
00291     emit activated(); // for KDIconView::slotNewMenuActivated()
00292 
00293     Entry entry = *(s_templatesList->at( id - 1 ));
00294     //kdDebug(1203) << QString("sFile = %1").arg(sFile) << endl;
00295 
00296     //if ( sName != "Folder" ) {
00297     if ( !QFile::exists( entry.templatePath ) ) {
00298           kdWarning(1203) << entry.templatePath << " doesn't exist" << endl;
00299           KMessageBox::sorry( 0L, i18n("The templates file %1 doesn't exist!").arg(entry.templatePath));
00300           return;
00301     }
00302     m_isURLDesktopFile = false;
00303     QString name;
00304     if ( KDesktopFile::isDesktopFile( entry.templatePath ) )
00305     {
00306         KDesktopFile df( entry.templatePath );
00307         //kdDebug(1203) <<  df.readType() << endl;
00308         if ( df.readType() == "Link" )
00309         {
00310             m_isURLDesktopFile = true;
00311             // entry.comment contains i18n("Enter link to location (URL):"). JFYI :)
00312             KURLDesktopFileDlg dlg( i18n("File name:"), entry.comment, d->m_parentWidget );
00313             // TODO dlg.setCaption( i18n( ... ) );
00314             if ( dlg.exec() )
00315             {
00316                 name = dlg.fileName();
00317                 m_linkURL = dlg.url();
00318                 if ( name.isEmpty() || m_linkURL.isEmpty() )
00319                     return;
00320                 if ( !name.endsWith( ".desktop" ) )
00321                     name += ".desktop";
00322             }
00323             else
00324                 return;
00325         }
00326         else
00327         {
00328           KURL::List::Iterator it = popupFiles.begin();
00329           for ( ; it != popupFiles.end(); ++it )
00330           {
00331               //kdDebug(1203) << "first arg=" << entry.templatePath << endl;
00332               //kdDebug(1203) << "second arg=" << (*it).url() << endl;
00333               //kdDebug(1203) << "third arg=" << entry.text << endl;
00334               (void) new KPropertiesDialog( entry.templatePath, *it, entry.text, d->m_parentWidget );
00335           }
00336           return; // done, exit.
00337         }
00338     }
00339     else
00340     {
00341         // The template is not a desktop file
00342         // Show the small dialog for getting the destination filename
00343         KLineEditDlg dlg( entry.comment, entry.text, d->m_parentWidget );
00344         // TODO dlg.setCaption( i18n( ... ) );
00345         if ( dlg.exec() )
00346         {
00347             name = dlg.text();
00348             if ( name.isEmpty() )
00349                 return;
00350         }
00351         else
00352             return;
00353     }
00354 
00355     // The template is not a desktop file [or it's a URL one]
00356     // Copy it.
00357     KURL::List::Iterator it = popupFiles.begin();
00358     /*
00359     if ( sFile =="Folder" )
00360     {
00361         for ( ; it != popupFiles.end(); ++it )
00362         {
00363           QString url = (*it).path(1) + KIO::encodeFileName(name);
00364           KURL::encode(url); // hopefully will disappear with next KURL
00365           KIO::Job * job = KIO::mkdir( url );
00366           connect( job, SIGNAL( result( KIO::Job * ) ),
00367                    SLOT( slotResult( KIO::Job * ) ) );
00368         }
00369     }
00370     else
00371     {
00372     */
00373         QString src = entry.templatePath;
00374         for ( ; it != popupFiles.end(); ++it )
00375         {
00376             KURL dest( *it );
00377             dest.addPath( KIO::encodeFileName(name) ); // Chosen destination file name
00378             d->m_destPath = dest.path(); // will only be used if m_isURLDesktopFile and dest is local
00379 
00380             KURL uSrc;
00381             uSrc.setPath( src );
00382             //kdDebug(1203) << "KNewMenu : KIO::copyAs( " << uSrc.url() << ", " << dest.url() << ")" << endl;
00383             KIO::Job * job = KIO::copyAs( uSrc, dest );
00384             connect( job, SIGNAL( result( KIO::Job * ) ),
00385                      SLOT( slotResult( KIO::Job * ) ) );
00386             if ( m_isURLDesktopFile )
00387                 connect( job, SIGNAL( renamed( KIO::Job *, const KURL&, const KURL& ) ),
00388                      SLOT( slotRenamed( KIO::Job *, const KURL&, const KURL& ) ) );
00389             KURL::List lst;
00390             lst.append( uSrc );
00391             (void)new KonqCommandRecorder( KonqCommand::COPY, lst, dest, job );
00392         }
00393     //}
00394 }
00395 
00396 // Special case (filename conflict when creating a link=url file)
00397 // We need to update m_destURL
00398 void KNewMenu::slotRenamed( KIO::Job *, const KURL& from , const KURL& to )
00399 {
00400     if ( from.isLocalFile() )
00401     {
00402         kdDebug() << k_funcinfo << from.prettyURL() << " -> " << to.prettyURL() << " ( m_destPath=" << d->m_destPath << ")" << endl;
00403         Q_ASSERT( from.path() == d->m_destPath );
00404         d->m_destPath = to.path();
00405     }
00406 }
00407 
00408 void KNewMenu::slotResult( KIO::Job * job )
00409 {
00410     if (job->error())
00411         job->showErrorDialog();
00412     else
00413     {
00414         KURL destURL = static_cast<KIO::CopyJob*>(job)->destURL();
00415         if ( destURL.isLocalFile() )
00416         {
00417             if ( m_isURLDesktopFile )
00418             {
00419                 // destURL is the original destination for the new file.
00420                 // But in case of a renaming (due to a conflict), the real path is in m_destPath
00421                 kdDebug(1203) << " destURL=" << destURL.path() << " " << " d->m_destPath=" << d->m_destPath << endl;
00422                 KDesktopFile df( d->m_destPath );
00423                 df.writeEntry( "Icon", KProtocolInfo::icon( KURL(m_linkURL).protocol() ) );
00424                 df.writeEntry( "URL", m_linkURL );
00425                 df.sync();
00426             }
00427             else
00428             {
00429                 // Normal (local) file. Need to "touch" it, kio_file copied the mtime.
00430                 (void) ::utime( QFile::encodeName( destURL.path() ), 0 );
00431             }
00432         }
00433     }
00434 }
00435 
00437 
00438 KURLDesktopFileDlg::KURLDesktopFileDlg( const QString& textFileName, const QString& textUrl )
00439     : KDialogBase( Plain, QString::null, Ok|Cancel|User1, Ok, 0L /*parent*/, 0L, true,
00440                    true, KStdGuiItem::clear() )
00441 {
00442     initDialog( textFileName, QString::null, textUrl, QString::null );
00443 }
00444 
00445 KURLDesktopFileDlg::KURLDesktopFileDlg( const QString& textFileName, const QString& textUrl, QWidget *parent )
00446     : KDialogBase( Plain, QString::null, Ok|Cancel|User1, Ok, parent, 0L, true,
00447                    true, KStdGuiItem::clear() )
00448 {
00449     initDialog( textFileName, QString::null, textUrl, QString::null );
00450 }
00451 
00452 void KURLDesktopFileDlg::initDialog( const QString& textFileName, const QString& defaultName, const QString& textUrl, const QString& defaultUrl )
00453 {
00454     QVBoxLayout * topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() );
00455 
00456     // First line: filename
00457     QHBox * fileNameBox = new QHBox( plainPage() );
00458     topLayout->addWidget( fileNameBox );
00459 
00460     QLabel * label = new QLabel( textFileName, fileNameBox );
00461     m_leFileName = new KLineEdit( fileNameBox, 0L );
00462     m_leFileName->setMinimumWidth(m_leFileName->sizeHint().width() * 3);
00463     label->setBuddy(m_leFileName);  // please "scheck" style
00464     m_leFileName->setText( defaultName );
00465     m_leFileName->setSelection(0, m_leFileName->text().length()); // autoselect
00466     connect( m_leFileName, SIGNAL(textChanged(const QString&)),
00467              SLOT(slotNameTextChanged(const QString&)) );
00468 
00469     // Second line: url
00470     QHBox * urlBox = new QHBox( plainPage() );
00471     topLayout->addWidget( urlBox );
00472     label = new QLabel( textUrl, urlBox );
00473     m_urlRequester = new KURLRequester( defaultUrl, urlBox, "urlRequester" );
00474     m_urlRequester->setMode( KFile::File | KFile::Directory );
00475     
00476     m_urlRequester->setMinimumWidth( m_urlRequester->sizeHint().width() * 3 );
00477     topLayout->addWidget( m_urlRequester );
00478     connect( m_urlRequester->lineEdit(), SIGNAL(textChanged(const QString&)),
00479              SLOT(slotURLTextChanged(const QString&)) );
00480     label->setBuddy(m_urlRequester);  // please "scheck" style
00481 
00482     m_urlRequester->setFocus();
00483     enableButtonOK( !defaultName.isEmpty() && !defaultUrl.isEmpty() );
00484     connect( this, SIGNAL(user1Clicked()), this, SLOT(slotClear()) );
00485     m_fileNameEdited = false;
00486 }
00487 
00488 QString KURLDesktopFileDlg::url() const
00489 {
00490     if ( result() == QDialog::Accepted )
00491         return m_urlRequester->url();
00492     else
00493         return QString::null;
00494 }
00495 
00496 QString KURLDesktopFileDlg::fileName() const
00497 {
00498     if ( result() == QDialog::Accepted )
00499         return m_leFileName->text();
00500     else
00501         return QString::null;
00502 }
00503 
00504 void KURLDesktopFileDlg::slotClear()
00505 {
00506     m_leFileName->setText( QString::null );
00507     m_urlRequester->clear();
00508     m_fileNameEdited = false;
00509 }
00510 
00511 void KURLDesktopFileDlg::slotNameTextChanged( const QString& )
00512 {
00513     kdDebug() << k_funcinfo << endl;
00514     m_fileNameEdited = true;
00515     enableButtonOK( !m_leFileName->text().isEmpty() && !m_urlRequester->url().isEmpty() );
00516 }
00517 
00518 void KURLDesktopFileDlg::slotURLTextChanged( const QString& )
00519 {
00520     if ( !m_fileNameEdited )
00521     {
00522         // use URL as default value for the filename
00523         // (we copy only its filename if protocol supports listing,
00524         // but for HTTP we don't want tons of index.html links)
00525         KURL url( m_urlRequester->url() );
00526         if ( KProtocolInfo::supportsListing( url ) )
00527             m_leFileName->setText( url.fileName() );
00528         else
00529             m_leFileName->setText( url.url() );
00530         m_fileNameEdited = false; // slotNameTextChanged set it to true erroneously
00531     }
00532     enableButtonOK( !m_leFileName->text().isEmpty() && !m_urlRequester->url().isEmpty() );
00533 }
00534 
00535 
00536 #include "knewmenu.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Thu Jan 29 23:03:28 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001