00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "projectdock.h"
00021
00022 #include "core/debughelper.h"
00023 #include "core/gluon_global.h"
00024 #include "engine/game.h"
00025 #include "engine/gameobject.h"
00026 #include "engine/scene.h"
00027 #include "engine/asset.h"
00028 #include "models/projectmodel.h"
00029 #include "models/modeltest.h"
00030 #include "engine/gameproject.h"
00031 #include "creator/lib/selectionmanager.h"
00032
00033 #include <QtGui/QTreeView>
00034 #include <QtGui/QMenu>
00035
00036 #include <KDebug>
00037 #include <KInputDialog>
00038 #include <KMessageBox>
00039 #include <KLocalizedString>
00040 #include <QFile>
00041 #include <QFileInfo>
00042 #include <KRun>
00043 #include <historymanager.h>
00044 #include <newobjectcommand.h>
00045 #include <QDir>
00046 #include <KStandardDirs>
00047 #include <QVBoxLayout>
00048 #include <KToolBar>
00049 #include <objectmanager.h>
00050 #include <filemanager.h>
00051
00052 using namespace GluonCreator;
00053
00054 class ProjectDock::ProjectDockPrivate
00055 {
00056 public:
00057 ProjectDockPrivate( ProjectDock* parent )
00058 {
00059 DEBUG_BLOCK
00060 q = parent;
00061 view = 0;
00062 GluonEngine::Asset* theItem;
00063 const QHash<QString, const QMetaObject*> types = GluonCore::GluonObjectFactory::instance()->objectTypes();
00064 QHash<QString, const QMetaObject*>::const_iterator i;
00065 for( i = types.constBegin(); i != types.constEnd(); ++i )
00066 {
00067 theItem = qobject_cast<GluonEngine::Asset*>( i.value()->newInstance() );
00068 if( theItem )
00069 {
00070 const QList<GluonEngine::AssetTemplate*> templates = theItem->templates();
00071 for( int j = 0; j < templates.length(); ++j )
00072 {
00073 assetTemplates.append( templates[j] );
00074 }
00075 }
00076 else
00077 {
00078 QObject* obj = i.value()->newInstance();
00079 if(obj) {
00080 if(obj->inherits("GluonEngine::Asset"))
00081 {
00082 DEBUG_TEXT2("The Asset class %1 is lacking the Q_INTERFACES(GluonEngine::Asset) macro", i.value()->className());
00083 }
00084 }
00085 }
00086 }
00087 }
00088 ProjectDock* q;
00089 ProjectModel* model;
00090 QTreeView* view;
00091 KToolBar* toolBar;
00092
00093 QModelIndex currentContextIndex;
00094 QList<QAction*> menuForObject( QModelIndex index );
00095 QList<QAction*> currentContextMenu;
00096 QList<GluonEngine::AssetTemplate*> assetTemplates;
00097 };
00098
00099 QList< QAction* > ProjectDock::ProjectDockPrivate::menuForObject( QModelIndex index )
00100 {
00101 QList<QAction*> menuItems;
00102
00103 GluonCore::GluonObject* object = static_cast<GluonCore::GluonObject*>( index.internalPointer() );
00104 if( object )
00105 {
00106 const QMetaObject* mobj = object->metaObject();
00107 if( mobj )
00108 {
00109 currentContextIndex = index;
00110 QAction* action;
00111 if( object->inherits( "GluonEngine::Asset" ) )
00112 {
00113 GluonEngine::Asset* asset = qobject_cast< GluonEngine::Asset* >( object );
00114 if( asset )
00115 {
00116 QList<QAction*> actions = asset->actions();
00117 foreach( QAction * action, actions )
00118 {
00119 connect( action, SIGNAL( triggered( bool ) ), model, SIGNAL( layoutChanged() ) );
00120 }
00121 menuItems.append( actions );
00122 }
00123 }
00124 else
00125 {
00126 action = new QAction( KIcon( "folder" ), i18n( "New Folder..." ), this->q );
00127 connect( action, SIGNAL( triggered() ), q, SLOT( newSubMenuTriggered() ) );
00128 menuItems.append( action );
00129
00130 action = new QAction( KIcon( "document-new" ), i18n( "New Scene" ), this->q );
00131 connect( action, SIGNAL( triggered( bool ) ), ObjectManager::instance(), SLOT( createNewScene() ) );
00132 menuItems.append( action );
00133
00134
00135 foreach( const GluonEngine::AssetTemplate * item, assetTemplates )
00136 {
00137 action = new QAction( i18n( "New %1" ).arg( item->name ), this->q );
00138 action->setProperty( "newAssetClassname", QString( item->parent()->metaObject()->className() ) );
00139 action->setProperty( "newAssetName", item->name );
00140 action->setProperty( "newAssetPluginname", item->pluginname );
00141 action->setProperty( "newAssetFilename", item->filename );
00142 connect( action, SIGNAL( triggered() ), q, SLOT( newAssetTriggered() ) );
00143 menuItems.append( action );
00144 }
00145 }
00146
00147 if( !object->inherits( "GluonEngine::GameProject" ) )
00148 {
00149 action = new QAction( this->q );
00150 action->setSeparator( true );
00151 menuItems.append( action );
00152
00153 action = new QAction( KIcon( "edit-delete" ), i18n( "Delete \"%1\"...", object->name() ), this->q );
00154 connect( action, SIGNAL( triggered() ), q, SLOT( deleteActionTriggered() ) );
00155 menuItems.append( action );
00156 }
00157 }
00158 }
00159 currentContextMenu = QList<QAction*>( menuItems );
00160
00161 return menuItems;
00162 }
00163
00164
00165
00166 ProjectDock::ProjectDock( const QString& title, QWidget* parent, Qt::WindowFlags flags )
00167 : QDockWidget( title, parent, flags ), d( new ProjectDockPrivate( this ) )
00168 {
00169 setObjectName( "ProjectDock" );
00170
00171 d->model = new ProjectModel( this );
00172 new ModelTest( d->model, this );
00173
00174 d->view = new QTreeView( this );
00175 d->view->setModel( d->model );
00176 d->view->setHeaderHidden( true );
00177 d->view->setAcceptDrops( true );
00178 d->view->setContextMenuPolicy( Qt::CustomContextMenu );
00179 d->view->setEditTriggers( QAbstractItemView::NoEditTriggers );
00180 connect( d->view, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( showContextMenuRequested( const QPoint& ) ) );
00181 connect( d->view->selectionModel(), SIGNAL( selectionChanged( QItemSelection, QItemSelection ) ), this, SLOT( selectionChanged( QItemSelection, QItemSelection ) ) );
00182
00183 d->model->setProject( GluonEngine::Game::instance()->gameProject() );
00184 connect( GluonEngine::Game::instance(), SIGNAL( currentProjectChanged( GluonEngine::GameProject* ) ), SLOT( currentProjectChanged( GluonEngine::GameProject* ) ) );
00185 connect( d->view, SIGNAL( doubleClicked( QModelIndex ) ), this, SLOT( activated( QModelIndex ) ) );
00186
00187 QWidget* widget = new QWidget( this );
00188 QVBoxLayout* layout = new QVBoxLayout();
00189 widget->setLayout( layout );
00190
00191 d->toolBar = new KToolBar( widget );
00192 d->toolBar->setIconDimensions( 16 );
00193 QAction* action = d->toolBar->addAction( KIcon( "document-new" ), i18n( "New Scene" ) );
00194 connect( action, SIGNAL( triggered( bool ) ), ObjectManager::instance(), SLOT( createNewScene() ) );
00195 action = d->toolBar->addAction( KIcon( "edit-delete" ), i18nc( "Delete selected object from project", "Delete" ) );
00196 connect( action, SIGNAL( triggered( bool ) ), SLOT( deleteActionTriggered() ) );
00197 layout->addWidget( d->toolBar );
00198 layout->addWidget( d->view );
00199
00200 setWidget( widget );
00201 }
00202
00203 ProjectDock::~ProjectDock()
00204 {
00205 delete d;
00206 }
00207
00208 void ProjectDock::activated( QModelIndex index )
00209 {
00210 DEBUG_FUNC_NAME
00211 if( !index.isValid() )
00212 {
00213 return;
00214 }
00215
00216 QObject* obj = static_cast<QObject*>( index.internalPointer() );
00217 if( !obj )
00218 {
00219 return;
00220 }
00221
00222 GluonEngine::Scene* scene = qobject_cast<GluonEngine::Scene*>( obj );
00223 GluonEngine::Asset* asset = qobject_cast<GluonEngine::Asset*>( obj );
00224
00225 if( scene )
00226 {
00227 if( GluonEngine::Game::instance()->currentScene() != scene )
00228 {
00229 GluonEngine::Game::instance()->setCurrentScene( scene );
00230 GluonEngine::Game::instance()->initializeAll();
00231 GluonEngine::Game::instance()->drawAll();
00232 }
00233 }
00234 else if( asset )
00235 {
00236 FileManager::instance()->openAsset( asset );
00237 }
00238 }
00239
00240 void ProjectDock::selectionChanged( const QItemSelection& selected, const QItemSelection& deselected )
00241 {
00242 Q_UNUSED( deselected )
00243
00244 SelectionManager::SelectionList selection;
00245 foreach( const QItemSelectionRange & range, selected )
00246 {
00247 foreach( const QModelIndex & index, range.indexes() )
00248 {
00249 GluonCore::GluonObject* obj = static_cast<GluonCore::GluonObject*>( index.internalPointer() );
00250 selection.append( obj );
00251 }
00252 }
00253 SelectionManager::instance()->setSelection( selection );
00254 }
00255
00256 void ProjectDock::currentProjectChanged( GluonEngine::GameProject* project )
00257 {
00258 d->model->setProject( project );
00259
00260 if( !d->toolBar->isEnabled() )
00261 d->toolBar->setEnabled( true );
00262
00263 d->view->expandAll();
00264 }
00265
00266 void ProjectDock::showContextMenuRequested( const QPoint& pos )
00267 {
00268 QModelIndex index = d->view->indexAt( pos );
00269 if( !index.isValid() )
00270 index = d->model->index( 0, 0 );
00271
00272 QMenu menu( static_cast<GluonCore::GluonObject*>( index.internalPointer() )->name(), this );
00273 menu.addActions( d->menuForObject( index ) );
00274 menu.exec( d->view->mapToGlobal( pos ) );
00275 connect( &menu, SIGNAL( aboutToHide() ), this, SLOT( contextMenuHiding() ) );
00276 }
00277
00278 void ProjectDock::contextMenuHiding()
00279 {
00280 d->currentContextIndex = QModelIndex();
00281 qDeleteAll( d->currentContextMenu );
00282 }
00283
00284 void ProjectDock::deleteActionTriggered()
00285 {
00286 DEBUG_BLOCK
00287 if( !d->currentContextIndex.isValid() )
00288 d->currentContextIndex = d->view->selectionModel()->currentIndex();
00289
00290 if( !d->currentContextIndex.isValid() )
00291 return;
00292
00293
00294 GluonCore::GluonObject* object = static_cast<GluonCore::GluonObject*>( d->currentContextIndex.internalPointer() );
00295 DEBUG_TEXT( QString( "Requested deletion of %1" ).arg( object->fullyQualifiedName() ) );
00296 if( KMessageBox::questionYesNo( this, i18n( "Please confirm that you wish to delete the object %1. This will delete both this item and all its children!" ).arg( object->name() ), i18n( "Really Delete?" ) ) == KMessageBox::Yes )
00297 {
00298 d->view->selectionModel()->select( d->currentContextIndex.parent(), QItemSelectionModel::ClearAndSelect );
00299
00300 d->model->removeRows( d->currentContextIndex.row(), 1, d->currentContextIndex.parent() );
00301
00302 d->currentContextIndex = QModelIndex();
00303 }
00304 }
00305
00306 void ProjectDock::newSubMenuTriggered()
00307 {
00308 if( d->currentContextIndex.isValid() )
00309 {
00310
00311 QString theName( KInputDialog::getText( i18n( "Enter Name" ), i18n( "Please enter the name of the new folder in the text box below:" ), i18n( "New Folder" ), 0, this ) );
00312 if( !theName.isEmpty() )
00313 {
00314 d->model->addChild( new GluonCore::GluonObject( theName ), d->currentContextIndex );
00315 }
00316 }
00317 }
00318
00319 void GluonCreator::ProjectDock::newAssetTriggered()
00320 {
00321 DEBUG_FUNC_NAME
00322 if( d->currentContextIndex.isValid() )
00323 {
00324 DEBUG_TEXT( "Index is valid" );
00325
00326 QAction* menuItem = qobject_cast< QAction* >( QObject::sender() );
00327 if( menuItem )
00328 {
00329 DEBUG_TEXT( "Menu item exists" );
00330 GluonCore::GluonObject* newChild = GluonCore::GluonObjectFactory::instance()->instantiateObjectByName( menuItem->property( "newAssetClassname" ).toString() );
00331 GluonEngine::Asset* newAsset = qobject_cast< GluonEngine::Asset* >( newChild );
00332 if( newAsset )
00333 {
00334 DEBUG_TEXT( "Asset was created" );
00335 d->model->addChild( newAsset, d->currentContextIndex );
00336
00337 newAsset->setName( menuItem->property( "newAssetName" ).toString() );
00338
00339 QString templateFilename = QString( "gluon/templates/%1/%2" ).arg( menuItem->property( "newAssetPluginname" ).toString() ).arg( menuItem->property( "newAssetFilename" ).toString() );
00340 QString fileName = GluonCore::Global::dataDirectory() + '/' + templateFilename;
00341 if( fileName.isEmpty() )
00342 {
00343 DEBUG_TEXT( "Failed at finding the template file!" );
00344 return;
00345 }
00346
00347 if( !QDir::current().exists( "Assets" ) )
00348 QDir::current().mkdir( "Assets" );
00349
00350 QFileInfo info( fileName );
00351 QUrl newLocation( QString( "Assets/%1.%2" ).arg( newAsset->fullyQualifiedFileName() ).arg( info.completeSuffix() ) );
00352 QFile( fileName ).copy( newLocation.toLocalFile() );
00353
00354 newAsset->setFile( newLocation );
00355 newAsset->setGameProject( GluonEngine::Game::instance()->gameProject() );
00356 newAsset->load();
00357
00358
00359 }
00360 }
00361 }
00362 }