AlgorithmSelector.cpp 12.2 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 14 15 16 17 18 19 20 21
#include <QLabel>




AlgorithmSelector::AlgorithmSelector(QWidget *parent) :
    QWidget( parent ),
    m_ui( new Ui::AlgorithmSelector ),
    m_SelectedTool( NULL ),
22 23
    m_SelectedToolParam( NULL ),
    m_CurrentToolProgress( NULL )
24 25 26 27 28 29 30 31 32
{
    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)) );

33 34 35
    m_ToolsByCategory.resize( ToolCategory::categoryCount() );
    m_LastUsedInCategory.resize( ToolCategory::categoryCount() );
    for( int i=0; i<ToolCategory::categoryCount(); ++i )
36 37 38 39 40 41
        m_LastUsedInCategory[i] = 0;
}


AlgorithmSelector::~AlgorithmSelector()
{
42
    delete m_CurrentToolProgress;
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
    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 )
    {
65 66
        int categoryId = plugin->category(i);
        if( ToolCategory::isCategoryDeclared(categoryId) )
67 68 69 70 71
        {
            ToolDescriptor tool;
            tool.plugin = plugin;
            tool.id     = i;
            tool.param  = new UIParamSet( "Tool options", this );
72
            plugin->declareParameters( i, *tool.param );
73
            tool.param->SetHidden();
74
			//tool.param->setMaximumWidth(360);
75

76 77
            connect( tool.param, SIGNAL(parameterUpdated(UIParam*)), tool.plugin, SLOT(updateParameter(UIParam*)) );

78
            foreach( UIParamAction* act, tool.param->GetActions() )
79
                connect( act->Widget(), SIGNAL(clicked(bool)), this, SLOT(emitActionSignal()) );
80

81
            m_ToolsByName[ plugin->name(i) ] = tool;
82 83 84 85 86 87 88
            m_ToolsByCategory[categoryId].push_back( tool );
            m_ui->widgetToolGroupBoxes->layout()->addWidget( tool.param );
        }
    }
}


89 90 91 92 93 94 95 96
void AlgorithmSelector::releaseAllTools()
{
    for( auto &category : m_ToolsByCategory )
        for( auto &tool : category )
            delete tool.param;
}


97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
void AlgorithmSelector::finalizeTools()
{
    // Sort tools by name for each category.
    for( QVector<QVector<ToolDescriptor>>::iterator category=m_ToolsByCategory.begin(); category!=m_ToolsByCategory.end(); ++category )
    {
        QMap<QString,ToolDescriptor> toolByName;
        foreach( ToolDescriptor tool, *category )
            toolByName[tool.plugin->name(tool.id)] = tool;

        category->clear();

        for( QMap<QString,ToolDescriptor>::iterator tool=toolByName.begin(); tool!=toolByName.end(); ++tool )
            category->push_back( *tool );
    }


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

124 125 126
    QPushButton *firstCategoryButton = NULL;
    int firstCategoryId = -1;

127
    for( int categoryId : ToolCategory::categoryIds() )
128 129
        if( !m_ToolsByCategory[categoryId].empty() )
        {
130
            QVBoxLayout *l = new QVBoxLayout();
131 132 133 134 135 136 137 138 139
            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 );
140
            categoryButton->setMaximumSize( 80, 80 );
141
            categoryButton->setCheckable( true );
142
            l->addWidget( categoryButton, 0, Qt::AlignHCenter );
143 144
            m_CategoryButtonGroup->addButton( categoryButton, categoryId );

145 146 147 148 149 150
            if( !firstCategoryButton )
            {
                firstCategoryButton = categoryButton;
                firstCategoryId = categoryId;
            }

151
            QLabel *categoryLabel = new QLabel( ToolCategory::categoryName(categoryId) );
152
            QFont f = QApplication::font();
153 154 155
            f.setPointSize( 7 );
            categoryLabel->setFont( f );
            categoryLabel->setAlignment( Qt::AlignHCenter );
156
            //categoryLabel->setWordWrap( true );
157
            l->addWidget( categoryLabel, 0, Qt::AlignHCenter );
158 159 160 161 162 163 164 165 166

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

167 168 169 170 171 172 173
	m_ui->widgetCategories->layout()->setAlignment(Qt::AlignHCenter | Qt::AlignTop);

    if( firstCategoryButton )
    {
        firstCategoryButton->setChecked( true );
        selectCategory( firstCategoryId );
    }
174 175 176
}


177
bool AlgorithmSelector::selectCategory( int categoryId )
178
{
179 180 181
    if( !ToolCategory::isCategoryDeclared(categoryId) )
        return false;

182 183 184 185 186 187 188 189 190 191 192 193 194 195
    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();
    foreach( ToolDescriptor tool, m_ToolsByCategory[categoryId] )
        m_ui->comboAvailableTools->addItem( tool.plugin->name(tool.id) );

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

    connect( m_ui->comboAvailableTools, SIGNAL(currentIndexChanged(int)), this, SLOT(selectTool(int)) );
196 197

    return true;
198 199 200
}


201
bool AlgorithmSelector::selectTool( int n )
202 203 204
{
    if( m_SelectedToolParam )
    {
205
        m_SelectedToolParam->SetHidden();
206 207 208
        m_SelectedToolParam = NULL;
    }

209 210 211
    if( n >= m_ToolsByCategory[m_SelectedCategory].size() )
        return false;

212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
    if( n >= 0 )
    {
        m_SelectedTool = &m_ToolsByCategory[m_SelectedCategory][n];

        QString description = m_SelectedTool->plugin->description( m_SelectedTool->id );
        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;
            m_SelectedTool->plugin->acceptedDataTypes( m_SelectedTool->id, acceptedTypes );
            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 );
            }
        }

238
        if( !m_SelectedTool->param->IsEmpty() )
239 240
        {
            m_SelectedToolParam = m_SelectedTool->param;
241
            m_SelectedToolParam->SetVisible();
242 243 244 245 246 247 248 249 250
        }

        m_LastUsedInCategory[m_SelectedCategory] = n;
    }
    else
    {
        m_ui->groupToolDescription->hide();
        m_SelectedTool = NULL;
    }
251 252

    return true;
253 254 255
}


256
QString AlgorithmSelector::state() const
257
{
258 259 260 261 262 263 264 265 266 267
    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;
}

268

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
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 )
288
    {
289 290 291 292
        v = tokens.front().toInt( &ok );
        if( !ok )
            return false;
        tokens.pop_front();
293
    }
294 295 296 297 298 299 300 301 302 303

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

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

    m_LastUsedInCategory = lastUsedInCategory;

    return true;
304 305 306
}


307 308 309 310 311 312 313 314 315 316 317 318 319
void AlgorithmSelector::emitApplySignal()
{
	if( m_SelectedTool )
	{
		m_ActionId = QString();
		emit askItemsToApplyToolOn();
	}
}


void AlgorithmSelector::emitActionSignal()
{
    m_ActionId = QString();
320
    foreach( UIParamAction* act, m_SelectedTool->param->GetActions() )
321 322
        if( act->Widget() == (QPushButton*)sender() )
            m_ActionId = act->Id();
323 324 325 326 327 328 329

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


void AlgorithmSelector::applyCurrentToolOn( const QList<GenericUIData*> &items,
330
                                            UIMainWindow *mainwin,
331
                                            GLViewer *glviewer,
332
                                            UIProject *project )
333 334 335
{
    if( m_SelectedTool )
    {
336 337 338
        m_ToolContext.mainwin  = mainwin;
        m_ToolContext.glviewer = glviewer;
        m_ToolContext.project  = project;
339 340 341

        QVector<QString> acceptedTypes;
        m_SelectedTool->plugin->acceptedDataTypes( m_SelectedTool->id, acceptedTypes );
342

343 344 345 346
        QMap<QString,int> acceptedTypeIds;
        for( int i=0; i<acceptedTypes.size(); ++i )
            acceptedTypeIds[ acceptedTypes[i] ] = i;

347 348
        UIToolDataSet dataSet;
        dataSet.items.resize( acceptedTypes.size() );
349

350
        for( GenericUIData *m : items )
351
        {
352 353 354
            auto found = acceptedTypeIds.find( m->GetTypeString() );
            if( found != acceptedTypeIds.end() )
                dataSet.items[ found.value() ].push_back( m );
355 356
        }

357 358 359
        connect( m_SelectedTool->plugin, SIGNAL(notifyCreateProgressBars(int)), this, SLOT(createProgressBars(int)) );
        connect( m_SelectedTool->plugin, SIGNAL(notifyDeleteProgressBars()), this, SLOT(deleteProgressBars()) );

360 361
        bool executionOk;
        if( m_ActionId.isNull() )
362
            executionOk = m_SelectedTool->plugin->exec( m_SelectedTool->id, dataSet, *m_SelectedToolParam, m_ToolContext );
363
        else
364
            executionOk = m_SelectedTool->plugin->execAction( m_SelectedTool->id, m_ActionId, dataSet, *m_SelectedToolParam, m_ToolContext );
365

366 367 368
        disconnect( m_SelectedTool->plugin, SIGNAL(notifyCreateProgressBars(int)), this, SLOT(createProgressBars(int)) );
        disconnect( m_SelectedTool->plugin, SIGNAL(notifyDeleteProgressBars()), this, SLOT(deleteProgressBars()) );
        deleteProgressBars();
369

370 371 372
        emit toolExecutionFinished( executionOk );
    }
}
373 374 375 376 377 378 379 380 381 382 383


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

384
        connect( m_SelectedTool->plugin, SIGNAL(notifyProgressBar(unsigned int,QString,int,QString)), m_CurrentToolProgress, SLOT(setBar(unsigned int,QString,int,QString)) );
385 386 387 388 389 390 391 392 393 394 395 396 397 398
        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;
    }
}