1
/**********************************************************************
2
** Copyright (C) 2000 Trolltech AS. All rights reserved.
4
** This file is part of Qt Designer.
6
** This file may be distributed and/or modified under the terms of the
7
** GNU General Public License version 2 as published by the Free Software
8
** Foundation and appearing in the file LICENSE.GPL included in the
9
** packaging of this file.
11
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
12
** licenses may use this file in accordance with the Qt Commercial License
13
** Agreement provided with the Software.
15
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18
** See http://www.trolltech.com/gpl/ for GPL licensing information.
19
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
20
** information about Qt Commercial License Agreements.
22
** Contact info@trolltech.com if any conditions of this licensing are
25
**********************************************************************/
28
#include "timestamp.h"
30
#include "formwindow.h"
32
#include "sourceeditor.h"
33
#include "mainwindow.h"
34
#include "../interfaces/languageinterface.h"
36
#include "workspace.h"
37
#include <qmessagebox.h>
39
#include <qstatusbar.h>
40
#include "propertyeditor.h"
41
#include <qworkspace.h>
43
#include "designerappiface.h"
44
#include <qapplication.h>
46
#include <kfiledialog.h>
48
#include "kdevdesigner_part.h"
50
static QString make_func_pretty( const QString &s )
53
if ( res.find( ")" ) - res.find( "(" ) == 1 )
55
res.replace( "(", "( " );
56
res.replace( ")", " )" );
57
res.replace( "&", " &" );
58
res.replace( "*", " *" );
59
res.replace( ",", ", " );
60
res.replace( ":", " : " );
61
res = res.simplifyWhiteSpace();
62
res.replace( " : : ", "::" );
63
res.replace( ">>", "> >" );
67
FormFile::FormFile( const QString &fn, bool temp, Project *p, const char *name )
68
: filename( fn ), fileNameTemp( temp ), pro( p ), fw( 0 ), ed( 0 ),
69
timeStamp( 0, fn + codeExtension() ), codeEdited( FALSE ), pkg( FALSE ),
70
cm( FALSE ), codeFileStat( None )
72
MetaDataBase::addEntry( this );
73
fake = qstrcmp( name, "qt_fakewindow" ) == 0;
74
//codeFileStat = FormFile::None;
75
pro->addFormFile( this );
78
checkFileName( FALSE );
80
connect(this, SIGNAL(somethingChanged(FormFile* )), this, SLOT(emitNewStatus(FormFile* )));
85
pro->removeFormFile( this );
87
formWindow()->setFormFile( 0 );
90
void FormFile::setFormWindow( FormWindow *f )
98
fw->setFormFile( this );
99
parseCode( cod, FALSE );
100
QTimer::singleShot( 0, this, SLOT( notifyFormWindowChange() ) );
103
void FormFile::setEditor( SourceEditor *e )
108
void FormFile::setFileName( const QString &fn )
110
if ( fn == filename )
112
if ( fn.isEmpty() ) {
114
if ( filename.find( "unnamed" ) != 0 )
115
filename = createUnnamedFileName();
118
fileNameTemp = FALSE;
121
timeStamp.setFileName( filename + codeExtension() );
126
void FormFile::setCode( const QString &c )
131
FormWindow *FormFile::formWindow() const
136
SourceEditor *FormFile::editor() const
141
QString FormFile::fileName() const
146
QString FormFile::absFileName() const
148
return pro->makeAbsolute( filename );
151
QString FormFile::codeFile() const
153
QString codeExt = codeExtension();
154
if ( codeExt.isEmpty() )
156
return filename + codeExt;
159
QString FormFile::code()
164
bool FormFile::save( bool withMsgBox, bool ignoreModified )
168
if ( !ignoreModified && !isModified() )
173
if ( formWindow() && isModified( WFormWindow ) ) {
175
if ( !formWindow()->checkCustomWidgets() )
179
if ( QFile::exists( pro->makeAbsolute( filename ) ) ) {
180
QString fn( pro->makeAbsolute( filename ) );
181
#if defined(Q_OS_WIN32)
186
QFile f( pro->makeAbsolute( filename ) );
187
if ( f.open( IO_ReadOnly ) ) {
189
if ( f2.open( IO_WriteOnly | IO_Translate ) ) {
190
QCString data( f.size() );
191
f.readBlock( data.data(), f.size() );
192
f2.writeBlock( data );
194
QMessageBox::warning( MainWindow::self, i18n( "Save" ),
195
i18n( "The file %1 could not be saved" ).arg( codeFile() ) );
201
if ( isModified( WFormCode ) ) {
202
if ( QFile::exists( pro->makeAbsolute( codeFile() ) ) ) {
203
QString fn( pro->makeAbsolute( codeFile() ) );
204
#if defined(Q_OS_WIN32)
209
QFile f( pro->makeAbsolute( codeFile() ) );
210
if ( f.open( IO_ReadOnly ) ) {
212
if ( f2.open( IO_WriteOnly | IO_Translate) ) {
213
QCString data( f.size() );
214
f.readBlock( data.data(), f.size() );
215
f2.writeBlock( data );
216
} else if ( qApp->type() != QApplication::Tty ) {
217
QMessageBox::warning( MainWindow::self, i18n( "Save" ),
218
i18n( "The file %1 could not be saved" ).arg( codeFile() ) );
224
if ( formWindow() ) {
225
Resource resource( MainWindow::self );
226
resource.setWidget( formWindow() );
227
bool formCodeOnly = isModified( WFormCode ) && !isModified( WFormWindow );
228
if ( !resource.save( pro->makeAbsolute( filename ), formCodeOnly ) ) {
229
if ( MainWindow::self )
230
MainWindow::self->statusMessage( i18n( "Failed to save file '%1'.").arg( formCodeOnly ? codeFile(): filename ) );
235
if ( MainWindow::self )
236
MainWindow::self->statusMessage( i18n( "'%1' saved.").
237
arg( formCodeOnly ? codeFile() : filename ));
239
if ( !Resource::saveFormCode(this, MetaDataBase::languageInterface(pro->language())) )
243
setModified( FALSE );
247
bool FormFile::saveAs( bool ignoreModified )
249
QString f = pro->makeAbsolute( fileName() );
250
if ( fileNameTemp && formWindow() ) {
251
f = QString( formWindow()->name() ).lower();
252
f.replace( "::", "_" );
253
f = pro->makeAbsolute( f + ".ui" );
256
if ( ignoreModified ) {
257
QString dir = QStringList::split( ':', pro->iFace()->customSetting( "QTSCRIPT_PACKAGES" ) ).first();
258
f = QFileInfo( f ).fileName();
259
f.prepend( dir + "/" );
263
fn = KFileDialog::getSaveFileName( f,
264
i18n( "*.ui|Qt User-Interface Files" ) + "\n" +
265
i18n( "*|All Files" ), MainWindow::self, /*0,*/
266
i18n( "Save Form '%1' As").arg( formName() )/*,
267
MainWindow::self ? &MainWindow::self->lastSaveFilter : 0*/ );
271
if ( fi.extension() != "ui" )
273
fileNameTemp = FALSE;
274
filename = pro->makeRelative( fn );
275
QFileInfo relfi( filename );
276
if ( relfi.exists() ) {
277
if ( QMessageBox::warning( MainWindow::self, i18n( "File Already Exists" ),
278
i18n( "The file already exists. Do you wish to overwrite it?" ),
280
QMessageBox::No ) == QMessageBox::Yes ) {
290
if ( !checkFileName( TRUE ) ) {
294
pro->setModified( TRUE );
295
timeStamp.setFileName( pro->makeAbsolute( codeFile() ) );
296
if ( ed && formWindow() )
297
ed->setCaption( i18n( "Edit %1" ).arg( formWindow()->name() ) );
299
if ( pro->isDummy() )
300
fw->mainWindow()->addRecentlyOpenedFile( fn );
301
return save( TRUE, ignoreModified );
304
bool FormFile::close()
311
return formWindow()->close();
315
bool FormFile::closeEvent()
317
if ( !isModified() && fileNameTemp ) {
318
pro->removeFormFile( this );
328
switch ( QMessageBox::warning( MainWindow::self, i18n( "Save Form" ),
329
i18n( "Save changes to form '%1'?" ).arg( filename ),
330
i18n( "&Yes" ), i18n( "&No" ), i18n( "&Cancel" ), 0, 2 ) ) {
334
case 1: // don't save
337
ed->editorInterface()->setText( cod );
339
pro->removeFormFile( this );
340
if ( MainWindow::self )
341
MainWindow::self->workspace()->update();
349
setModified( FALSE );
350
if ( MainWindow::self )
351
MainWindow::self->updateFunctionList();
352
setCodeEdited( FALSE );
356
void FormFile::setModified( bool m, int who )
358
if ( ( who & WFormWindow ) == WFormWindow )
359
setFormWindowModified( m );
360
if ( ( who & WFormCode ) == WFormCode )
361
setCodeModified( m );
364
bool FormFile::isModified( int who )
366
if ( who == WFormWindow )
367
return isFormWindowModified();
368
if ( who == WFormCode )
369
return isCodeModified();
370
return isCodeModified() || isFormWindowModified();
373
bool FormFile::isFormWindowModified() const
375
if ( !formWindow() || !formWindow()->commandHistory() )
377
return formWindow()->commandHistory()->isModified();
380
bool FormFile::isCodeModified() const
384
return editor()->isModified();
387
void FormFile::setFormWindowModified( bool m )
389
bool b = isFormWindowModified();
392
if ( !formWindow() || !formWindow()->commandHistory() )
394
formWindow()->commandHistory()->setModified( m );
395
emit somethingChanged( this );
398
void FormFile::setCodeModified( bool m )
400
bool b = isCodeModified();
403
emit somethingChanged( this );
407
editor()->setModified( m );
410
void FormFile::showFormWindow()
412
if ( !MainWindow::self )
414
if ( formWindow() ) {
415
if ( ( formWindow()->hasFocus() ||
416
MainWindow::self->qWorkspace()->activeWindow() == formWindow() ) &&
417
MainWindow::self->propertyeditor()->formWindow() != formWindow() ) {
418
MainWindow::self->propertyeditor()->setWidget( formWindow()->currentWidget(), formWindow() );
419
MainWindow::self->objectHierarchy()->setFormWindow( formWindow(),
420
formWindow()->currentWidget() );
422
formWindow()->setFocus();
425
MainWindow::self->openFormWindow( pro->makeAbsolute( filename ), TRUE, this );
428
bool FormFile::setupUihFile( bool askForUih )
430
if ( !pro->isCpp() || !askForUih ) {
431
if ( !hasFormCode() ) {
435
codeFileStat = FormFile::Ok;
438
if ( codeFileStat != FormFile::Ok && !ed ) {
439
if ( hasFormCode() ) {
440
int i = QMessageBox::information( MainWindow::self, i18n( "Using ui.h File" ),
441
i18n( "An \"ui.h\" file for this form already exists.\n"
442
"Do you want to use it or create a new one?" ),
443
i18n( "Use Existing" ), i18n( "Create New" ),
444
i18n( "Cancel" ), 2, 2 );
450
if ( QMessageBox::Yes != QMessageBox::information( MainWindow::self, i18n( "Creating ui.h file" ),
451
i18n( "Do you want to create an new \"ui.h\" file?" ),
452
QMessageBox::Yes, QMessageBox::No ) )
458
codeFileStat = FormFile::Ok;
462
SourceEditor *FormFile::showEditor( bool askForUih )
464
if ( !MainWindow::self )
467
//emit signal to the embedding IDE if there is one and return 0 because
468
//no source editing is possible
469
emit fw->mainWindow()->part()->emitEditSource(fw->fileName());
471
/* if ( !setupUihFile( askForUih ) )
473
return MainWindow::self->openSourceEditor();*/
476
static int ui_counter = 0;
477
QString FormFile::createUnnamedFileName()
479
return QString( "unnamed" ) + QString::number( ++ui_counter ) + QString( ".ui" );
482
QString FormFile::codeExtension() const
484
LanguageInterface *iface = MetaDataBase::languageInterface( pro->language() );
486
return iface->formCodeExtension();
490
QString FormFile::codeComment() const
492
return QString( "/****************************************************************************\n"
493
"** ui.h extension file, included from the uic-generated form implementation.\n"
495
"** If you want to add, delete, or rename functions or slots, use\n"
496
"** Qt Designer to update this file, preserving your code.\n"
498
"** You should not define a constructor or destructor in this file.\n"
499
"** Instead, write your code in functions called init() and destroy().\n"
500
"** These will automatically be called by the form's constructor and\n"
502
"*****************************************************************************/\n" );
505
bool FormFile::hasFormCode() const
507
return !cod.isEmpty() && cod != QString( codeComment() );
510
int FormFile::codeFileState() const
512
return hasFormCode() ? codeFileStat : None;
515
void FormFile::setCodeFileState( UihState s )
520
void FormFile::createFormCode()
524
LanguageInterface *iface = MetaDataBase::languageInterface( pro->language() );
529
QValueList<MetaDataBase::Function> functionList = MetaDataBase::functionList( formWindow() );
530
for ( QValueList<MetaDataBase::Function>::Iterator it = functionList.begin(); it != functionList.end(); ++it ) {
531
cod += (!cod.isEmpty() ? "\n\n" : "") +
532
iface->createFunctionStart( formWindow()->name(), make_func_pretty((*it).function),
533
(*it).returnType.isEmpty() ?
535
(*it).returnType, (*it).access ) +
536
"\n" + iface->createEmptyFunction();
538
parseCode( cod, FALSE );
541
void FormFile::load()
547
bool FormFile::loadCode()
549
QFile f( pro->makeAbsolute( codeFile() ) );
550
if ( !f.open( IO_ReadOnly ) ) {
552
setCodeFileState( FormFile::None );
555
QTextStream ts( &f );
557
parseCode( cod, FALSE );
558
if ( hasFormCode() && codeFileStat != FormFile::Ok )
559
setCodeFileState( FormFile::Deleted );
564
bool FormFile::isCodeEdited() const
569
void FormFile::setCodeEdited( bool b )
574
void FormFile::parseCode( const QString &txt, bool allowModify )
578
LanguageInterface *iface = MetaDataBase::languageInterface( pro->language() );
581
QValueList<LanguageInterface::Function> functions;
582
QValueList<MetaDataBase::Function> newFunctions, oldFunctions;
583
oldFunctions = MetaDataBase::functionList( formWindow() );
584
iface->functions( txt, &functions );
585
QMap<QString, QString> funcs;
586
for ( QValueList<LanguageInterface::Function>::Iterator it = functions.begin();
587
it != functions.end(); ++it ) {
589
for ( QValueList<MetaDataBase::Function>::Iterator fit = oldFunctions.begin();
590
fit != oldFunctions.end(); ++fit ) {
591
QString f( (*fit).function );
592
if ( MetaDataBase::normalizeFunction( f ) ==
593
MetaDataBase::normalizeFunction( (*it).name ) ) {
595
MetaDataBase::Function function;
596
function.function = make_func_pretty( (*it).name );
597
function.specifier = (*fit).specifier;
598
function.type = (*fit).type;
600
function.access = (*it).access;
602
function.access = (*fit).access;
603
function.language = (*fit).language;
604
function.returnType = (*it).returnType;
605
newFunctions << function;
606
funcs.insert( (*it).name, (*it).body );
607
oldFunctions.remove( fit );
612
MetaDataBase::Function function;
613
function.function = make_func_pretty( (*it).name );
614
function.specifier = "virtual";
615
function.access = "public";
616
function.language = pro->language();
617
function.returnType = (*it).returnType;
618
if ( function.returnType == "void" )
619
function.type = "slot";
621
function.type = "function";
622
if ( function.function == "init()" || function.function == "destroy()" ) {
623
function.type = "function";
624
function.access = "private";
625
function.specifier = "non virtual";
627
newFunctions << function;
628
funcs.insert( (*it).name, (*it).body );
630
setFormWindowModified( TRUE );
634
if ( allowModify && oldFunctions.count() > 0 )
635
setFormWindowModified( TRUE );
637
MetaDataBase::setFunctionList( formWindow(), newFunctions );
640
void FormFile::syncCode()
644
parseCode( editor()->editorInterface()->text(), TRUE );
645
cod = editor()->editorInterface()->text();
648
void FormFile::checkTimeStamp()
650
if ( timeStamp.isUpToDate() )
654
if ( QMessageBox::information( MainWindow::self, i18n( "Qt Designer" ),
655
i18n( "File '%1' has been changed outside Qt Designer.\n"
656
"Do you want to reload it?" ).arg( timeStamp.fileName() ),
657
i18n( "&Yes" ), i18n( "&No" ) ) == 0 ) {
658
QFile f( timeStamp.fileName() );
659
if ( f.open( IO_ReadOnly ) ) {
660
QTextStream ts( &f );
661
editor()->editorInterface()->setText( ts.read() );
663
if ( MainWindow::self )
664
MainWindow::self->functionsChanged();
672
bool FormFile::isUihFileUpToDate()
674
if ( timeStamp.isUpToDate() )
677
MainWindow::self->editSource();
678
qDebug( "parse Code" );
679
parseCode( editor()->editorInterface()->text(), TRUE );
685
void FormFile::addFunctionCode( MetaDataBase::Function function )
687
if ( pro->isCpp() && !hasFormCode() && !codeEdited )
689
LanguageInterface *iface = MetaDataBase::languageInterface( pro->language() );
693
QValueList<LanguageInterface::Function> funcs;
694
iface->functions( cod, &funcs );
695
bool hasFunc = FALSE;
696
for ( QValueList<LanguageInterface::Function>::Iterator it = funcs.begin();
697
it != funcs.end(); ++it ) {
698
if ( MetaDataBase::normalizeFunction( (*it).name ) == MetaDataBase::normalizeFunction( function.function ) ) {
705
if ( !codeEdited && !timeStamp.isUpToDate() )
707
MetaDataBase::MetaInfo mi = MetaDataBase::metaInfo( formWindow() );
709
if ( mi.classNameChanged )
712
cn = formWindow()->name();
713
QString body = "\n\n" + iface->createFunctionStart( cn,
714
make_func_pretty( function.function ),
715
function.returnType.isEmpty() ?
717
function.returnType, function.access ) +
718
"\n" + iface->createEmptyFunction();
722
emit somethingChanged( this );
727
void FormFile::removeFunctionCode( MetaDataBase::Function function )
729
if ( pro->isCpp() && !hasFormCode() && !codeEdited )
732
LanguageInterface *iface = MetaDataBase::languageInterface( pro->language() );
737
QString sourceCode = code();
738
if ( sourceCode.isEmpty() )
740
QValueList<LanguageInterface::Function> functions;
741
iface->functions( sourceCode, &functions );
742
QString fu = MetaDataBase::normalizeFunction( function.function );
743
for ( QValueList<LanguageInterface::Function>::Iterator fit = functions.begin(); fit != functions.end(); ++fit ) {
744
if ( MetaDataBase::normalizeFunction( (*fit).name ) == fu ) {
747
while ( line < (*fit).start - 1 ) {
748
start = sourceCode.find( '\n', start );
757
while ( line < (*fit).end + 1 ) {
758
end = sourceCode.find( '\n', end );
760
if ( line <= (*fit).end )
761
end = sourceCode.length() - 1;
770
sourceCode.remove( start, end - start );
771
setCode( sourceCode );
776
void FormFile::functionNameChanged( const QString &oldName, const QString &newName )
778
if ( !cod.isEmpty() ) {
779
QString funcStart = QString( formWindow()->name() ) + QString( "::" );
780
int i = cod.find( funcStart + oldName );
782
cod.remove( i + funcStart.length(), oldName.length() );
783
cod.insert( i + funcStart.length(), newName );
788
void FormFile::functionRetTypeChanged( const QString &fuName, const QString &oldType, const QString &newType )
790
if ( !cod.isEmpty() ) {
791
QString oldFunct = oldType + " " + QString( formWindow()->name() ) + "::" + fuName;
792
QString newFunct = newType + " " + QString( formWindow()->name() ) + "::" + fuName;
794
int i = cod.find( oldFunct );
796
cod.remove( i, oldFunct.length() );
797
cod.insert( i, newFunct );
802
QString FormFile::formName() const
804
FormFile* that = (FormFile*) this;
805
if ( formWindow() ) {
806
that->cachedFormName = formWindow()->name();
807
return cachedFormName;
809
if ( !cachedFormName.isNull() )
810
return cachedFormName;
811
QFile f( pro->makeAbsolute( filename ) );
812
if ( f.open( IO_ReadOnly ) ) {
813
QTextStream ts( &f );
816
while ( !ts.eof() ) {
817
line = ts.readLine();
818
if ( !className.isEmpty() ) {
819
int end = line.find( "</class>" );
823
className += line.left( end );
829
if ( ( start = line.find( "<class>" ) ) != -1 ) {
830
int end = line.find( "</class>" );
832
className = line.mid( start + 7 );
834
className = line.mid( start + 7, end - ( start + 7 ) );
839
that->cachedFormName = className;
841
if ( cachedFormName.isEmpty() )
842
that->cachedFormName = filename;
843
return cachedFormName;
846
void FormFile::formWindowChangedSomehow()
848
emit somethingChanged( this );
851
bool FormFile::checkFileName( bool allowBreak )
853
FormFile *ff = pro->findFormFile( filename, this );
855
QMessageBox::warning( MainWindow::self, i18n( "Invalid Filename" ),
856
i18n( "The project already contains a form with a\n"
857
"filename of '%1'. Please choose a new filename." ).arg( filename ) );
860
while ( fn.isEmpty() ) {
861
fn = KFileDialog::getSaveFileName( pro->makeAbsolute( fileName() ),
862
i18n( "*.ui|Qt User-Interface Files" ) + "\n" +
863
i18n( "*|All Files" ), MainWindow::self,/* 0,*/
864
i18n( "Save Form '%1' As").
865
arg( formWindow()->name() )/*,
866
MainWindow::self ? &MainWindow::self->lastSaveFilter : 0 */);
867
if ( allowBreak && fn.isEmpty() )
870
filename = pro->makeRelative( fn );
871
ff = pro->findFormFile( filename, this );
876
void FormFile::addConnection( const QString &sender, const QString &signal,
877
const QString &receiver, const QString &slot )
879
LanguageInterface *iface = MetaDataBase::languageInterface( pro->language() );
881
iface->addConnection( sender, signal, receiver, slot, &cod );
883
ed->editorInterface()->setText( cod );
886
void FormFile::removeConnection( const QString &sender, const QString &signal,
887
const QString &receiver, const QString &slot )
889
LanguageInterface *iface = MetaDataBase::languageInterface( pro->language() );
891
iface->removeConnection( sender, signal, receiver, slot, &cod );
893
ed->editorInterface()->setText( cod );
896
void FormFile::notifyFormWindowChange()
899
pro->formOpened( fw );
902
void FormFile::emitNewStatus(FormFile *file)
904
fw->mainWindow()->part()->emitNewStatus(fileName(), isModified());