AlgorithmSelector.cpp 17.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/*
 *	(c) LSIIT, UMR CNRS/UdS
 *	Authors: O. Gnevaux, F. Larue.
 *
 *	See licence.txt for additional information.
 */


#include "GLViewer.h"
#include "AlgorithmSelector.h"
#include "ui_AlgorithmSelector.h"
12
#include "UIMultiProgressDialog.h"
13
#include <QLabel>
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "ScriptParser.h"




QString AlgorithmSelector::ToolDescriptor::getName() const
{
    return plugin? plugin->name(id) : script->GetName();
}

QString AlgorithmSelector::ToolDescriptor::getDescription() const
{
    return plugin? plugin->description(id) : script->GetDescription();
}

void AlgorithmSelector::ToolDescriptor::getAcceptedDataTypes( QVector<QString> &types ) const
{
    if( plugin )
        plugin->acceptedDataTypes( id, types );
}
34
35
36
37
38
39
40
41




AlgorithmSelector::AlgorithmSelector(QWidget *parent) :
    QWidget( parent ),
    m_ui( new Ui::AlgorithmSelector ),
    m_SelectedTool( NULL ),
42
43
    m_SelectedToolParam( NULL ),
    m_CurrentToolProgress( NULL )
44
45
46
47
48
49
50
51
52
{
    m_ui->setupUi(this);
    m_ui->groupToolDescription->hide();

    connect( m_ui->buttonApplyTool, SIGNAL(clicked()), this, SLOT(emitApplySignal()) );

    m_CategoryButtonGroup = new QButtonGroup( this );
    connect( m_CategoryButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(selectCategory(int)) );

53
54
55
    m_ToolsByCategory.resize( ToolCategory::categoryCount() );
    m_LastUsedInCategory.resize( ToolCategory::categoryCount() );
    for( int i=0; i<ToolCategory::categoryCount(); ++i )
56
57
58
59
60
61
        m_LastUsedInCategory[i] = 0;
}


AlgorithmSelector::~AlgorithmSelector()
{
62
63
    for( auto &tool : m_ToolsByName )
        delete tool.script;
64
    delete m_CurrentToolProgress;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    delete m_ui;
}


void AlgorithmSelector::changeEvent(QEvent *e)
{
    QWidget::changeEvent( e );
    switch( e->type() )
    {
        case QEvent::LanguageChange: m_ui->retranslateUi(this); break;
        default: break;
    }
}


void AlgorithmSelector::populateTools( ToolInterface *plugin )
{
    QList<int> toolIds;
    plugin->toolIds( toolIds );

    foreach( int i, toolIds )
    {
87
88
        int categoryId = plugin->category(i);
        if( ToolCategory::isCategoryDeclared(categoryId) )
89
        {
90
91
92
93
94
95
            ToolDescriptor *tool = &m_ToolsByName[ plugin->name(i) ];
            tool->plugin = plugin;
            tool->id     = i;
            tool->param  = new UIParamSet( "Tool options", this );
            plugin->declareParameters( i, *tool->param );
            tool->param->SetHidden();
96
			//tool.param->setMaximumWidth(360);
97

98
            connect( tool->param, SIGNAL(parameterUpdated(UIParam*)), tool->plugin, SLOT(updateParameter(UIParam*)) );
99

100
            foreach( UIParamAction* act, tool->param->GetActions() )
101
                connect( act->Widget(), SIGNAL(clicked(bool)), this, SLOT(emitActionSignal()) );
102
103

            m_ToolsByCategory[categoryId].push_back( tool );
104
            m_ui->widgetToolGroupBoxes->layout()->addWidget( tool->param );
105
106
107
108
109
        }
    }
}


110
111
112
113
114
bool AlgorithmSelector::populateTools( const QString &scriptFileName )
{
    ScriptParser *script = new ScriptParser();
    script->SetAvailableTools( this );

115
116
117
    UIParamSet *toolParam = new UIParamSet( "Tool options", this );

    if( !script->ParseFile(scriptFileName, toolParam)  ||  script->GetCategory().isEmpty()  ||  script->GetName().isEmpty() )
118
119
    {
        delete script;
120
        delete toolParam;
121
122
123
124
125
126
127
128
129
130
131
132
133
        return false;
    }

    bool categoryDeclared = false;
    int categoryId = -1;
    for( int i=0; i<ToolCategory::categoryCount(); ++i )
        if( script->GetCategory() == ToolCategory::categoryName(i) )
        {
            categoryId = i;
            categoryDeclared = true;
            break;
        }

134
    if( !categoryDeclared )
135
    {
136
        delete script;
137
        delete toolParam;
138
139
        return false;
    }
140

141
142
143
144
    ToolDescriptor *tool = &m_ToolsByName[ script->GetName() ];
    tool->script = script;
    tool->scriptSourceFile = scriptFileName;
    tool->scriptSourceModificationTime = QFileInfo(scriptFileName).lastModified();
145
    tool->param = toolParam;
146
    tool->param->SetHidden();
147

148
    //connect( tool.param, SIGNAL(parameterUpdated(UIParam*)), tool.plugin, SLOT(updateParameter(UIParam*)) );
149

150
151
152
153
154
    //foreach( UIParamAction* act, tool.param->GetActions() )
    //    connect( act->Widget(), SIGNAL(clicked(bool)), this, SLOT(emitActionSignal()) );

    m_ToolsByCategory[categoryId].push_back( tool );
    m_ui->widgetToolGroupBoxes->layout()->addWidget( tool->param );
155
156
157
158
159

    return true;
}


160
161
void AlgorithmSelector::releaseAllTools()
{
162
163
    for( auto &tool : m_ToolsByName )
        delete tool.param;
164
165
166
}


167
168
169
void AlgorithmSelector::finalizeTools()
{
    // Sort tools by name for each category.
170
    for( auto &category : m_ToolsByCategory )
171
    {
172
173
174
        QMap<QString,ToolDescriptor*> toolByName;
        for( ToolDescriptor *tool : category )
            toolByName[tool->getName()] = tool;
175

176
        category.clear();
177

178
        for( ToolDescriptor *tool : toolByName )
179
            category.push_back( tool );
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    }


    /** For each non-empty category, a pannel similar to the following one is created and added to the category widget.
     *      +--------------+
     *      | +----------+ |
     *      | |  Button  | |
     *      | |   with   | |
     *      | |   icon   | |
     *      | +----------+ |
     *      |     Label    |
     *      +--------------+
     */

194
195
196
    QPushButton *firstCategoryButton = NULL;
    int firstCategoryId = -1;

197
    for( int categoryId : ToolCategory::categoryIds() )
198
199
        if( !m_ToolsByCategory[categoryId].empty() )
        {
200
            QVBoxLayout *l = new QVBoxLayout();
201
202
203
204
205
206
207
208
209
            l->setAlignment( Qt::AlignHCenter );
            l->setContentsMargins( 0, 0, 0, 0 );
            l->setSpacing( 0 );

            QPushButton *categoryButton = new QPushButton( ToolCategory::categoryIcon(categoryId), QString() );
            categoryButton->setContentsMargins( 0, 0, 0, 0 );
            categoryButton->setIconSize( QSize(80,80) );
            categoryButton->setFlat( true );
            categoryButton->setMinimumSize( 80, 80 );
210
            categoryButton->setMaximumSize( 80, 80 );
211
            categoryButton->setCheckable( true );
212
            l->addWidget( categoryButton, 0, Qt::AlignHCenter );
213
214
            m_CategoryButtonGroup->addButton( categoryButton, categoryId );

215
216
217
218
219
220
            if( !firstCategoryButton )
            {
                firstCategoryButton = categoryButton;
                firstCategoryId = categoryId;
            }

221
            QLabel *categoryLabel = new QLabel( ToolCategory::categoryName(categoryId) );
222
            QFont f = QApplication::font();
223
224
225
            f.setPointSize( 7 );
            categoryLabel->setFont( f );
            categoryLabel->setAlignment( Qt::AlignHCenter );
226
            //categoryLabel->setWordWrap( true );
227
            l->addWidget( categoryLabel, 0, Qt::AlignHCenter );
228
229
230
231
232
233
234
235
236

            QWidget *categoryPannel = new QWidget();
            categoryPannel->setLayout( l );

            QGridLayout *allCategories = (QGridLayout*) m_ui->widgetCategories->layout();
            int i = allCategories->count();
            allCategories->addWidget( categoryPannel, i>>2, i&3 );
        }

237
238
239
240
241
242
243
	m_ui->widgetCategories->layout()->setAlignment(Qt::AlignHCenter | Qt::AlignTop);

    if( firstCategoryButton )
    {
        firstCategoryButton->setChecked( true );
        selectCategory( firstCategoryId );
    }
244
245
246
}


247
bool AlgorithmSelector::selectCategory( int categoryId )
248
{
249
250
251
    if( !ToolCategory::isCategoryDeclared(categoryId) )
        return false;

252
253
254
255
256
257
258
    disconnect( m_ui->comboAvailableTools, SIGNAL(currentIndexChanged(int)), this, SLOT(selectTool(int)) );

    m_SelectedCategory = categoryId;
    int lastUsedId = m_LastUsedInCategory[categoryId];

    // Populate the combobox with the names of all tools associated to the selected category.
    m_ui->comboAvailableTools->clear();
259
    for( ToolDescriptor *tool : m_ToolsByCategory[categoryId] )
260
    {
261
262
263
264
265
        if( tool->script )
        {
            QIcon icon(tool->isScriptBroken? ":/images/resources/iconBrokenScript.png" : ":/images/resources/iconScript.png");
            m_ui->comboAvailableTools->addItem( icon, tool->getName() );
        }
266
        else
267
            m_ui->comboAvailableTools->addItem( tool->getName() );
268
    }
269
270
271
272
273

    m_ui->comboAvailableTools->setCurrentIndex( lastUsedId );
    selectTool( lastUsedId );

    connect( m_ui->comboAvailableTools, SIGNAL(currentIndexChanged(int)), this, SLOT(selectTool(int)) );
274
275

    return true;
276
277
278
}


279
bool AlgorithmSelector::selectTool( int n )
280
281
282
{
    if( m_SelectedToolParam )
    {
283
        m_SelectedToolParam->SetHidden();
284
285
286
        m_SelectedToolParam = NULL;
    }

287
288
289
    if( n >= m_ToolsByCategory[m_SelectedCategory].size() )
        return false;

290
291
    if( n >= 0 )
    {
292
        m_SelectedTool = m_ToolsByCategory[m_SelectedCategory][n];
293

294
        QString description = m_SelectedTool->getDescription();
295
296
297
298
299
300
301
302
303
        if( description.isNull() || description.isEmpty() )
            m_ui->groupToolDescription->hide();
        else
        {
            m_ui->groupToolDescription->show();
            m_ui->labelToolDescription->setText( description );
            m_ui->labelToolDescription->setEnabled( true );

            QVector<QString> acceptedTypes;
304
            m_SelectedTool->getAcceptedDataTypes(acceptedTypes);
305
306
307
308
309
310
311
312
313
314
315
            if( acceptedTypes.empty() )
                m_ui->labelToolDescription->setToolTip( "" );
            else
            {
                QString toolTip = "Accepted items:";
                foreach( QString t, acceptedTypes )
                    toolTip += QString("\n") + t;
                m_ui->labelToolDescription->setToolTip( toolTip );
            }
        }

316
        if( !m_SelectedTool->param->IsEmpty() )
317
318
        {
            m_SelectedToolParam = m_SelectedTool->param;
319
            m_SelectedToolParam->SetVisible();
320
321
322
        }

        m_LastUsedInCategory[m_SelectedCategory] = n;
323
324

        recompileCurrentScript();
325
326
327
328
329
330
    }
    else
    {
        m_ui->groupToolDescription->hide();
        m_SelectedTool = NULL;
    }
331
332

    return true;
333
334
335
}


336
QString AlgorithmSelector::state() const
337
{
338
339
340
341
342
343
344
345
346
347
    QString stateValue;

    stateValue += QString::number(m_SelectedCategory) + ";";
    stateValue += QString::number(m_ui->comboAvailableTools->currentIndex());
    for( auto v : m_LastUsedInCategory )
        stateValue += ";" + QString::number(v);
    
    return stateValue;
}

348

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
bool AlgorithmSelector::setState( const QString &stateValue )
{
    QStringList tokens = stateValue.split( ';' );
    if( tokens.size() != m_LastUsedInCategory.size()+2 )
        return false;

    bool ok;
    int selectedCategory = tokens.front().toInt( &ok );
    if( !ok )
        return false;
    tokens.pop_front();

    int selectedTool = tokens.front().toInt( &ok );
    if( !ok )
        return false;
    tokens.pop_front();

    QVector<int> lastUsedInCategory( m_LastUsedInCategory.size() );
    for( auto &v : lastUsedInCategory )
368
    {
369
370
371
372
        v = tokens.front().toInt( &ok );
        if( !ok )
            return false;
        tokens.pop_front();
373
    }
374
375
376
377
378
379
380
381
382
383

    m_CategoryButtonGroup->button( selectedCategory )->setChecked( true );
    selectCategory( selectedCategory );

    m_ui->comboAvailableTools->setCurrentIndex( selectedTool );
    selectTool( selectedTool );

    m_LastUsedInCategory = lastUsedInCategory;

    return true;
384
385
386
}


387
388
389
390
391
392
393
394
395
396
397
398
399
void AlgorithmSelector::emitApplySignal()
{
	if( m_SelectedTool )
	{
		m_ActionId = QString();
		emit askItemsToApplyToolOn();
	}
}


void AlgorithmSelector::emitActionSignal()
{
    m_ActionId = QString();
400
    foreach( UIParamAction* act, m_SelectedTool->param->GetActions() )
401
402
        if( act->Widget() == (QPushButton*)sender() )
            m_ActionId = act->Id();
403
404
405
406
407
408

    if( !m_ActionId.isNull() )
        emit askItemsToApplyToolOn();
}


409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
void AlgorithmSelector::applyToolOn( ToolDescriptor *tool,
                                     const QList<GenericUIData*> &items,
                                     UIMainWindow *mainwin,
                                     GLViewer *glviewer,
                                     UIProject *project )
{
    ToolDescriptor *selectedBackup = m_SelectedTool;
    m_SelectedTool = tool;

    applyCurrentToolOn(items, mainwin, glviewer, project);

    m_SelectedTool = selectedBackup;
}


424
void AlgorithmSelector::applyCurrentToolOn( const QList<GenericUIData*> &items,
425
                                            UIMainWindow *mainwin,
426
                                            GLViewer *glviewer,
427
                                            UIProject *project )
428
429
430
{
    if( m_SelectedTool )
    {
431
432
433
        m_ToolContext.mainwin  = mainwin;
        m_ToolContext.glviewer = glviewer;
        m_ToolContext.project  = project;
434

435
436
437
438
439
        bool executionOk = true;
        if( m_SelectedTool->plugin )
        {
            QVector<QString> acceptedTypes;
            m_SelectedTool->plugin->acceptedDataTypes( m_SelectedTool->id, acceptedTypes );
440

441
442
443
            QMap<QString,int> acceptedTypeIds;
            for( int i=0; i<acceptedTypes.size(); ++i )
                acceptedTypeIds[ acceptedTypes[i] ] = i;
444

445
446
            UIToolDataSet dataSet;
            dataSet.items.resize( acceptedTypes.size() );
447

448
449
450
451
452
453
            for( GenericUIData *m : items )
            {
                auto found = acceptedTypeIds.find( m->GetTypeString() );
                if( found != acceptedTypeIds.end() )
                    dataSet.items[ found.value() ].push_back( m );
            }
454

455
456
            connect( m_SelectedTool->plugin, SIGNAL(notifyCreateProgressBars(int)), this, SLOT(createProgressBars(int)) );
            connect( m_SelectedTool->plugin, SIGNAL(notifyDeleteProgressBars()), this, SLOT(deleteProgressBars()) );
457

458
459
            if( project )
                project->StartNewDataTracking();
460

461
462
463
464
            if( m_ActionId.isNull() )
                executionOk = m_SelectedTool->plugin->exec( m_SelectedTool->id, dataSet, *m_SelectedTool->param, m_ToolContext );
            else
                executionOk = m_SelectedTool->plugin->execAction( m_SelectedTool->id, m_ActionId, dataSet, *m_SelectedTool->param, m_ToolContext );
465

466
467
            if( project )
                project->StopNewDataTracking();
468

469
470
471
472
473
474
475
476
            disconnect( m_SelectedTool->plugin, SIGNAL(notifyCreateProgressBars(int)), this, SLOT(createProgressBars(int)) );
            disconnect( m_SelectedTool->plugin, SIGNAL(notifyDeleteProgressBars()), this, SLOT(deleteProgressBars()) );
            deleteProgressBars();
        }
        else if( m_SelectedTool->script )
        {
            executionOk = m_SelectedTool->script->RunScript( m_ToolContext );
        }
477

478
479
480
        emit toolExecutionFinished( executionOk );
    }
}
481
482
483
484
485
486
487
488
489
490
491


void AlgorithmSelector::createProgressBars( int n )
{
    deleteProgressBars();

    if( n > 0 )
    {
        m_CurrentToolProgress = new UIMultiProgressDialog( n, m_ToolContext.mainwin );
        m_CurrentToolProgress->setWindowTitle( m_SelectedTool->plugin->name(m_SelectedTool->id) );

492
        connect( m_SelectedTool->plugin, SIGNAL(notifyProgressBar(unsigned int,QString,int,QString)), m_CurrentToolProgress, SLOT(setBar(unsigned int,QString,int,QString)) );
493
494
495
496
497
498
499
500
501
502
503
504
505
506
        connect( m_SelectedTool->plugin, SIGNAL(notifyProgressValue(unsigned int,int)), m_CurrentToolProgress, SLOT(setProgress(unsigned int,int)) );
    }
}


void AlgorithmSelector::deleteProgressBars()
{
    if( m_CurrentToolProgress )
    {
        m_CurrentToolProgress->close();
        m_CurrentToolProgress->deleteLater();
        m_CurrentToolProgress = NULL;
    }
}
507
508
509
510
511
512
513
514
515
516
517
518


void AlgorithmSelector::recompileCurrentScript()
{
    if( !m_SelectedTool  ||  !m_SelectedTool->script )
        return;

    QDateTime modificationTime = QFileInfo(m_SelectedTool->scriptSourceFile).lastModified();

    if( modificationTime <= m_SelectedTool->scriptSourceModificationTime )
        return;

519
520
    UIParamSet *toolParam = new UIParamSet( "Tool options", this );

521
    ScriptParser *parser = new ScriptParser();
522
    m_SelectedTool->isScriptBroken = !parser->ParseFile(m_SelectedTool->scriptSourceFile, toolParam);
523
524
525
    if( m_SelectedTool->isScriptBroken )
    {
        delete parser;
526
        delete toolParam;
527
528
529
    }
    else
    {
530
531
532
533
534
535
536
        m_ui->widgetToolGroupBoxes->layout()->removeWidget( m_SelectedTool->param );
        delete m_SelectedTool->param;

        m_SelectedTool->param = m_SelectedToolParam = toolParam;
        m_ui->widgetToolGroupBoxes->layout()->addWidget( m_SelectedTool->param );
        m_SelectedTool->param->SetVisible();

537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
        delete m_SelectedTool->script;
        m_SelectedTool->script = parser;
        m_SelectedTool->scriptSourceModificationTime = modificationTime;
    }

    int id = 0;
    for( ToolDescriptor *tool : m_ToolsByCategory[m_SelectedCategory] )
        if( tool != m_SelectedTool )
            ++id;
        else
            break;

    QIcon icon(m_SelectedTool->isScriptBroken? ":/images/resources/iconBrokenScript.png" : ":/images/resources/iconScript.png");
    m_ui->comboAvailableTools->setItemIcon(id, icon);

    if( m_SelectedTool->isScriptBroken )
        return;

    m_ui->comboAvailableTools->setItemText(id, m_SelectedTool->getName());

    QString description = m_SelectedTool->getDescription();
    if( description.isNull() || description.isEmpty() )
        m_ui->groupToolDescription->hide();
    else
    {
        m_ui->groupToolDescription->show();
        m_ui->labelToolDescription->setText( description );
        m_ui->labelToolDescription->setEnabled( true );
        m_ui->labelToolDescription->setToolTip( "" );
    }
}