1
/* This file is part of the KDE libraries
2
Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
3
David Faure <faure@kde.org>
4
2001,2006 Holger Freyther <freyther@kde.org>
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Library General Public
8
License as published by the Free Software Foundation; either
9
version 2 of the License, or (at your option) any later version.
11
This library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Library General Public License for more details.
16
You should have received a copy of the GNU Library General Public License
17
along with this library; see the file COPYING.LIB. If not, write to
18
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
Boston, MA 02110-1301, USA.
22
#include "kio/renamedialog.h"
23
#include "kio/renamedialogplugin.h"
27
#include <qdatetime.h>
28
#include <qfileinfo.h>
31
#include <qlineedit.h>
34
#include <kmessagebox.h>
35
#include <kpushbutton.h>
36
#include <kio/global.h>
37
#include <kmimetypetrader.h>
38
#include <klibloader.h>
44
#include <kmimetype.h>
45
#include <kseparator.h>
46
#include <kstringhandler.h>
47
#include <kstandardguiitem.h>
49
#include <ksqueezedtextlabel.h>
54
class RenameDialog::RenameDialogPrivate
57
RenameDialogPrivate(){
59
bRename = bSkip = bAutoSkip = bOverwrite = bOverwriteAll = 0;
60
bResume = bResumeAll = bSuggestNewName = 0;
66
QPushButton *bAutoSkip;
67
QPushButton *bOverwrite;
68
QPushButton *bOverwriteAll;
70
QPushButton *bResumeAll;
71
QPushButton *bSuggestNewName;
72
QLineEdit* m_pLineEdit;
80
RenameDialog::RenameDialog(QWidget *parent, const QString & _caption,
81
const KUrl &_src, const KUrl &_dest,
82
RenameDialog_Mode _mode,
83
KIO::filesize_t sizeSrc,
84
KIO::filesize_t sizeDest,
89
: QDialog ( parent ), d(new RenameDialogPrivate)
91
setObjectName( "KIO::RenameDialog" );
97
setWindowTitle( _caption );
99
d->bCancel = new KPushButton( KStandardGuiItem::cancel(), this );
100
connect(d->bCancel, SIGNAL(clicked()), this, SLOT(cancelPressed()));
102
if ( ! (_mode & M_NORENAME ) ) {
103
d->bRename = new QPushButton( i18n( "&Rename" ), this );
104
d->bRename->setEnabled(false);
105
d->bSuggestNewName = new QPushButton( i18n( "Suggest New &Name" ), this );
106
connect(d->bSuggestNewName, SIGNAL(clicked()), this, SLOT(suggestNewNamePressed()));
107
connect(d->bRename, SIGNAL(clicked()), this, SLOT(renamePressed()));
110
if ( ( _mode & M_MULTI ) && ( _mode & M_SKIP ) ) {
111
d->bSkip = new QPushButton( i18n( "&Skip" ), this );
112
connect(d->bSkip, SIGNAL(clicked()), this, SLOT(skipPressed()));
114
d->bAutoSkip = new QPushButton( i18n( "&Auto Skip" ), this );
115
connect(d->bAutoSkip, SIGNAL(clicked()), this, SLOT(autoSkipPressed()));
118
if ( _mode & M_OVERWRITE ) {
119
d->bOverwrite = new QPushButton( i18n( "&Overwrite" ), this );
120
connect(d->bOverwrite, SIGNAL(clicked()), this, SLOT(overwritePressed()));
122
if ( _mode & M_MULTI ) {
123
d->bOverwriteAll = new QPushButton( i18n( "O&verwrite All" ), this );
124
connect(d->bOverwriteAll, SIGNAL(clicked()), this, SLOT(overwriteAllPressed()));
128
if ( _mode & M_RESUME ) {
129
d->bResume = new QPushButton( i18n( "&Resume" ), this );
130
connect(d->bResume, SIGNAL(clicked()), this, SLOT(resumePressed()));
132
if ( _mode & M_MULTI )
134
d->bResumeAll = new QPushButton( i18n( "R&esume All" ), this );
135
connect(d->bResumeAll, SIGNAL(clicked()), this, SLOT(resumeAllPressed()));
139
QVBoxLayout* pLayout = new QVBoxLayout( this );
140
pLayout->setMargin( KDialog::marginHint() );
141
pLayout->setSpacing( KDialog::spacingHint() );
142
pLayout->addStrut( 360 ); // makes dlg at least that wide
144
// User tries to overwrite a file with itself ?
145
if ( _mode & M_OVERWRITE_ITSELF ) {
146
QLabel *lb = new QLabel( i18n( "This action would overwrite '%1' with itself.\n"
147
"Please enter a new file name:" , KStringHandler::csqueeze( d->src.pathOrUrl(),100 ) ), this );
148
d->bRename->setText(i18n("C&ontinue"));
149
pLayout->addWidget( lb );
151
else if ( _mode & M_OVERWRITE ) {
153
// Figure out the mimetype and load one plugin
154
// (This is the only mode that is handled by plugins)
156
KService::List plugin_offers;
157
if( d->mimeSrc != KMimeType::defaultMimeType() ){
158
plugin_offers = KMimeTypeTrader::self()->query(d->mimeSrc, "RenameDialog/Plugin");
160
}else if(d->mimeDest != KMimeType::defaultMimeType() ) {
161
plugin_offers = KMimeTypeTrader::self()->query(d->mimeDest, "RenameDialog/Plugin");
163
if(!plugin_offers.isEmpty() ){
164
RenameDialogPlugin::FileItem src( _src, d->mimeSrc, sizeSrc, ctimeSrc, mtimeSrc );
165
RenameDialogPlugin::FileItem dst( _dest,d->mimeDest, sizeDest, ctimeDest, mtimeDest );
166
kDebug(7024) << "Offers" << endl;
167
KService::List::ConstIterator it = plugin_offers.begin();
168
const KService::List::ConstIterator end = plugin_offers.end();
169
for( ; it != end; ++it ){
170
RenameDialogPlugin *plugin = KLibLoader::createInstance<RenameDialogPlugin>( (*it)->library().toLocal8Bit(), this );
174
plugin->setObjectName( (*it)->name() );
175
if( plugin->wantToHandle( _mode, src, dst ) ) {
177
plugin->handle( _mode, src, dst );
178
pLayout->addWidget(plugin );
179
kDebug(7024) << "RenameDialogPlugin" << endl;
189
// No plugin found, build default dialog
190
QGridLayout * gridLayout = new QGridLayout();
191
gridLayout->setMargin( KDialog::marginHint() );
192
gridLayout->setSpacing( KDialog::spacingHint() );
193
pLayout->addLayout(gridLayout);
194
gridLayout->setColumnStretch(0,0);
195
gridLayout->setColumnStretch(1,10);
198
if (mtimeDest < mtimeSrc)
199
sentence1 = i18n("An older item named '%1' already exists.", d->dest.pathOrUrl());
200
else if (mtimeDest == mtimeSrc)
201
sentence1 = i18n("A similar file named '%1' already exists.", d->dest.pathOrUrl());
203
sentence1 = i18n("A newer item named '%1' already exists.", d->dest.pathOrUrl());
205
QLabel * lb1 = new KSqueezedTextLabel( sentence1, this );
206
gridLayout->addWidget( lb1, 0, 0, 1, 2 ); // takes the complete first line
208
lb1 = new QLabel( this );
209
lb1->setPixmap( KIO::pixmapForUrl( d->dest ) );
210
gridLayout->addWidget( lb1, 1, 0, 3, 1 ); // takes the first column on rows 1-3
213
if ( sizeDest != (KIO::filesize_t)-1 )
215
QLabel * lb = new QLabel( i18n("size %1", KIO::convertSize(sizeDest) ), this );
216
gridLayout->addWidget( lb, row, 1 );
220
if ( ctimeDest != (time_t)-1 )
222
QDateTime dctime; dctime.setTime_t( ctimeDest );
223
QLabel * lb = new QLabel( i18n("created on %1", KGlobal::locale()->formatDateTime(dctime) ), this );
224
gridLayout->addWidget( lb, row, 1 );
227
if ( mtimeDest != (time_t)-1 )
229
QDateTime dmtime; dmtime.setTime_t( mtimeDest );
230
QLabel * lb = new QLabel( i18n("modified on %1", KGlobal::locale()->formatDateTime(dmtime) ), this );
231
gridLayout->addWidget( lb, row, 1 );
235
if ( !d->src.isEmpty() )
237
// rows 1 to 3 are the details (size/ctime/mtime), row 4 is empty
239
QLabel * lb2 = new KSqueezedTextLabel( i18n("The source file is '%1'", d->src.pathOrUrl()), this );
240
gridLayout->addWidget( lb2, 5, 0, 1, 2 ); // takes the complete first line
242
lb2 = new QLabel( this );
243
lb2->setPixmap( KIO::pixmapForUrl( d->src ) );
244
gridLayout->addWidget( lb2, 6, 0, 3, 1 ); // takes the first column on rows 6-8
248
if ( sizeSrc != (KIO::filesize_t)-1 )
250
QLabel * lb = new QLabel( i18n("size %1", KIO::convertSize(sizeSrc) ), this );
251
gridLayout->addWidget( lb, row, 1 );
254
if ( ctimeSrc != (time_t)-1 )
256
QDateTime dctime; dctime.setTime_t( ctimeSrc );
257
QLabel * lb = new QLabel( i18n("created on %1", KGlobal::locale()->formatDateTime(dctime) ), this );
258
gridLayout->addWidget( lb, row, 1 );
261
if ( mtimeSrc != (time_t)-1 )
263
QDateTime dmtime; dmtime.setTime_t( mtimeSrc );
264
QLabel * lb = new QLabel( i18n("modified on %1", KGlobal::locale()->formatDateTime(dmtime) ), this );
265
gridLayout->addWidget( lb, row, 1 );
273
// This is the case where we don't want to allow overwriting, the existing
274
// file must be preserved (e.g. when renaming).
276
if (mtimeDest < mtimeSrc)
277
sentence1 = i18n("An older item named '%1' already exists.", d->dest.pathOrUrl());
278
else if (mtimeDest == mtimeSrc)
279
sentence1 = i18n("A similar file named '%1' already exists.", d->dest.pathOrUrl());
281
sentence1 = i18n("A newer item named '%1' already exists.", d->dest.pathOrUrl());
283
QLabel *lb = new KSqueezedTextLabel( sentence1, this );
284
pLayout->addWidget(lb);
286
QHBoxLayout* layout2 = new QHBoxLayout();
287
pLayout->addLayout( layout2 );
289
d->m_pLineEdit = new QLineEdit( this );
290
layout2->addWidget( d->m_pLineEdit );
291
QString fileName = d->dest.fileName();
292
d->m_pLineEdit->setText( KIO::decodeFileName( fileName ) );
293
if ( d->bRename || d->bOverwrite )
294
connect(d->m_pLineEdit, SIGNAL(textChanged(const QString &)),
295
SLOT(enableRenameButton(const QString &)));
296
if ( d->bSuggestNewName )
298
layout2->addWidget( d->bSuggestNewName );
299
setTabOrder( d->m_pLineEdit, d->bSuggestNewName );
302
KSeparator* separator = new KSeparator( this );
303
pLayout->addWidget( separator );
305
QHBoxLayout* layout = new QHBoxLayout();
306
pLayout->addLayout( layout );
308
layout->addStretch(1);
312
layout->addWidget( d->bRename );
313
setTabOrder( d->bRename, d->bCancel );
317
layout->addWidget( d->bSkip );
318
setTabOrder( d->bSkip, d->bCancel );
322
layout->addWidget( d->bAutoSkip );
323
setTabOrder( d->bAutoSkip, d->bCancel );
327
layout->addWidget( d->bOverwrite );
328
setTabOrder( d->bOverwrite, d->bCancel );
330
if ( d->bOverwriteAll )
332
layout->addWidget( d->bOverwriteAll );
333
setTabOrder( d->bOverwriteAll, d->bCancel );
337
layout->addWidget( d->bResume );
338
setTabOrder( d->bResume, d->bCancel );
342
layout->addWidget( d->bResumeAll );
343
setTabOrder( d->bResumeAll, d->bCancel );
346
d->bCancel->setDefault( true );
347
layout->addWidget( d->bCancel );
349
resize( sizeHint() );
352
RenameDialog::~RenameDialog()
355
// no need to delete Pushbuttons,... qt will do this
358
void RenameDialog::enableRenameButton(const QString &newDest)
360
if ( newDest != KIO::decodeFileName( d->dest.fileName() ) && !newDest.isEmpty() )
362
d->bRename->setEnabled( true );
363
d->bRename->setDefault( true );
365
d->bOverwrite->setEnabled( false ); // prevent confusion (#83114)
369
d->bRename->setEnabled( false );
371
d->bOverwrite->setEnabled( true );
375
KUrl RenameDialog::newDestUrl()
377
KUrl newDest( d->dest );
378
QString fileName = d->m_pLineEdit->text();
379
newDest.setFileName( KIO::encodeFileName( fileName ) );
383
void RenameDialog::cancelPressed()
389
void RenameDialog::renamePressed()
391
if ( d->m_pLineEdit->text().isEmpty() )
394
KUrl u = newDestUrl();
397
KMessageBox::error( this, i18n( "Malformed URL\n%1" , u.url() ) );
404
QString RenameDialog::suggestName(const KUrl& baseURL, const QString& oldName)
406
QString dotSuffix, suggestedName;
407
QString basename = oldName;
409
int index = basename.indexOf( '.' );
411
dotSuffix = basename.mid( index );
412
basename.truncate( index );
415
int pos = basename.lastIndexOf( '_' );
417
QString tmp = basename.mid( pos+1 );
419
int number = tmp.toInt( &ok );
420
if ( !ok ) {// ok there is no number
421
suggestedName = basename + '1' + dotSuffix;
424
// yes there's already a number behind the _ so increment it by one
425
basename.replace( pos+1, tmp.length(), QString::number(number+1) );
426
suggestedName = basename + dotSuffix;
429
else // no underscore yet
430
suggestedName = basename + "_1" + dotSuffix ;
432
// Check if suggested name already exists
434
// TODO: network transparency. However, using NetAccess from a modal dialog
435
// could be a problem, no? (given that it uses a modal widget itself....)
436
if ( baseURL.isLocalFile() )
437
exists = QFileInfo( baseURL.path(KUrl::AddTrailingSlash) + suggestedName ).exists();
440
return suggestedName;
441
else // already exists -> recurse
442
return suggestName( baseURL, suggestedName );
445
// Propose button clicked
446
void RenameDialog::suggestNewNamePressed()
448
/* no name to play with */
449
if ( d->m_pLineEdit->text().isEmpty() )
452
KUrl destDirectory( d->dest );
453
destDirectory.setPath( destDirectory.directory() );
454
d->m_pLineEdit->setText( suggestName( destDirectory, d->m_pLineEdit->text() ) );
458
void RenameDialog::skipPressed()
463
void RenameDialog::autoSkipPressed()
468
void RenameDialog::overwritePressed()
473
void RenameDialog::overwriteAllPressed()
478
void RenameDialog::resumePressed()
483
void RenameDialog::resumeAllPressed()
488
static QString mime( const KUrl& src )
490
KMimeType::Ptr type = KMimeType::findByUrl( src );
491
//if( type->name() == KMimeType::defaultMimeType() ){ // ok no mimetype
492
// QString ty = KIO::NetAccess::mimetype(d->src );
497
/** This will figure out the mimetypes and query for a plugin
498
* Loads it then and asks the plugin if it wants to do the job
499
* We'll take the first available mimetype
500
* The scanning for a mimetype will be done in 2 ways
503
void RenameDialog::pluginHandling()
505
d->mimeSrc = mime( d->src );
506
d->mimeDest = mime(d->dest );
508
kDebug(7024) << "Source Mimetype: "<< d->mimeSrc << endl;
509
kDebug(7024) << "Dest Mimetype: "<< d->mimeDest << endl;
513
RenameDialog_Result KIO::open_RenameDialog( const QString & _caption,
514
const KUrl & _src, const KUrl & _dest,
515
RenameDialog_Mode _mode,
517
KIO::filesize_t sizeSrc,
518
KIO::filesize_t sizeDest,
524
RenameDialog dlg( 0, _caption, _src, _dest, _mode,
525
sizeSrc, sizeDest, ctimeSrc, ctimeDest, mtimeSrc, mtimeDest );
527
_new = dlg.newDestUrl().path();
529
return (RenameDialog_Result)i;
532
#include "renamedialog.moc"