]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/pkg/YQPkgObjList.cc
YQPkgObjList QT3_SUPPORT
[duncan/yast2-qt4.git] / src / pkg / YQPkgObjList.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQPkgObjList.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   Textdomain "packages-qt"
18
19 /-*/
20
21 #define y2log_component "qt-pkg"
22 #include <ycp/y2log.h>
23 #include <QPixmap>
24 #include <QHeaderView>
25 #include <QMenu>
26 #include <QAction>
27 //Added by qt3to4:
28 #include <qevent.h>
29
30 #include "utf8.h"
31
32 #include "YQPkgObjList.h"
33 #include "YQPkgTextDialog.h"
34 #include "YQi18n.h"
35 #include "YQIconPool.h"
36 #include "YQUI.h"
37
38 using std::list;
39 using std::string;
40
41
42 #define VERBOSE_EXCLUDE_RULES   0
43 #define EXTRA_SOLVE_COLLECTIONS 0
44
45
46 YQPkgObjList::YQPkgObjList( QWidget * parent )
47     : QY2ListView( parent )
48     , _editable( true )
49     , _installedContextMenu(0)
50     , _notInstalledContextMenu(0)
51 {
52     // This class does not add any columns. This is the main reason why this is
53     // an abstract base class: It doesn't know which columns are desired and in
54     // what order.
55
56     _statusCol          = -42;
57     _nameCol            = -42;
58     _versionCol         = -42;
59     _instVersionCol     = -42;
60     _summaryCol         = -42;
61     _sizeCol            = -42;
62     _brokenIconCol      = -42;
63     _satisfiedIconCol   = -42;
64     _debug              = false;
65
66     _excludedItems = new YQPkgObjList::ExcludedItems( this );
67
68     createActions();
69
70     connect( this,      SIGNAL( columnClicked           ( int, QTreeWidgetItem *, int, const QPoint & ) ),
71              this,      SLOT  ( pkgObjClicked           ( int, QTreeWidgetItem *, int, const QPoint & ) ) );
72
73     connect( this,      SIGNAL( columnDoubleClicked     ( int, QTreeWidgetItem *, int, const QPoint & ) ),
74              this,      SLOT  ( pkgObjClicked           ( int, QTreeWidgetItem *, int, const QPoint & ) ) );
75
76     connect( this,      SIGNAL( currentItemChanged      ( QTreeWidgetItem *, QTreeWidgetItem * ) ),
77              this,      SLOT  ( currentItemChangedInternal( QTreeWidgetItem * ) ) );
78 }
79
80
81 YQPkgObjList::~YQPkgObjList()
82 {
83     if ( _excludedItems )
84         delete _excludedItems;
85 }
86
87
88 void
89 YQPkgObjList::addPkgObjItem( ZyppSel selectable, ZyppObj zyppObj )
90 {
91     if ( ! selectable )
92     {
93         y2error( "Null zypp::ui::Selectable!" );
94         return;
95     }
96
97     YQPkgObjListItem * item = new YQPkgObjListItem( this, selectable, zyppObj );
98     applyExcludeRules( item );
99 }
100
101
102 void
103 YQPkgObjList::addPassiveItem( const QString &   name,
104                               const QString &   summary,
105                               FSize             size )
106 {
107     QY2ListViewItem * item = new QY2ListViewItem( this, QString::null );
108
109     if ( item )
110     {
111         if ( nameCol()    >= 0 && ! name.isEmpty()    ) item->setText( nameCol(),       name    );
112         if ( summaryCol() >= 0 && ! summary.isEmpty() ) item->setText( summaryCol(),    summary );
113         if ( sizeCol()    >= 0 && size > 0L           )
114         {
115             QString sizeStr = size.form().c_str();
116             sizeStr += "  ";
117             item->setText( sizeCol(), sizeStr );
118         }
119     }
120 }
121
122
123 void
124 YQPkgObjList::pkgObjClicked( int                button,
125                              QTreeWidgetItem *  listViewItem,
126                              int                col,
127                              const QPoint &     pos )
128 {
129     YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *> (listViewItem);
130
131     if ( item )
132     {
133         if ( button == Qt::LeftButton )
134         {
135             if ( col == statusCol() )
136                 // || col == nameCol() )
137             {
138                 if ( editable() && item->editable() )
139                     item->cycleStatus();
140             }
141         }
142         else if ( button == Qt::RightButton )
143         {
144             if ( editable() && item->editable() )
145             {
146                 updateActions( item );
147
148                 QMenu * contextMenu =
149                     item->selectable()->hasInstalledObj() ?
150                     installedContextMenu() : notInstalledContextMenu();
151
152                 if ( contextMenu )
153                     contextMenu->popup( pos );
154             }
155         }
156     }
157 }
158
159
160 void
161 YQPkgObjList::currentItemChangedInternal( QTreeWidgetItem * listViewItem )
162 {
163     YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *> (listViewItem);
164
165     emit currentItemChanged( item ? item->selectable() : ZyppSel() );
166 }
167
168
169 void
170 YQPkgObjList::clear()
171 {
172     emit currentItemChanged( ZyppSel() );
173
174     _excludedItems->clear();
175     QY2ListView::clear();
176 }
177
178
179 QPixmap
180 YQPkgObjList::statusIcon( ZyppStatus status, bool enabled, bool bySelection )
181 {
182     QPixmap icon = YQIconPool::pkgNoInst();
183
184     if ( enabled )
185     {
186         switch ( status )
187         {
188             case S_Del:                 icon = YQIconPool::pkgDel();            break;
189             case S_Install:             icon = YQIconPool::pkgInstall();        break;
190             case S_KeepInstalled:       icon = YQIconPool::pkgKeepInstalled();  break;
191             case S_NoInst:              icon = YQIconPool::pkgNoInst();         break;
192             case S_Protected:           icon = YQIconPool::pkgProtected();      break;
193             case S_Taboo:               icon = YQIconPool::pkgTaboo();          break;
194             case S_Update:              icon = YQIconPool::pkgUpdate();         break;
195
196             case S_AutoDel:             icon = bySelection ?
197                                             YQIconPool::pkgSelAutoDel() :
198                                             YQIconPool::pkgAutoDel();           break;
199
200             case S_AutoInstall:         icon = bySelection ?
201                                             YQIconPool::pkgSelAutoInstall() :
202                                             YQIconPool::pkgAutoInstall();       break;
203
204             case S_AutoUpdate:          icon = bySelection ?
205                                             YQIconPool::pkgSelAutoUpdate() :
206                                              YQIconPool::pkgAutoUpdate();       break;
207
208
209                 // Intentionally omitting 'default' branch so the compiler can
210                 // catch unhandled enum states
211         }
212     }
213     else
214     {
215         switch ( status )
216         {
217             case S_Del:                 icon = YQIconPool::disabledPkgDel();            break;
218             case S_Install:             icon = YQIconPool::disabledPkgInstall();        break;
219             case S_KeepInstalled:       icon = YQIconPool::disabledPkgKeepInstalled();  break;
220             case S_NoInst:              icon = YQIconPool::disabledPkgNoInst();         break;
221             case S_Protected:           icon = YQIconPool::disabledPkgProtected();      break;
222             case S_Taboo:               icon = YQIconPool::disabledPkgTaboo();          break;
223             case S_Update:              icon = YQIconPool::disabledPkgUpdate();         break;
224
225             case S_AutoDel:             icon = bySelection ?
226                                             YQIconPool::disabledPkgSelAutoDel() :
227                                             YQIconPool::disabledPkgAutoDel();           break;
228
229             case S_AutoInstall:         icon = bySelection ?
230                                             YQIconPool::disabledPkgSelAutoInstall() :
231                                             YQIconPool::disabledPkgAutoInstall();       break;
232
233             case S_AutoUpdate:          icon = bySelection ?
234                                             YQIconPool::disabledPkgSelAutoUpdate() :
235                                             YQIconPool::disabledPkgAutoUpdate();        break;
236
237                 // Intentionally omitting 'default' branch so the compiler can
238                 // catch unhandled enum states
239         }
240     }
241
242     return icon;
243 }
244
245
246 QString
247 YQPkgObjList::statusText( ZyppStatus status ) const
248 {
249     switch ( status )
250     {
251         case S_AutoDel:         return _( "Autodelete"                  );
252         case S_AutoInstall:     return _( "Autoinstall"                 );
253         case S_AutoUpdate:      return _( "Autoupdate"                  );
254         case S_Del:             return _( "Delete"                      );
255         case S_Install:         return _( "Install"                     );
256         case S_KeepInstalled:   return _( "Keep"                        );
257         case S_NoInst:          return _( "Do Not Install"              );
258         case S_Protected:       return _( "Protected -- Do Not Modify"  );
259         case S_Taboo:           return _( "Taboo -- Never Install"      );
260         case S_Update:          return _( "Update"                      );
261     }
262
263     return QString::null;
264 }
265
266
267 void
268 YQPkgObjList::setCurrentStatus( ZyppStatus newStatus, bool doSelectNextItem )
269 {
270 #if FIXME
271     QTreeWidgetItem * listViewItem = selectedItem();
272
273     if ( ! listViewItem )
274         return;
275
276     YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *> (listViewItem);
277
278     if ( item && item->editable() && _editable )
279     {
280         if ( newStatus != item->status() )
281         {
282             item->setStatus( newStatus );
283
284             if ( item->showLicenseAgreement() )
285             {
286                 item->showNotifyTexts( newStatus );
287             }
288             else // License not confirmed?
289             {
290                 // Status is now S_Taboo or S_Del - update status icon
291                 item->setStatusIcon();
292             }
293
294             emit statusChanged();
295         }
296     }
297
298     if ( doSelectNextItem )
299         selectNextItem();
300 #endif
301 }
302
303
304 void
305 YQPkgObjList::setAllItemStatus( ZyppStatus newStatus, bool force )
306 {
307     if ( ! _editable )
308         return;
309
310     YQUI::ui()->busyCursor();
311     QTreeWidgetItemIterator it( this );
312
313     while ( *it )
314     {
315         YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *> (*it);
316
317         if ( item && item->editable() && newStatus != item->status() )
318         {
319             if ( newStatus == S_Update )
320             {
321                 if ( item->candidateIsNewer() || force )
322                     item->setStatus( newStatus,
323                                      false );   // sendSignals
324             }
325             else
326             {
327                 item->setStatus( newStatus,
328                                  false );       // sendSignals
329             }
330         }
331
332         ++it;
333     }
334
335     emit updateItemStates();
336     emit updatePackages();
337
338     YQUI::ui()->normalCursor();
339     emit statusChanged();
340 }
341
342
343 void
344 YQPkgObjList::selectNextItem()
345 {
346 #if FIXME
347     QTreeWidgetItem * item = selectedItem();
348
349     if ( item && item->nextSibling() )
350     {
351         item->setSelected( false );                     // Doesn't emit signals
352         ensureItemVisible( item->nextSibling() );       // Scroll if necessary
353         setSelected( item->nextSibling(), true );       // Emits signals
354     }
355 #endif
356 }
357
358
359 void
360 YQPkgObjList::createActions()
361 {
362     actionSetCurrentInstall             = createAction( S_Install,              "[+]"           );
363     actionSetCurrentDontInstall         = createAction( S_NoInst,               "[-]"           );
364     actionSetCurrentKeepInstalled       = createAction( S_KeepInstalled,        "[<], [-]"      );
365     actionSetCurrentDelete              = createAction( S_Del,                  "[-]"           );
366     actionSetCurrentUpdate              = createAction( S_Update,               "[>], [+]"      );
367     actionSetCurrentTaboo               = createAction( S_Taboo,                "[!]"           );
368     actionSetCurrentProtected           = createAction( S_Protected,            "[*]"           );
369
370     actionSetListInstall                = createAction( S_Install,              "", true );
371     actionSetListDontInstall            = createAction( S_NoInst,               "", true );
372     actionSetListKeepInstalled          = createAction( S_KeepInstalled,        "", true );
373     actionSetListDelete                 = createAction( S_Del,                  "", true );
374     actionSetListProtected              = createAction( S_Protected,            "", true );
375
376     actionSetListUpdate                 = createAction( _( "Update if newer version available" ),
377                                                         statusIcon( S_Update, true ),
378                                                         statusIcon( S_Update, false ),
379                                                         "",
380                                                         true );
381
382     actionSetListUpdateForce            = createAction( _( "Update unconditionally" ),
383                                                         statusIcon( S_Update, true ),
384                                                         statusIcon( S_Update, false ),
385                                                         "",
386                                                         true );
387
388     actionSetListTaboo                  = createAction( S_Taboo,                "", true );
389
390     connect( actionSetCurrentInstall,        SIGNAL( activated() ), this, SLOT( setCurrentInstall()       ) );
391     connect( actionSetCurrentDontInstall,    SIGNAL( activated() ), this, SLOT( setCurrentDontInstall()   ) );
392     connect( actionSetCurrentKeepInstalled,  SIGNAL( activated() ), this, SLOT( setCurrentKeepInstalled() ) );
393     connect( actionSetCurrentDelete,         SIGNAL( activated() ), this, SLOT( setCurrentDelete()        ) );
394     connect( actionSetCurrentUpdate,         SIGNAL( activated() ), this, SLOT( setCurrentUpdate()        ) );
395     connect( actionSetCurrentTaboo,          SIGNAL( activated() ), this, SLOT( setCurrentTaboo()         ) );
396     connect( actionSetCurrentProtected,      SIGNAL( activated() ), this, SLOT( setCurrentProtected()     ) );
397
398     connect( actionSetListInstall,           SIGNAL( activated() ), this, SLOT( setListInstall()          ) );
399     connect( actionSetListDontInstall,       SIGNAL( activated() ), this, SLOT( setListDontInstall()      ) );
400     connect( actionSetListKeepInstalled,     SIGNAL( activated() ), this, SLOT( setListKeepInstalled()    ) );
401     connect( actionSetListDelete,            SIGNAL( activated() ), this, SLOT( setListDelete()           ) );
402     connect( actionSetListUpdate,            SIGNAL( activated() ), this, SLOT( setListUpdate()           ) );
403     connect( actionSetListUpdateForce,       SIGNAL( activated() ), this, SLOT( setListUpdateForce()      ) );
404     connect( actionSetListTaboo,             SIGNAL( activated() ), this, SLOT( setListTaboo()            ) );
405     connect( actionSetListProtected,         SIGNAL( activated() ), this, SLOT( setListProtected()        ) );
406 }
407
408
409
410 QAction *
411 YQPkgObjList::createAction( ZyppStatus status, const QString & key, bool enabled )
412 {
413     return createAction( statusText( status ),
414                          statusIcon( status, true ),
415                          statusIcon( status, false ),
416                          key,
417                          enabled );
418 }
419
420
421 QAction *
422 YQPkgObjList::createAction( const QString &     text,
423                             const QPixmap &     icon,
424                             const QPixmap &     insensitiveIcon,
425                             const QString &     key,
426                             bool                enabled )
427 {
428     QString label = text;
429
430     if ( ! key.isEmpty() )
431         label += "\t" + key;
432
433
434     QIcon iconSet ( icon );
435
436     if ( ! insensitiveIcon.isNull() )
437     {
438         iconSet.addPixmap( insensitiveIcon,
439                            QIcon::Disabled );
440     }
441
442     QAction * action = new QAction( label,      // text
443                                     this );     // parent
444     Q_CHECK_PTR( action );
445     action->setEnabled( enabled );
446     action->setIcon( iconSet );
447
448     return action;
449 }
450
451
452 void
453 YQPkgObjList::createNotInstalledContextMenu()
454 {
455     _notInstalledContextMenu = new QMenu( this );
456     Q_CHECK_PTR( _notInstalledContextMenu );
457
458     _notInstalledContextMenu->addAction(actionSetCurrentInstall);
459     _notInstalledContextMenu->addAction(actionSetCurrentDontInstall);
460     _notInstalledContextMenu->addAction(actionSetCurrentTaboo);
461
462     addAllInListSubMenu( _notInstalledContextMenu );
463 }
464
465
466 void
467 YQPkgObjList::createInstalledContextMenu()
468 {
469     _installedContextMenu = new QMenu( this );
470     Q_CHECK_PTR( _installedContextMenu );
471
472     _installedContextMenu->addAction(actionSetCurrentKeepInstalled);
473     _installedContextMenu->addAction(actionSetCurrentDelete);
474     _installedContextMenu->addAction(actionSetCurrentUpdate);
475
476     addAllInListSubMenu( _installedContextMenu );
477 }
478
479
480 QMenu *
481 YQPkgObjList::addAllInListSubMenu( QMenu * menu )
482 {
483     QMenu * submenu = new QMenu( menu );
484     Q_CHECK_PTR( submenu );
485
486     submenu->addAction(actionSetListInstall);
487     submenu->addAction(actionSetListDontInstall);
488     submenu->addAction(actionSetListKeepInstalled);
489     submenu->addAction(actionSetListDelete);
490     submenu->addAction(actionSetListUpdate);
491     submenu->addAction(actionSetListUpdateForce);
492     submenu->addAction(actionSetListTaboo);
493
494     QAction *action = menu->addMenu( submenu );
495     action->setText(_( "&All in This List" ));
496
497     return submenu;
498 }
499
500
501 QMenu *
502 YQPkgObjList::notInstalledContextMenu()
503 {
504     if ( ! _notInstalledContextMenu )
505         createNotInstalledContextMenu();
506
507     return _notInstalledContextMenu;
508 }
509
510
511 QMenu *
512 YQPkgObjList::installedContextMenu()
513 {
514     if ( ! _installedContextMenu )
515         createInstalledContextMenu();
516
517     return _installedContextMenu;
518 }
519
520
521 void
522 YQPkgObjList::updateActions( YQPkgObjListItem * item )
523 {
524 #if FIXME
525     if ( !item)
526       item = dynamic_cast<YQPkgObjListItem *> ( selectedItem() );
527
528     if ( item )
529     {
530         ZyppSel selectable = item->selectable();
531
532         if ( selectable->hasInstalledObj() )
533         {
534             actionSetCurrentInstall->setEnabled( false );
535             actionSetCurrentDontInstall->setEnabled( false );
536             actionSetCurrentTaboo->setEnabled( false );
537             actionSetCurrentProtected->setEnabled( true );
538
539             actionSetCurrentKeepInstalled->setEnabled( true );
540             actionSetCurrentDelete->setEnabled( true );
541             actionSetCurrentUpdate->setEnabled( selectable->hasCandidateObj() );
542         }
543         else
544         {
545             actionSetCurrentInstall->setEnabled( selectable->hasCandidateObj() );
546             actionSetCurrentDontInstall->setEnabled( true );
547             actionSetCurrentTaboo->setEnabled( true );
548             actionSetCurrentProtected->setEnabled( false );
549
550             actionSetCurrentKeepInstalled->setEnabled( false );
551             actionSetCurrentDelete->setEnabled( false );
552             actionSetCurrentUpdate->setEnabled( false );
553         }
554     }
555     else        // ! item
556     {
557         actionSetCurrentInstall->setEnabled( false );
558         actionSetCurrentDontInstall->setEnabled( false );
559         actionSetCurrentTaboo->setEnabled( false );
560
561         actionSetCurrentKeepInstalled->setEnabled( false );
562         actionSetCurrentDelete->setEnabled( false );
563         actionSetCurrentUpdate->setEnabled( false );
564         actionSetCurrentProtected->setEnabled( false );
565     }
566 #endif
567 }
568
569
570 void
571 YQPkgObjList::keyPressEvent( QKeyEvent * event )
572 {
573 #if FIXME
574     if ( event )
575     {
576         unsigned special_combo = ( Qt::ControlButton | Qt::ShiftButton | Qt::AltButton );
577
578         if ( ( event->state() & special_combo ) == special_combo )
579         {
580             if ( event->key() == Qt::Key_Q )
581             {
582                 _debug= ! _debug;
583                 y2milestone( "Debug mode %s", _debug ? "on" : "off" );
584             }
585
586         }
587         QTreeWidgetItem * selectedListViewItem = selectedItem();
588
589         if ( selectedListViewItem )
590         {
591             YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *> (selectedListViewItem);
592
593             if ( item )
594             {
595                 bool installed = item->selectable()->hasInstalledObj();
596                 ZyppStatus status = item->status();
597
598                 switch( event->ascii() )
599                 {
600                     case Qt::Key_Space:         // Cycle
601                         item->cycleStatus();
602                         event->accept();
603                         return;
604
605                     case '+':   // Grab everything - install or update
606
607                         if ( installed )
608                         {
609                             ZyppStatus newStatus = S_KeepInstalled;
610
611                             if ( item->candidateIsNewer() )
612                                 newStatus = S_Update;
613
614                             setCurrentStatus( newStatus );
615                         }
616                         else
617                             setCurrentStatus( S_Install );
618                         selectNextItem();
619                         event->accept();
620                         return;
621
622                     case '-':   // Get rid of everything - don't install or delete
623                         setCurrentStatus( installed ? S_Del : S_NoInst );
624                         selectNextItem();
625                         event->accept();
626                         return;
627
628                     case '!':   // Taboo
629
630                         if ( ! installed )
631                             setCurrentStatus( S_Taboo );
632                         selectNextItem();
633                         event->accept();
634                         return;
635
636                     case '*':   // Protected
637
638                         if ( installed )
639                             setCurrentStatus( S_Protected );
640                         selectNextItem();
641                         event->accept();
642                         return;
643
644                     case '>':   // Update what is worth to be updated
645
646                         if ( installed && item->candidateIsNewer() )
647                             setCurrentStatus( S_Update );
648                         selectNextItem();
649                         event->accept();
650                         return;
651
652                     case '<':   // Revert update
653
654                         if ( status == S_Update ||
655                              status == S_AutoUpdate )
656                         {
657                             setCurrentStatus( S_KeepInstalled );
658                         }
659                         selectNextItem();
660                         event->accept();
661                         return;
662
663                     case 'b':
664                     case 'B':   // Toggle debugIsBroken flag
665
666                         if ( _debug )
667                         {
668                             item->toggleDebugIsBroken();
669                             item->setStatusIcon();
670                         }
671                         event->accept();
672                         break;
673
674                     case 's':
675                     case 'S':   // Toggle debugIsSatisfied flag
676
677                         if ( _debug )
678                         {
679                             item->toggleDebugIsSatisfied();
680                             item->setStatusIcon();
681                         }
682                         event->accept();
683                         break;
684                 }
685             }
686         }
687     }
688 #endif
689     QY2ListView::keyPressEvent( event );
690 }
691
692
693 void
694 YQPkgObjList::message( const QString & text )
695 {
696     QY2ListViewItem * item = new QY2ListViewItem( this );
697     Q_CHECK_PTR( item );
698
699     item->setText( nameCol() >= 0 ? nameCol() : 0, text );
700     item->setBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
701 }
702
703
704 void
705 YQPkgObjList::addExcludeRule( YQPkgObjList::ExcludeRule * rule )
706 {
707     _excludeRules.push_back( rule );
708 }
709
710
711 void
712 YQPkgObjList::applyExcludeRules()
713 {
714     // y2debug( "Applying exclude rules" );
715     QTreeWidgetItemIterator listView_it( this );
716
717     while ( *listView_it )
718     {
719         QTreeWidgetItem * current_item = *listView_it;
720
721         // Advance iterator now so it remains valid even if there are changes
722         // to the QListView, e.g., if the current item is excluded and thus
723         // removed from the QListView
724         ++listView_it;
725
726         applyExcludeRules( current_item );
727     }
728
729     ExcludedItems::iterator excluded_it = _excludedItems->begin();
730
731     while ( excluded_it != _excludedItems->end() )
732     {
733         QTreeWidgetItem * current_item = (*excluded_it).first;
734
735         // Advance iterator now so it remains valid even if there are changes
736         // to the excluded items, e.g., if the current item is un-excluded and thus
737         // removed from the excluded items
738         ++excluded_it;
739
740         applyExcludeRules( current_item );
741     }
742
743     logExcludeStatistics();
744 }
745
746
747 void
748 YQPkgObjList::logExcludeStatistics()
749 {
750     if ( _excludedItems->size() > 0 )
751     {
752         y2milestone( "%d packages excluded", _excludedItems->size() );
753
754         for ( ExcludeRuleList::iterator rule_it = _excludeRules.begin();
755               rule_it != _excludeRules.end();
756               ++rule_it )
757         {
758             ExcludeRule * rule = *rule_it;
759
760             if ( rule->isEnabled() )
761             {
762                 y2milestone( "Active exclude rule: \"%s\"",
763                              qPrintable(rule->regexp().pattern()) );
764             }
765         }
766     }
767 }
768
769
770 void
771 YQPkgObjList::applyExcludeRules( QTreeWidgetItem * listViewItem )
772 {
773     YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *>( listViewItem );
774
775     if ( item )
776     {
777         bool exclude = false;
778         ExcludeRule * matchingRule = 0;
779
780         for ( ExcludeRuleList::iterator rule_it = _excludeRules.begin();
781               rule_it != _excludeRules.end() && ! exclude;
782               ++rule_it )
783         {
784             ExcludeRule * rule = *rule_it;
785
786             if ( rule->match( item ) )
787             {
788                 exclude = true;
789                 matchingRule = rule;
790             }
791         }
792
793         if ( exclude != item->isExcluded() )    // change exclude status?
794         {
795             this->exclude( item, exclude );
796
797 #if VERBOSE_EXCLUDE_RULES
798             if ( exclude )
799             {
800                 y2debug( "Rule %s matches: Excluding %s",
801                          matchingRule->regexp().pattern().ascii(),
802                          item->zyppObj()->name().c_str() );
803             }
804             else
805             {
806                 y2debug( "Un-excluding %s", item->zyppObj()->name().c_str() );
807             }
808 #endif
809         }
810     }
811 }
812
813
814 void
815 YQPkgObjList::exclude( YQPkgObjListItem * item, bool exclude )
816 {
817 #if FIXME
818     if ( exclude == item->isExcluded() )
819         return;
820
821     item->setExcluded( exclude );
822
823     if ( exclude )
824     {
825         QTreeWidgetItem * parentItem = item->parent();
826
827         if ( parentItem )
828             parentItem->takeItem( item );
829         else
830             QTreeWidget::takeItem( item );
831
832         _excludedItems->add( item, parentItem );
833     }
834     else // un-exclude
835     {
836         if ( _excludedItems->contains( item ) )
837         {
838             QTreeWidgetItem * oldParent = _excludedItems->oldParentItem( item );
839             _excludedItems->remove( item );
840
841             if ( oldParent )
842                 oldParent->insertItem( item );
843             else
844                 QTreeWidget::insertItem( item );
845         }
846     }
847 #endif
848 }
849
850
851
852
853 YQPkgObjListItem::YQPkgObjListItem( YQPkgObjList * pkgObjList,
854                                     ZyppSel selectable,
855                                     ZyppObj zyppObj )
856     : QY2ListViewItem( pkgObjList )
857     , _pkgObjList( pkgObjList )
858     , _selectable( selectable )
859     , _zyppObj( zyppObj )
860     , _editable( true )
861     , _excluded( false )
862 {
863     init();
864 }
865
866
867 YQPkgObjListItem::YQPkgObjListItem( YQPkgObjList *      pkgObjList,
868                                     QY2ListViewItem *   parent,
869                                     ZyppSel             selectable,
870                                     ZyppObj             zyppObj )
871     : QY2ListViewItem( parent )
872     , _pkgObjList( pkgObjList )
873     , _selectable( selectable )
874     , _zyppObj( zyppObj )
875     , _editable( true )
876     , _excluded( false )
877 {
878     init();
879 }
880
881
882 YQPkgObjListItem::~YQPkgObjListItem()
883 {
884     // NOP
885 }
886
887
888 void
889 YQPkgObjListItem::init()
890 {
891     if ( _zyppObj == 0 && _selectable )
892         _zyppObj = _selectable->theObj();
893
894     _debugIsBroken      = false;
895     _debugIsSatisfied   = false;
896     _candidateIsNewer   = false;
897     _installedIsNewer   = false;
898
899     const ZyppObj candidate = selectable()->candidateObj();
900     const ZyppObj installed = selectable()->installedObj();
901
902     if ( candidate && installed )
903     {
904         if ( candidate->edition() < installed->edition() )
905             _installedIsNewer = true;
906         else if ( installed->edition() < candidate->edition() )
907             _candidateIsNewer = true;
908     }
909
910     if ( nameCol()    >= 0 )    setText( nameCol(),     zyppObj()->name()       );
911     if ( summaryCol() >= 0 )    setText( summaryCol(),  zyppObj()->summary()    );
912
913     if ( sizeCol()    >= 0 )
914     {
915         zypp::ByteCount size = zyppObj()->size();
916
917         if ( size > 0L )
918             setText( sizeCol(), size.asString() + "  " );
919     }
920
921     if ( instVersionCol() >= 0 )
922     {
923         if ( selectable()->hasInstalledObj() )
924              setText( instVersionCol(), installed->edition() );
925
926         if ( zyppObj() != selectable()->installedObj() &&
927              zyppObj() != selectable()->candidateObj()   )
928         {
929             setText( versionCol(), zyppObj()->edition() );
930         }
931         else if ( selectable()->hasCandidateObj() )
932         {
933             setText( versionCol(), candidate->edition() );
934         }
935     }
936     else
937     {
938         setText( versionCol(),  zyppObj()->edition() );
939     }
940
941     setStatusIcon();
942 }
943
944
945 void
946 YQPkgObjListItem::updateData()
947 {
948     init();
949 }
950
951
952 void
953 YQPkgObjListItem::setText( int column, const string text )
954 {
955     QTreeWidgetItem::setText( column, fromUTF8( text.c_str() ) );
956 }
957
958
959 void
960 YQPkgObjListItem::setText( int column, const zypp::Edition & edition )
961 {
962     setText( column, edition.asString() );
963 }
964
965
966 ZyppStatus
967 YQPkgObjListItem::status() const
968 {
969     if ( ! selectable() )
970     {
971         y2error( "No selectable" );
972         return S_NoInst;
973     }
974
975     return selectable()->status();
976 }
977
978
979 bool
980 YQPkgObjListItem::bySelection() const
981 {
982     zypp::ResStatus::TransactByValue modifiedBy = selectable()->modifiedBy();
983
984     return ( modifiedBy == zypp::ResStatus::APPL_LOW ||
985              modifiedBy == zypp::ResStatus::APPL_HIGH  );
986 }
987
988
989 void
990 YQPkgObjListItem::setStatus( ZyppStatus newStatus, bool sendSignals )
991 {
992     ZyppStatus oldStatus = selectable()->status();
993     selectable()->set_status( newStatus );
994
995     if ( oldStatus != selectable()->status() )
996     {
997         applyChanges();
998
999         if ( sendSignals )
1000         {
1001             _pkgObjList->updateItemStates();
1002             _pkgObjList->sendUpdatePackages();
1003         }
1004     }
1005
1006     setStatusIcon();
1007 }
1008
1009
1010 void
1011 YQPkgObjListItem::solveResolvableCollections()
1012 {
1013 #if EXTRA_SOLVE_COLLECTIONS
1014     zypp::Resolver_Ptr resolver = zypp::getZYpp()->resolver();
1015
1016     resolver->transactReset( zypp::ResStatus::APPL_LOW );
1017
1018     resolver->transactResKind( zypp::ResTraits<zypp::Product  >::kind );
1019     resolver->transactResKind( zypp::ResTraits<zypp::Selection>::kind );
1020     resolver->transactResKind( zypp::ResTraits<zypp::Pattern  >::kind );
1021     resolver->transactResKind( zypp::ResTraits<zypp::Language >::kind );
1022     resolver->transactResKind( zypp::ResTraits<zypp::Patch    >::kind );
1023     resolver->transactResKind( zypp::ResTraits<zypp::Atom     >::kind );
1024 #endif
1025 }
1026
1027
1028
1029 void
1030 YQPkgObjListItem::updateStatus()
1031 {
1032     setStatusIcon();
1033 }
1034
1035
1036 void
1037 YQPkgObjListItem::setStatusIcon()
1038 {
1039 #if FIXME
1040     if ( statusCol() >= 0 )
1041     {
1042         bool enabled = editable() && _pkgObjList->editable();
1043         setPixmap( statusCol(), _pkgObjList->statusIcon( status(), enabled, bySelection() ) );
1044     }
1045
1046
1047     if ( brokenIconCol() >= 0 )
1048     {
1049         // Reset this icon now - it might be the same column as satisfiedIconCol()
1050         setPixmap( brokenIconCol(), QPixmap() );
1051     }
1052
1053     if ( satisfiedIconCol() >= 0 )
1054     {
1055         // Set special icon for zyppObjs that are not marked as installed,
1056         // but satisfied anyway (e.g. for patches or patterns where the user
1057         // selected all required packages manually)
1058
1059         setPixmap( satisfiedIconCol(), isSatisfied() ? YQIconPool::pkgSatisfied() : QPixmap() );
1060     }
1061
1062     if ( brokenIconCol() >= 0 )
1063     {
1064         // Set special icon for zyppObjs that are installed, but broken
1065         // (dependencies no longer satisfied, e.g. for patches or patterns)
1066
1067         if ( isBroken() )
1068         {
1069             setPixmap( brokenIconCol(), YQIconPool::warningSign() );
1070
1071             y2warning( "Broken object: %s - %s",
1072                        _selectable->theObj()->name().c_str(),
1073                        _selectable->theObj()->summary().c_str() );
1074         }
1075     }
1076 #endif
1077 }
1078
1079
1080 bool
1081 YQPkgObjListItem::isSatisfied() const
1082 {
1083     if ( _debugIsSatisfied )
1084         return true;
1085
1086     if ( _selectable->hasInstalledObj() )
1087         return false;
1088
1089     return _selectable->candidatePoolItem().status().isSatisfied();
1090 }
1091
1092
1093 bool YQPkgObjListItem::isBroken() const
1094 {
1095     if ( _debugIsBroken )
1096         return true;
1097
1098     if ( ! _selectable->hasInstalledObj() )
1099         return false;           // can't be broken if not installed
1100
1101     switch ( status() )
1102     {
1103         case S_KeepInstalled:
1104         case S_Protected:
1105
1106             return _selectable->installedPoolItem().status().isIncomplete();
1107
1108         case S_Update:          // will be fixed by updating
1109         case S_AutoUpdate:
1110         case S_Del:             // will no longer be relevant after deleting
1111         case S_AutoDel:
1112
1113             return false;
1114
1115         case S_NoInst:          // should not happen - no installed obj
1116         case S_Install:
1117         case S_AutoInstall:
1118         case S_Taboo:
1119
1120             y2error( "Expected uninstalled zyppObj" );
1121             return false;
1122     }
1123
1124     y2error( "Should never get here" );
1125     return false;
1126 }
1127
1128
1129 void
1130 YQPkgObjListItem::cycleStatus()
1131 {
1132     if ( ! _editable || ! _pkgObjList->editable() )
1133         return;
1134
1135     ZyppStatus oldStatus = status();
1136     ZyppStatus newStatus = oldStatus;
1137
1138     if ( selectable()->hasInstalledObj() )
1139     {
1140         switch ( oldStatus )
1141         {
1142             case S_Protected:
1143                 newStatus = selectable()->hasCandidateObj() ?
1144                     S_KeepInstalled: S_NoInst;
1145                 break;
1146
1147             case S_KeepInstalled:
1148                 newStatus = selectable()->hasCandidateObj() ?
1149                     S_Update : S_Del;
1150                 break;
1151
1152             case S_Update:
1153                 newStatus = S_Del;
1154                 break;
1155
1156             case S_Del:
1157                 newStatus = S_KeepInstalled;
1158                 break;
1159
1160             default:
1161                 newStatus = S_KeepInstalled;
1162                 break;
1163         }
1164     }
1165     else        // Pkg not installed
1166     {
1167         switch ( oldStatus )
1168         {
1169             case S_NoInst:
1170                 if ( selectable()->hasCandidateObj() )
1171                 {
1172                     newStatus = S_Install;
1173                 }
1174                 else
1175                 {
1176                     y2warning( "No candidate for %s", selectable()->theObj()->name().c_str() );
1177                     newStatus = S_NoInst;
1178                 }
1179                 break;
1180
1181             case S_AutoInstall:
1182                 newStatus =  S_Taboo;
1183                 break;
1184
1185             default:
1186                 newStatus = S_NoInst;
1187                 break;
1188         }
1189     }
1190
1191     if ( oldStatus != newStatus )
1192     {
1193         setStatus( newStatus );
1194
1195         if ( showLicenseAgreement() )
1196         {
1197             showNotifyTexts( newStatus );
1198         }
1199         else // License not confirmed?
1200         {
1201             // Status is now S_Taboo or S_Del - update status icon
1202             setStatusIcon();
1203         }
1204
1205         _pkgObjList->sendStatusChanged();
1206     }
1207 }
1208
1209
1210 void
1211 YQPkgObjListItem::showNotifyTexts( ZyppStatus status )
1212 {
1213     string text;
1214
1215     switch ( status )
1216     {
1217         case S_Install:
1218             if ( selectable()->hasCandidateObj() )
1219                 text = selectable()->candidateObj()->insnotify();
1220             break;
1221
1222         case S_NoInst:
1223         case S_Del:
1224         case S_Taboo:
1225             if ( selectable()->hasCandidateObj() )
1226                 text = selectable()->candidateObj()->delnotify();
1227             break;
1228
1229         default: break;
1230     }
1231
1232     if ( ! text.empty() )
1233     {
1234         y2debug( "Showing notify text" );
1235         YQPkgTextDialog::showText( _pkgObjList, selectable(), text );
1236     }
1237 }
1238
1239
1240 bool
1241 YQPkgObjListItem::showLicenseAgreement()
1242 {
1243     return showLicenseAgreement( selectable() );
1244 }
1245
1246
1247 bool
1248 YQPkgObjListItem::showLicenseAgreement( ZyppSel sel )
1249 {
1250     string licenseText;
1251
1252     switch ( sel->status() )
1253     {
1254         case S_Install:
1255         case S_AutoInstall:
1256         case S_Update:
1257         case S_AutoUpdate:
1258
1259             if ( sel->hasLicenceConfirmed() )
1260                 return true;
1261
1262             if ( sel->candidateObj() )
1263                 licenseText = sel->candidateObj()->licenseToConfirm();
1264             break;
1265
1266         default: return true;
1267     }
1268
1269     if ( licenseText.empty() )
1270         return true;
1271
1272     y2debug( "Showing license agreement for %s", sel->name().c_str() );
1273     bool confirmed = YQPkgTextDialog::confirmText( 0, sel, licenseText );
1274
1275     if ( confirmed )
1276     {
1277         y2milestone( "User confirmed license agreement for %s", sel->name().c_str() );
1278         sel->setLicenceConfirmed( true );
1279     }
1280     else
1281     {
1282         // The user rejected the license agreement -
1283         // make sure the package gets unselected.
1284
1285         switch ( sel->status() )
1286         {
1287             case S_Install:
1288             case S_AutoInstall:
1289
1290                 y2warning( "User rejected license agreement for %s - setting to TABOO",
1291                            sel->name().c_str() );
1292
1293                 sel->set_status( S_Taboo );
1294                 break;
1295
1296
1297             case S_Update:
1298             case S_AutoUpdate:
1299
1300                 y2warning( "User rejected license agreement for %s  - setting to PROTECTED",
1301                            sel->name().c_str() );
1302
1303                 sel->set_status( S_Protected );
1304                 // S_Keep wouldn't be good enough: The next solver run might
1305                 // set it to S_AutoUpdate again
1306                 break;
1307
1308             default: break;
1309         }
1310     }
1311
1312     return confirmed;
1313 }
1314
1315
1316 QString
1317 YQPkgObjListItem::toolTip( int col )
1318 {
1319     if ( col == statusCol() )
1320     {
1321         QString tip = _pkgObjList->statusText( status() );
1322
1323         switch ( status() )
1324         {
1325             case S_AutoDel:
1326             case S_AutoInstall:
1327             case S_AutoUpdate:
1328
1329                 if ( bySelection() )
1330                     // Translators: Additional hint what caused an auto-status
1331                     tip += "\n" + _( "(by a software selection)" );
1332                 else
1333                     tip += "\n" + _( "(by dependencies)" );
1334
1335                 break;
1336
1337             default:
1338                 break;
1339         }
1340
1341         return tip;
1342     }
1343
1344     if ( col == brokenIconCol() )
1345     {
1346         if ( isBroken() )
1347             // Translators: tool tip for patches / patterns that are installed,
1348             // but whose dependencies are broken (no longer satisfied)
1349             return _( "Dependencies broken" );
1350     }
1351
1352     // don't use "else if" here, it might be the same colum as another one!
1353
1354     if ( col == satisfiedIconCol() )
1355     {
1356         if ( isSatisfied() )
1357             // Translators: tool tip for patches / patterns that are not installed,
1358             // but whose dependencies are satisfied
1359             return _( "All dependencies satisfied" );
1360     }
1361
1362     return QString::null;
1363 }
1364
1365
1366 /**
1367  * Comparison function used for sorting the list.
1368  * Returns:
1369  * -1 if this <  other
1370  *  0 if this == other
1371  * +1 if this >  other
1372  **/
1373 int
1374 YQPkgObjListItem::compare( QTreeWidgetItem *    otherListViewItem,
1375                            int                  col,
1376                            bool                 ascending ) const
1377 {
1378     YQPkgObjListItem * other = dynamic_cast<YQPkgObjListItem *> (otherListViewItem);
1379
1380     if ( other )
1381     {
1382         if ( col == sizeCol() )
1383         {
1384             // Numeric sort by size
1385
1386             if ( this->zyppObj()->size() < other->zyppObj()->size() ) return -1;
1387             if ( this->zyppObj()->size() > other->zyppObj()->size() ) return 1;
1388             return 0;
1389         }
1390         else if ( col == statusCol() )
1391         {
1392             // Sorting by status depends on the numeric value of the
1393             // ZyppStatus enum, thus it is important to insert new
1394             // package states there where they make most sense. We want to show
1395             // dangerous or noteworthy states first - e.g., "taboo" which should
1396             // seldeom occur, but when it does, it is important.
1397
1398             if ( this->status() < other->status() ) return -1;
1399             if ( this->status() > other->status() ) return 1;
1400             return 0;
1401         }
1402         else if ( col == instVersionCol() ||
1403                   col == versionCol() )
1404         {
1405             // Sorting by version numbers doesn't make too much sense, so let's
1406             // sort by package relation:
1407             // - Installed newer than candidate (red)
1408             // - Candidate newer than installed (blue) - worthwhile updating
1409             // - Installed
1410             // - Not installed, but candidate available
1411             //
1412             // Within these categories, sort versions by ASCII - OK, it's
1413             // pretty random, but predictable.
1414
1415             int thisPoints  = this->versionPoints();
1416             int otherPoints = other->versionPoints();
1417
1418             if ( thisPoints > otherPoints ) return -1;
1419             if ( thisPoints < otherPoints ) return  1;
1420             return QY2ListViewItem::compare( otherListViewItem, col, ascending );
1421         }
1422     }
1423
1424     // Fallback: Use parent class method
1425     return QY2ListViewItem::compare( otherListViewItem, col, ascending );
1426 }
1427
1428
1429 int
1430 YQPkgObjListItem::versionPoints() const
1431 {
1432     int points = 0;
1433
1434     if ( installedIsNewer() )                   points += 1000;
1435     if ( candidateIsNewer() )                   points += 100;
1436     if ( selectable()->hasInstalledObj() )      points += 10;
1437     if ( selectable()->hasCandidateObj() )      points += 1;
1438
1439     return points;
1440 }
1441
1442
1443 void
1444 YQPkgObjListItem::setExcluded( bool excl )
1445 {
1446     _excluded = excl;
1447 }
1448
1449
1450
1451
1452 YQPkgObjList::ExcludeRule::ExcludeRule( YQPkgObjList *  parent,
1453                                         const QRegExp & regexp,
1454                                         int             column )
1455     : _parent( parent )
1456     , _regexp( regexp )
1457     , _column( column )
1458     , _enabled( true )
1459 {
1460     _parent->addExcludeRule( this );
1461 }
1462
1463
1464 void
1465 YQPkgObjList::ExcludeRule::enable( bool enable )
1466 {
1467     _enabled = enable;
1468
1469 #if VERBOSE_EXCLUDE_RULES
1470     y2debug( "%s exclude rule %s",
1471              enable ? "Enabling" : "Disabling",
1472              _regexp.pattern().ascii() );
1473 #endif
1474 }
1475
1476
1477 void
1478 YQPkgObjList::ExcludeRule::setRegexp( const QRegExp & regexp )
1479 {
1480     _regexp = regexp;
1481 }
1482
1483
1484 void
1485 YQPkgObjList::ExcludeRule::setColumn( int column )
1486 {
1487     _column = column;
1488 }
1489
1490
1491 bool
1492 YQPkgObjList::ExcludeRule::match( QTreeWidgetItem * item )
1493 {
1494     if ( ! _enabled )
1495         return false;
1496
1497     QString text = item->text( _column );
1498
1499     if ( text.isEmpty() )
1500         return false;
1501
1502     return _regexp.exactMatch( text );
1503 }
1504
1505
1506
1507
1508
1509
1510 YQPkgObjList::ExcludedItems::ExcludedItems( YQPkgObjList * parent )
1511     : _pkgObjList( parent )
1512 {
1513 }
1514
1515
1516 YQPkgObjList::ExcludedItems::~ExcludedItems()
1517 {
1518     clear();
1519 }
1520
1521
1522 void YQPkgObjList::ExcludedItems::add( QTreeWidgetItem * item, QTreeWidgetItem * oldParent )
1523 {
1524     _excludeMap.insert( ItemPair( item, oldParent ) );
1525 }
1526
1527
1528 void YQPkgObjList::ExcludedItems::remove( QTreeWidgetItem * item )
1529 {
1530     ItemMap::iterator it = _excludeMap.find( item );
1531
1532     if ( it != _excludeMap.end() )
1533     {
1534         _excludeMap.erase( it );
1535     }
1536 }
1537
1538
1539 void YQPkgObjList::ExcludedItems::clear()
1540 {
1541     for ( ItemMap::iterator it = _excludeMap.begin();
1542           it != _excludeMap.end();
1543           ++it )
1544     {
1545         delete it->first;
1546     }
1547
1548     _excludeMap.clear();
1549 }
1550
1551
1552 bool YQPkgObjList::ExcludedItems::contains( QTreeWidgetItem * item )
1553 {
1554     return ( _excludeMap.find( item ) != _excludeMap.end() );
1555 }
1556
1557
1558 QTreeWidgetItem * YQPkgObjList::ExcludedItems::oldParentItem( QTreeWidgetItem * item )
1559 {
1560     ItemMap::iterator it = _excludeMap.find( item );
1561
1562     if ( it == _excludeMap.end() )
1563         return 0;
1564
1565     return it->second;
1566 }
1567
1568
1569
1570 #include "YQPkgObjList.moc"