]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/pkg/YQPkgSearchFilterView.cc
restart qt4 porting
[duncan/yast2-qt4.git] / src / pkg / YQPkgSearchFilterView.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQPkgSearchFilterView.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   Textdomain "packages-qt"
18
19 /-*/
20
21 #include <qcheckbox.h>
22 #include <qcombobox.h>
23 #include <qlabel.h>
24 #include <qlayout.h>
25 #include <qpushbutton.h>
26 #include <qradiobutton.h>
27 #include <qvbuttongroup.h>
28 #include <qvgroupbox.h>
29 #include <qprogressdialog.h>
30 #include <qdatetime.h>
31
32 #define y2log_component "qt-pkg"
33 #include <ycp/y2log.h>
34
35 #include "YQPkgSearchFilterView.h"
36 #include "QY2LayoutUtils.h"
37 #include "YQi18n.h"
38 #include "utf8.h"
39 #include "YQApplication.h"
40 #include "YQUI.h"
41
42 using std::list;
43 using std::string;
44
45
46 #define SPACING                 6       // between subwidgets
47 #define MARGIN                  4       // around the widget
48
49
50 YQPkgSearchFilterView::YQPkgSearchFilterView( QWidget * parent )
51     : QVBox( parent )
52 {
53     _matchCount = 0;
54     setMargin( MARGIN );
55     setSpacing( SPACING );
56
57     addVStretch( this );
58
59     // Headline
60     QLabel * label = new QLabel( _( "Searc&h:" ), this );
61     CHECK_PTR( label );
62     label->setFont( YQUI::yqApp()->headingFont() );
63
64     // Input field ( combo box ) for search text
65     _searchText = new QComboBox( this );
66     CHECK_PTR( _searchText );
67     _searchText->setEditable( true );
68     label->setBuddy( _searchText );
69
70
71     // Box for search button
72     QHBox * hbox = new QHBox( this );
73     CHECK_PTR( hbox );
74
75     addHStretch( hbox );
76
77     // Search button
78     _searchButton = new QPushButton( _( "&Search" ), hbox );
79     CHECK_PTR( _searchButton );
80
81     connect( _searchButton, SIGNAL( clicked() ),
82              this,          SLOT  ( filter()  ) );
83
84     addVStretch( this );
85
86     //
87     // Where to search
88     //
89
90     QVGroupBox * gbox = new QVGroupBox( _( "Search in" ), this );
91     CHECK_PTR( gbox );
92
93
94     _searchInName        = new QCheckBox( _( "&Name"            ), gbox ); CHECK_PTR( _searchInName        );
95     _searchInSummary     = new QCheckBox( _( "Su&mmary"         ), gbox ); CHECK_PTR( _searchInSummary     );
96     _searchInDescription = new QCheckBox( _( "Descr&iption"     ), gbox ); CHECK_PTR( _searchInDescription );
97
98     addVStretch( gbox );
99
100     // Intentionally NOT marking RPM tags for translation
101     _searchInProvides    = new QCheckBox(  "RPM \"&Provides\""   , gbox ); CHECK_PTR( _searchInProvides    );
102     _searchInRequires    = new QCheckBox(  "RPM \"Re&quires\""   , gbox ); CHECK_PTR( _searchInRequires    );
103
104     _searchInName->setChecked( true );
105     _searchInSummary->setChecked( true );
106
107     addVStretch( this );
108
109
110     //
111     // Search mode
112     //
113
114     label = new QLabel( _( "Search &Mode:" ), this );
115     CHECK_PTR( label );
116
117     _searchMode = new QComboBox( this );
118     CHECK_PTR( _searchMode );
119     _searchMode->setEditable( false );
120
121     label->setBuddy( _searchMode );
122
123     // Caution: combo box items must be inserted in the same order as enum SearchMode!
124     _searchMode->insertItem( _( "Contains"               ) );
125     _searchMode->insertItem( _( "Begins with"            ) );
126     _searchMode->insertItem( _( "Exact Match"            ) );
127     _searchMode->insertItem( _( "Use Wild Cards"         ) );
128     _searchMode->insertItem( _( "Use Regular Expression" ) );
129
130     _searchMode->setCurrentItem( Contains );
131
132
133     addVStretch( this );
134
135     _caseSensitive = new QCheckBox( _( "Case Sensiti&ve" ), this );
136     CHECK_PTR( _caseSensitive );
137
138     for ( int i=0; i < 6; i++ )
139         addVStretch( this );
140 }
141
142
143 YQPkgSearchFilterView::~YQPkgSearchFilterView()
144 {
145     // NOP
146 }
147
148
149 void
150 YQPkgSearchFilterView::keyPressEvent( QKeyEvent * event )
151 {
152     if ( event )
153     {
154         if ( event->state() == 0 )      // No Ctrl / Alt / Shift etc. pressed
155         {
156             if ( event->key() == Qt::Key_Return ||
157                  event->key() == Qt::Key_Enter    )
158             {
159                 _searchButton->animateClick();
160                 return;
161             }
162         }
163
164     }
165
166     QVBox::keyPressEvent( event );
167 }
168
169
170 void
171 YQPkgSearchFilterView::setFocus()
172 {
173     _searchText->setFocus();
174 }
175
176
177 QSize
178 YQPkgSearchFilterView::minimumSizeHint() const
179 {
180     return QSize( 0, 0 );
181 }
182
183
184 void
185 YQPkgSearchFilterView::filterIfVisible()
186 {
187     if ( isVisible() )
188         filter();
189 }
190
191
192 void
193 YQPkgSearchFilterView::filter()
194 {
195     emit filterStart();
196     _matchCount = 0;
197
198     if ( ! _searchText->currentText().isEmpty() )
199     {
200         // Create a progress dialog that is only displayed if the search takes
201         // longer than a couple of seconds ( default: 4 ).
202
203         QProgressDialog progress( _( "Searching..." ),                  // text
204                                   _( "&Cancel" ),                       // cancelButtonLabel
205 #ifdef FIXME
206                                   Y2PM::packageManager().size(),        // totalSteps
207 #else
208                                   1000,
209 #endif
210                                   this, 0,                              // parent, name
211                                   true );                               // modal
212         progress.setCaption( "" );
213         progress.setMinimumDuration( 2000 ); // millisec
214         QTime timer;
215
216         QRegExp regexp = _searchText->currentText();
217         regexp.setCaseSensitive( _caseSensitive->isChecked() );
218         regexp.setWildcard( _searchMode->currentItem() == UseWildcards );
219
220         timer.start();
221
222
223         int count = 0;
224
225         for ( ZyppPoolIterator it = zyppPkgBegin();
226               it != zyppPkgEnd() && ! progress.wasCancelled();
227               ++it )
228         {
229             ZyppSel selectable = *it;
230
231             bool match =
232                 check( selectable, selectable->candidateObj(), regexp ) ||
233                 check( selectable, selectable->installedObj(), regexp );
234
235             // If there is neither an installed nor a candidate package, check
236             // any other instance.
237
238             if ( ! match                      &&
239                  ! selectable->candidateObj() &&
240                  ! selectable->installedObj()   )
241                 check( selectable, selectable->theObj(), regexp );
242
243
244             progress.setProgress( count++ );
245
246             if ( timer.elapsed() > 300 ) // milisec
247             {
248                 // Process events only every 300 milliseconds - this is very
249                 // expensive since both the progress dialog and the package
250                 // list change all the time, thus display updates are necessary
251                 // each time.
252
253                 qApp->processEvents();
254                 timer.restart();
255             }
256         }
257
258         if ( _matchCount == 0 )
259             emit message( _( "No Results." ) );
260     }
261
262     emit filterFinished();
263 }
264
265
266 bool
267 YQPkgSearchFilterView::check( ZyppSel   selectable,
268                               ZyppObj   zyppObj )
269 {
270     QRegExp regexp = _searchText->currentText();
271     regexp.setCaseSensitive( _caseSensitive->isChecked() );
272     regexp.setWildcard( _searchMode->currentItem() == UseWildcards );
273
274     return check( selectable, zyppObj, regexp );
275 }
276
277
278 bool
279 YQPkgSearchFilterView::check( ZyppSel           selectable,
280                               ZyppObj           zyppObj,
281                               const QRegExp &   regexp )
282 {
283     if ( ! zyppObj )
284         return false;
285
286     bool match =
287         ( _searchInName->isChecked()        && check( zyppObj->name(),        regexp ) ) ||
288         ( _searchInSummary->isChecked()     && check( zyppObj->summary(),     regexp ) ) ||
289         ( _searchInDescription->isChecked() && check( zyppObj->description(), regexp ) ) ||
290         ( _searchInProvides->isChecked()    && check( zyppObj->dep( zypp::Dep::PROVIDES ), regexp ) ) ||
291         ( _searchInRequires->isChecked()    && check( zyppObj->dep( zypp::Dep::REQUIRES ), regexp ) );
292
293     if ( match )
294     {
295         ZyppPkg zyppPkg = tryCastToZyppPkg( zyppObj );
296
297         if ( zyppPkg )
298         {
299             _matchCount++;
300             emit filterMatch( selectable, zyppPkg );
301         }
302     }
303
304     return match;
305 }
306
307
308 bool
309 YQPkgSearchFilterView::check( const string &    attribute,
310                               const QRegExp &   regexp )
311 {
312     QString att         = fromUTF8( attribute );
313     QString searchText  = _searchText->currentText();
314     bool match          = false;
315
316     switch ( _searchMode->currentItem() )
317     {
318         case Contains:
319             match = att.contains( searchText, _caseSensitive->isChecked() );
320             break;
321
322         case BeginsWith:
323             match = att.startsWith( searchText );       // only case sensitive
324             break;
325
326         case ExactMatch:
327             match = ( att == searchText );
328             break;
329
330         case UseWildcards:
331         case UseRegExp:
332             // Both cases differ in how the regexp is set up during initialization
333             match = att.contains( regexp );
334             break;
335
336             // Intentionally omitting "default" branch - let gcc watch for unhandled enums
337     }
338
339     return match;
340 }
341
342
343 bool
344 YQPkgSearchFilterView::check( const zypp::CapSet & capSet, const QRegExp & regexp )
345 {
346     for ( zypp::CapSet::const_iterator it = capSet.begin();
347           it != capSet.end();
348           ++it )
349     {
350         if ( check( ( *it).index(), regexp ) )
351         {
352             // y2debug( "Match for %s", (*it).asString().c_str() );
353             return true;
354         }
355     }
356
357     return false;
358 }
359
360
361
362 #include "YQPkgSearchFilterView.moc"