AlgorithmSelector.cpp 16.7 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
    if( !script->ParseFile(scriptFileName)  ||  script->GetCategory().isEmpty()  ||  script->GetName().isEmpty() )
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    {
        delete script;
        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;
        }

131
    if( !categoryDeclared )
132
    {
133
134
135
        delete script;
        return false;
    }
136

137
138
139
140
141
142
143
144
    ToolDescriptor *tool = &m_ToolsByName[ script->GetName() ];
    tool->script = script;
    tool->scriptSourceFile = scriptFileName;
    tool->scriptSourceModificationTime = QFileInfo(scriptFileName).lastModified();
    tool->param = new UIParamSet( "Tool options", this );
    //plugin->declareParameters( i, *tool.param );
    tool->param->SetHidden();
    //tool.param->setMaximumWidth(360);
145

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

148
149
150
151
152
    //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 );
153
154
155
156
157

    return true;
}


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


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

174
        category.clear();
175

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


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

192
193
194
    QPushButton *firstCategoryButton = NULL;
    int firstCategoryId = -1;

195
    for( int categoryId : ToolCategory::categoryIds() )
196
197
        if( !m_ToolsByCategory[categoryId].empty() )
        {
198
            QVBoxLayout *l = new QVBoxLayout();
199
200
201
202
203
204
205
206
207
            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 );
208
            categoryButton->setMaximumSize( 80, 80 );
209
            categoryButton->setCheckable( true );
210
            l->addWidget( categoryButton, 0, Qt::AlignHCenter );
211
212
            m_CategoryButtonGroup->addButton( categoryButton, categoryId );

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

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

            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 );
        }

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

    if( firstCategoryButton )
    {
        firstCategoryButton->setChecked( true );
        selectCategory( firstCategoryId );
    }
242
243
244
}


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

250
251
252
253
254
255
256
    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();
257
    for( ToolDescriptor *tool : m_ToolsByCategory[categoryId] )
258
    {
259
260
261
262
263
        if( tool->script )
        {
            QIcon icon(tool->isScriptBroken? ":/images/resources/iconBrokenScript.png" : ":/images/resources/iconScript.png");
            m_ui->comboAvailableTools->addItem( icon, tool->getName() );
        }
264
        else
265
            m_ui->comboAvailableTools->addItem( tool->getName() );
266
    }
267
268
269
270
271

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

    connect( m_ui->comboAvailableTools, SIGNAL(currentIndexChanged(int)), this, SLOT(selectTool(int)) );
272
273

    return true;
274
275
276
}


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

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

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

292
        QString description = m_SelectedTool->getDescription();
293
294
295
296
297
298
299
300
301
        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;
302
            m_SelectedTool->getAcceptedDataTypes(acceptedTypes);
303
304
305
306
307
308
309
310
311
312
313
            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 );
            }
        }

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

        m_LastUsedInCategory[m_SelectedCategory] = n;
321
322

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

    return true;
331
332
333
}


334
QString AlgorithmSelector::state() const
335
{
336
337
338
339
340
341
342
343
344
345
    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;
}

346

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
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 )
366
    {
367
368
369
370
        v = tokens.front().toInt( &ok );
        if( !ok )
            return false;
        tokens.pop_front();
371
    }
372
373
374
375
376
377
378
379
380
381

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

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

    m_LastUsedInCategory = lastUsedInCategory;

    return true;
382
383
384
}


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


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

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


407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
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;
}


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

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

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

443
444
            UIToolDataSet dataSet;
            dataSet.items.resize( acceptedTypes.size() );
445

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

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

456
457
            if( project )
                project->StartNewDataTracking();
458

459
460
461
462
            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 );
463

464
465
            if( project )
                project->StopNewDataTracking();
466

467
468
469
470
471
472
473
474
            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 );
        }
475

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


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) );

490
        connect( m_SelectedTool->plugin, SIGNAL(notifyProgressBar(unsigned int,QString,int,QString)), m_CurrentToolProgress, SLOT(setBar(unsigned int,QString,int,QString)) );
491
492
493
494
495
496
497
498
499
500
501
502
503
504
        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;
    }
}
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556


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

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

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

    ScriptParser *parser = new ScriptParser();
    m_SelectedTool->isScriptBroken = !parser->ParseFile(m_SelectedTool->scriptSourceFile);
    if( m_SelectedTool->isScriptBroken )
    {
        delete parser;
    }
    else
    {
        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( "" );
    }
}