1 //////////////////////////////////////////////////////////////////////////////
2 // oxygenexceptionlistwidget.cpp
3 // -------------------
4 //
5 // SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
6 //
7 // SPDX-License-Identifier: MIT
8 //////////////////////////////////////////////////////////////////////////////
9 
10 #include "oxygenexceptionlistwidget.h"
11 #include "oxygenexceptiondialog.h"
12 
13 #include <KLocalizedString>
14 
15 #include <QMessageBox>
16 #include <QPointer>
17 #include <QIcon>
18 
19 //__________________________________________________________
20 namespace Oxygen
21 {
22 
23     //__________________________________________________________
ExceptionListWidget(QWidget * parent)24     ExceptionListWidget::ExceptionListWidget( QWidget* parent ):
25         QWidget( parent )
26     {
27 
28         // ui
29         m_ui.setupUi( this );
30 
31         // list
32         m_ui.exceptionListView->setAllColumnsShowFocus( true );
33         m_ui.exceptionListView->setRootIsDecorated( false );
34         m_ui.exceptionListView->setSortingEnabled( false );
35         m_ui.exceptionListView->setModel( &model() );
36         m_ui.exceptionListView->sortByColumn( ExceptionModel::ColumnType, Qt::AscendingOrder );
37         m_ui.exceptionListView->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Ignored ) );
38 
39         m_ui.moveUpButton->setIcon( QIcon::fromTheme( QStringLiteral( "arrow-up" ) ) );
40         m_ui.moveDownButton->setIcon( QIcon::fromTheme( QStringLiteral( "arrow-down" ) ) );
41         m_ui.addButton->setIcon( QIcon::fromTheme( QStringLiteral( "list-add" ) ) );
42         m_ui.removeButton->setIcon( QIcon::fromTheme( QStringLiteral( "list-remove" ) ) );
43         m_ui.editButton->setIcon( QIcon::fromTheme( QStringLiteral( "edit-rename" ) ) );
44 
45         connect( m_ui.addButton, SIGNAL(clicked()), SLOT(add()) );
46         connect( m_ui.editButton, SIGNAL(clicked()), SLOT(edit()) );
47         connect( m_ui.removeButton, SIGNAL(clicked()), SLOT(remove()) );
48         connect( m_ui.moveUpButton, SIGNAL(clicked()), SLOT(up()) );
49         connect( m_ui.moveDownButton, SIGNAL(clicked()), SLOT(down()) );
50 
51         connect( m_ui.exceptionListView, SIGNAL(activated(QModelIndex)), SLOT(edit()) );
52         connect( m_ui.exceptionListView, SIGNAL(clicked(QModelIndex)), SLOT(toggle(QModelIndex)) );
53         connect( m_ui.exceptionListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(updateButtons()) );
54 
55         updateButtons();
56         resizeColumns();
57 
58 
59     }
60 
61     //__________________________________________________________
setExceptions(const InternalSettingsList & exceptions)62     void ExceptionListWidget::setExceptions( const InternalSettingsList& exceptions )
63     {
64         model().set( exceptions );
65         resizeColumns();
66         setChanged( false );
67     }
68 
69     //__________________________________________________________
exceptions(void)70     InternalSettingsList ExceptionListWidget::exceptions( void )
71     {
72         return model().get();
73         setChanged( false );
74     }
75 
76     //__________________________________________________________
updateButtons(void)77     void ExceptionListWidget::updateButtons( void )
78     {
79 
80         bool hasSelection( !m_ui.exceptionListView->selectionModel()->selectedRows().empty() );
81         m_ui.removeButton->setEnabled( hasSelection );
82         m_ui.editButton->setEnabled( hasSelection );
83 
84         m_ui.moveUpButton->setEnabled( hasSelection && !m_ui.exceptionListView->selectionModel()->isRowSelected( 0, QModelIndex() ) );
85         m_ui.moveDownButton->setEnabled( hasSelection && !m_ui.exceptionListView->selectionModel()->isRowSelected( model().rowCount()-1, QModelIndex() ) );
86 
87     }
88 
89 
90     //_______________________________________________________
add(void)91     void ExceptionListWidget::add( void )
92     {
93 
94 
95         QPointer<ExceptionDialog> dialog = new ExceptionDialog( this );
96         dialog->setWindowTitle( i18n( "New Exception - Oxygen Settings" ) );
97         InternalSettingsPtr exception( new InternalSettings() );
98 
99         exception->load();
100 
101         dialog->setException( exception );
102 
103         // run dialog and check existence
104         if( !dialog->exec() )
105         {
106             delete dialog;
107             return;
108         }
109 
110         dialog->save();
111         delete dialog;
112 
113         // check exceptions
114         if( !checkException( exception ) ) return;
115 
116         // create new item
117         model().add( exception );
118         setChanged( true );
119 
120         // make sure item is selected
121         QModelIndex index( model().index( exception ) );
122         if( index != m_ui.exceptionListView->selectionModel()->currentIndex() )
123         {
124             m_ui.exceptionListView->selectionModel()->select( index,  QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
125             m_ui.exceptionListView->selectionModel()->setCurrentIndex( index,  QItemSelectionModel::Current|QItemSelectionModel::Rows );
126         }
127 
128         resizeColumns();
129         return;
130 
131     }
132 
133     //_______________________________________________________
edit(void)134     void ExceptionListWidget::edit( void )
135     {
136 
137         // retrieve selection
138         QModelIndex current( m_ui.exceptionListView->selectionModel()->currentIndex() );
139         if( ! model().contains( current ) ) return;
140 
141         InternalSettingsPtr exception( model().get( current ) );
142 
143         // create dialog
144         QPointer<ExceptionDialog> dialog( new ExceptionDialog( this ) );
145         dialog->setWindowTitle( i18n( "Edit Exception - Oxygen Settings" ) );
146         dialog->setException( exception );
147 
148         // map dialog
149         if( !dialog->exec() )
150         {
151             delete dialog;
152             return;
153         }
154 
155         // check modifications
156         if( !dialog->isChanged() ) return;
157 
158         // retrieve exception
159         dialog->save();
160         delete dialog;
161 
162         // check new exception validity
163         checkException( exception );
164         resizeColumns();
165 
166         setChanged( true );
167 
168         return;
169 
170     }
171 
172     //_______________________________________________________
remove(void)173     void ExceptionListWidget::remove( void )
174     {
175 
176         // confirmation dialog
177         {
178             QMessageBox messageBox( QMessageBox::Question, i18n("Question - Oxygen Settings" ), i18n("Remove selected exception?"), QMessageBox::Yes | QMessageBox::Cancel );
179             messageBox.button( QMessageBox::Yes )->setText( i18n("Remove") );
180             messageBox.setDefaultButton( QMessageBox::Cancel );
181             if( messageBox.exec() == QMessageBox::Cancel ) return;
182         }
183 
184         // remove
185         model().remove( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
186         resizeColumns();
187         updateButtons();
188 
189         setChanged( true );
190 
191         return;
192 
193     }
194 
195     //_______________________________________________________
toggle(const QModelIndex & index)196     void ExceptionListWidget::toggle( const QModelIndex& index )
197     {
198 
199         if( !model().contains( index ) ) return;
200         if( index.column() != ExceptionModel::ColumnEnabled ) return;
201 
202         // get matching exception
203         InternalSettingsPtr exception( model().get( index ) );
204         exception->setEnabled( !exception->enabled() );
205         setChanged( true );
206         return;
207 
208     }
209 
210     //_______________________________________________________
up(void)211     void ExceptionListWidget::up( void )
212     {
213 
214         InternalSettingsList selection( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
215         if( selection.empty() ) { return; }
216 
217         // retrieve selected indexes in list and store in model
218         QModelIndexList selectedIndices( m_ui.exceptionListView->selectionModel()->selectedRows() );
219         InternalSettingsList selectedExceptions( model().get( selectedIndices ) );
220 
221         InternalSettingsList currentException( model().get() );
222         InternalSettingsList newExceptions;
223 
224         for( InternalSettingsList::const_iterator iter = currentException.constBegin(); iter != currentException.constEnd(); ++iter )
225         {
226 
227             // check if new list is not empty, current index is selected and last index is not.
228             // if yes, move.
229             if(
230                 !( newExceptions.empty() ||
231                 selectedIndices.indexOf( model().index( *iter ) ) == -1 ||
232                 selectedIndices.indexOf( model().index( newExceptions.back() ) ) != -1
233                 ) )
234             {
235                 InternalSettingsPtr last( newExceptions.back() );
236                 newExceptions.removeLast();
237                 newExceptions.append( *iter );
238                 newExceptions.append( last );
239             } else newExceptions.append( *iter );
240 
241         }
242 
243         model().set( newExceptions );
244 
245         // restore selection
246         m_ui.exceptionListView->selectionModel()->select( model().index( selectedExceptions.front() ),  QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
247         for( InternalSettingsList::const_iterator iter = selectedExceptions.constBegin(); iter != selectedExceptions.constEnd(); ++iter )
248         { m_ui.exceptionListView->selectionModel()->select( model().index( *iter ), QItemSelectionModel::Select|QItemSelectionModel::Rows ); }
249 
250         setChanged( true );
251 
252         return;
253 
254     }
255 
256     //_______________________________________________________
down(void)257     void ExceptionListWidget::down( void )
258     {
259 
260         InternalSettingsList selection( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
261         if( selection.empty() )
262         { return; }
263 
264         // retrieve selected indexes in list and store in model
265         QModelIndexList selectedIndices( m_ui.exceptionListView->selectionModel()->selectedIndexes() );
266         InternalSettingsList selectedExceptions( model().get( selectedIndices ) );
267 
268         InternalSettingsList currentExceptions( model().get() );
269         InternalSettingsList newExceptions;
270 
271         InternalSettingsListIterator iter( currentExceptions );
272         iter.toBack();
273         while( iter.hasPrevious() )
274         {
275 
276             InternalSettingsPtr current( iter.previous() );
277 
278             // check if new list is not empty, current index is selected and last index is not.
279             // if yes, move.
280             if(
281                 !( newExceptions.empty() ||
282                 selectedIndices.indexOf( model().index( current ) ) == -1 ||
283                 selectedIndices.indexOf( model().index( newExceptions.front() ) ) != -1
284                 ) )
285             {
286 
287                 InternalSettingsPtr first( newExceptions.front() );
288                 newExceptions.removeFirst();
289                 newExceptions.prepend( current );
290                 newExceptions.prepend( first );
291 
292             } else newExceptions.prepend( current );
293         }
294 
295         model().set( newExceptions );
296 
297         // restore selection
298         m_ui.exceptionListView->selectionModel()->select( model().index( selectedExceptions.front() ),  QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
299         for( InternalSettingsList::const_iterator iter = selectedExceptions.constBegin(); iter != selectedExceptions.constEnd(); ++iter )
300         { m_ui.exceptionListView->selectionModel()->select( model().index( *iter ), QItemSelectionModel::Select|QItemSelectionModel::Rows ); }
301 
302         setChanged( true );
303 
304         return;
305 
306     }
307 
308     //_______________________________________________________
resizeColumns(void) const309     void ExceptionListWidget::resizeColumns( void ) const
310     {
311         m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnEnabled );
312         m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnType );
313         m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnRegExp );
314     }
315 
316     //_______________________________________________________
checkException(InternalSettingsPtr exception)317     bool ExceptionListWidget::checkException( InternalSettingsPtr exception )
318     {
319 
320         while( exception->exceptionPattern().isEmpty() || !QRegularExpression( exception->exceptionPattern() ).isValid() )
321         {
322 
323             QMessageBox::warning( this, i18n( "Warning - Oxygen Settings" ), i18n("Regular Expression syntax is incorrect") );
324             QPointer<ExceptionDialog> dialog( new ExceptionDialog( this ) );
325             dialog->setException( exception );
326             if( dialog->exec() == QDialog::Rejected )
327             {
328                 delete dialog;
329                 return false;
330             }
331 
332             dialog->save();
333             delete dialog;
334         }
335 
336         return true;
337     }
338 
339 }
340