]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/pkg/YQPkgObjList.cc
#ifdefed out everything not compiling so it can be ported
[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.h>
24 #include <q3header.h>
25 #include <q3popupmenu.h>
26 #include <q3action.h>
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( selectionChanged        ( QTreeWidgetItem * ) ),
77              this,      SLOT  ( selectionChangedInternal( 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                 Q3PopupMenu * 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::selectionChangedInternal( QTreeWidgetItem * listViewItem )
162 {
163     YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *> (listViewItem);
164
165     emit selectionChanged( item ? item->selectable() : ZyppSel() );
166 }
167
168
169 void
170 YQPkgObjList::clear()
171 {
172     emit selectionChanged( 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 Q3Action *
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 Q3Action *
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.setPixmap( insensitiveIcon,
439                            QIcon::Automatic,
440                            QIcon::Disabled );
441     }
442
443     Q3Action * action = new Q3Action( label,    // text
444                                     iconSet,    // icon set
445                                     label,      // menu text
446                                     0,          // accel key
447                                     this );     // parent
448     Q_CHECK_PTR( action );
449     action->setEnabled( enabled );
450
451     return action;
452 }
453
454
455 void
456 YQPkgObjList::createNotInstalledContextMenu()
457 {
458     _notInstalledContextMenu = new Q3PopupMenu( this );
459     Q_CHECK_PTR( _notInstalledContextMenu );
460
461     actionSetCurrentInstall->addTo( _notInstalledContextMenu );
462     actionSetCurrentDontInstall->addTo( _notInstalledContextMenu );
463     actionSetCurrentTaboo->addTo( _notInstalledContextMenu );
464
465     addAllInListSubMenu( _notInstalledContextMenu );
466 }
467
468
469 void
470 YQPkgObjList::createInstalledContextMenu()
471 {
472     _installedContextMenu = new Q3PopupMenu( this );
473     Q_CHECK_PTR( _installedContextMenu );
474
475     actionSetCurrentKeepInstalled->addTo( _installedContextMenu );
476     actionSetCurrentDelete->addTo( _installedContextMenu );
477     actionSetCurrentUpdate->addTo( _installedContextMenu );
478
479     addAllInListSubMenu( _installedContextMenu );
480 }
481
482
483 Q3PopupMenu *
484 YQPkgObjList::addAllInListSubMenu( Q3PopupMenu * menu )
485 {
486     Q3PopupMenu * submenu = new Q3PopupMenu( menu );
487     Q_CHECK_PTR( submenu );
488
489     actionSetListInstall->addTo( submenu );
490     actionSetListDontInstall->addTo( submenu );
491     actionSetListKeepInstalled->addTo( submenu );
492     actionSetListDelete->addTo( submenu );
493     actionSetListUpdate->addTo( submenu );
494     actionSetListUpdateForce->addTo( submenu );
495     actionSetListTaboo->addTo( submenu );
496
497     menu->insertItem( _( "&All in This List" ), submenu );
498
499     return submenu;
500 }
501
502
503 Q3PopupMenu *
504 YQPkgObjList::notInstalledContextMenu()
505 {
506     if ( ! _notInstalledContextMenu )
507         createNotInstalledContextMenu();
508
509     return _notInstalledContextMenu;
510 }
511
512
513 Q3PopupMenu *
514 YQPkgObjList::installedContextMenu()
515 {
516     if ( ! _installedContextMenu )
517         createInstalledContextMenu();
518
519     return _installedContextMenu;
520 }
521
522
523 void
524 YQPkgObjList::updateActions( YQPkgObjListItem * item )
525 {
526 #if FIXME
527     if ( !item)
528       item = dynamic_cast<YQPkgObjListItem *> ( selectedItem() );
529
530     if ( item )
531     {
532         ZyppSel selectable = item->selectable();
533
534         if ( selectable->hasInstalledObj() )
535         {
536             actionSetCurrentInstall->setEnabled( false );
537             actionSetCurrentDontInstall->setEnabled( false );
538             actionSetCurrentTaboo->setEnabled( false );
539             actionSetCurrentProtected->setEnabled( true );
540
541             actionSetCurrentKeepInstalled->setEnabled( true );
542             actionSetCurrentDelete->setEnabled( true );
543             actionSetCurrentUpdate->setEnabled( selectable->hasCandidateObj() );
544         }
545         else
546         {
547             actionSetCurrentInstall->setEnabled( selectable->hasCandidateObj() );
548             actionSetCurrentDontInstall->setEnabled( true );
549             actionSetCurrentTaboo->setEnabled( true );
550             actionSetCurrentProtected->setEnabled( false );
551
552             actionSetCurrentKeepInstalled->setEnabled( false );
553             actionSetCurrentDelete->setEnabled( false );
554             actionSetCurrentUpdate->setEnabled( false );
555         }
556     }
557     else        // ! item
558     {
559         actionSetCurrentInstall->setEnabled( false );
560         actionSetCurrentDontInstall->setEnabled( false );
561         actionSetCurrentTaboo->setEnabled( false );
562
563         actionSetCurrentKeepInstalled->setEnabled( false );
564         actionSetCurrentDelete->setEnabled( false );
565         actionSetCurrentUpdate->setEnabled( false );
566         actionSetCurrentProtected->setEnabled( false );
567     }
568 #endif
569 }
570
571
572 void
573 YQPkgObjList::keyPressEvent( QKeyEvent * event )
574 {
575 #if FIXME
576     if ( event )
577     {
578         unsigned special_combo = ( Qt::ControlButton | Qt::ShiftButton | Qt::AltButton );
579
580         if ( ( event->state() & special_combo ) == special_combo )
581         {
582             if ( event->key() == Qt::Key_Q )
583             {
584                 _debug= ! _debug;
585                 y2milestone( "Debug mode %s", _debug ? "on" : "off" );
586             }
587
588         }
589         QTreeWidgetItem * selectedListViewItem = selectedItem();
590
591         if ( selectedListViewItem )
592         {
593             YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *> (selectedListViewItem);
594
595             if ( item )
596             {
597                 bool installed = item->selectable()->hasInstalledObj();
598                 ZyppStatus status = item->status();
599
600                 switch( event->ascii() )
601                 {
602                     case Qt::Key_Space:         // Cycle
603                         item->cycleStatus();
604                         event->accept();
605                         return;
606
607                     case '+':   // Grab everything - install or update
608
609                         if ( installed )
610                         {
611                             ZyppStatus newStatus = S_KeepInstalled;
612
613                             if ( item->candidateIsNewer() )
614                                 newStatus = S_Update;
615
616                             setCurrentStatus( newStatus );
617                         }
618                         else
619                             setCurrentStatus( S_Install );
620                         selectNextItem();
621                         event->accept();
622                         return;
623
624                     case '-':   // Get rid of everything - don't install or delete
625                         setCurrentStatus( installed ? S_Del : S_NoInst );
626                         selectNextItem();
627                         event->accept();
628                         return;
629
630                     case '!':   // Taboo
631
632                         if ( ! installed )
633                             setCurrentStatus( S_Taboo );
634                         selectNextItem();
635                         event->accept();
636                         return;
637
638                     case '*':   // Protected
639
640                         if ( installed )
641                             setCurrentStatus( S_Protected );
642                         selectNextItem();
643                         event->accept();
644                         return;
645
646                     case '>':   // Update what is worth to be updated
647
648                         if ( installed && item->candidateIsNewer() )
649                             setCurrentStatus( S_Update );
650                         selectNextItem();
651                         event->accept();
652                         return;
653
654                     case '<':   // Revert update
655
656                         if ( status == S_Update ||
657                              status == S_AutoUpdate )
658                         {
659                             setCurrentStatus( S_KeepInstalled );
660                         }
661                         selectNextItem();
662                         event->accept();
663                         return;
664
665                     case 'b':
666                     case 'B':   // Toggle debugIsBroken flag
667
668                         if ( _debug )
669                         {
670                             item->toggleDebugIsBroken();
671                             item->setStatusIcon();
672                         }
673                         event->accept();
674                         break;
675
676                     case 's':
677                     case 'S':   // Toggle debugIsSatisfied flag
678
679                         if ( _debug )
680                         {
681                             item->toggleDebugIsSatisfied();
682                             item->setStatusIcon();
683                         }
684                         event->accept();
685                         break;
686                 }
687             }
688         }
689     }
690 #endif
691     QY2ListView::keyPressEvent( event );
692 }
693
694
695 void
696 YQPkgObjList::message( const QString & text )
697 {
698     QY2ListViewItem * item = new QY2ListViewItem( this );
699     Q_CHECK_PTR( item );
700
701     item->setText( nameCol() >= 0 ? nameCol() : 0, text );
702     item->setBackgroundColor( QColor( 0xE0, 0xE0, 0xF8 ) );
703 }
704
705
706 void
707 YQPkgObjList::addExcludeRule( YQPkgObjList::ExcludeRule * rule )
708 {
709     _excludeRules.push_back( rule );
710 }
711
712
713 void
714 YQPkgObjList::applyExcludeRules()
715 {
716     // y2debug( "Applying exclude rules" );
717     QTreeWidgetItemIterator listView_it( this );
718
719     while ( *listView_it )
720     {
721         QTreeWidgetItem * current_item = *listView_it;
722
723         // Advance iterator now so it remains valid even if there are changes
724         // to the QListView, e.g., if the current item is excluded and thus
725         // removed from the QListView
726         ++listView_it;
727
728         applyExcludeRules( current_item );
729     }
730
731     ExcludedItems::iterator excluded_it = _excludedItems->begin();
732
733     while ( excluded_it != _excludedItems->end() )
734     {
735         QTreeWidgetItem * current_item = (*excluded_it).first;
736
737         // Advance iterator now so it remains valid even if there are changes
738         // to the excluded items, e.g., if the current item is un-excluded and thus
739         // removed from the excluded items
740         ++excluded_it;
741
742         applyExcludeRules( current_item );
743     }
744
745     logExcludeStatistics();
746 }
747
748
749 void
750 YQPkgObjList::logExcludeStatistics()
751 {
752     if ( _excludedItems->size() > 0 )
753     {
754         y2milestone( "%d packages excluded", _excludedItems->size() );
755
756         for ( ExcludeRuleList::iterator rule_it = _excludeRules.begin();
757               rule_it != _excludeRules.end();
758               ++rule_it )
759         {
760             ExcludeRule * rule = *rule_it;
761
762             if ( rule->isEnabled() )
763             {
764                 y2milestone( "Active exclude rule: \"%s\"",
765                              rule->regexp().pattern().ascii() );
766             }
767         }
768     }
769 }
770
771
772 void
773 YQPkgObjList::applyExcludeRules( QTreeWidgetItem * listViewItem )
774 {
775     YQPkgObjListItem * item = dynamic_cast<YQPkgObjListItem *>( listViewItem );
776
777     if ( item )
778     {
779         bool exclude = false;
780         ExcludeRule * matchingRule = 0;
781
782         for ( ExcludeRuleList::iterator rule_it = _excludeRules.begin();
783               rule_it != _excludeRules.end() && ! exclude;
784               ++rule_it )
785         {
786             ExcludeRule * rule = *rule_it;
787
788             if ( rule->match( item ) )
789             {
790                 exclude = true;
791                 matchingRule = rule;
792             }
793         }
794
795         if ( exclude != item->isExcluded() )    // change exclude status?
796         {
797             this->exclude( item, exclude );
798
799 #if VERBOSE_EXCLUDE_RULES
800             if ( exclude )
801             {
802                 y2debug( "Rule %s matches: Excluding %s",
803                          matchingRule->regexp().pattern().ascii(),
804                          item->zyppObj()->name().c_str() );
805             }
806             else
807             {
808                 y2debug( "Un-excluding %s", item->zyppObj()->name().c_str() );
809             }
810 #endif
811         }
812     }
813 }
814
815
816 void
817 YQPkgObjList::exclude( YQPkgObjListItem * item, bool exclude )
818 {
819 #if FIXME
820     if ( exclude == item->isExcluded() )
821         return;
822
823     item->setExcluded( exclude );
824
825     if ( exclude )
826     {
827         QTreeWidgetItem * parentItem = item->parent();
828
829         if ( parentItem )
830             parentItem->takeItem( item );
831         else
832             Q3ListView::takeItem( item );
833
834         _excludedItems->add( item, parentItem );
835     }
836     else // un-exclude
837     {
838         if ( _excludedItems->contains( item ) )
839         {
840             QTreeWidgetItem * oldParent = _excludedItems->oldParentItem( item );
841             _excludedItems->remove( item );
842
843             if ( oldParent )
844                 oldParent->insertItem( item );
845             else
846                 Q3ListView::insertItem( item );
847         }
848     }
849 #endif
850 }
851
852
853
854
855 YQPkgObjListItem::YQPkgObjListItem( YQPkgObjList * pkgObjList,
856                                     ZyppSel selectable,
857                                     ZyppObj zyppObj )
858     : QY2ListViewItem( pkgObjList )
859     , _pkgObjList( pkgObjList )
860     , _selectable( selectable )
861     , _zyppObj( zyppObj )
862     , _editable( true )
863     , _excluded( false )
864 {
865     init();
866 }
867
868
869 YQPkgObjListItem::YQPkgObjListItem( YQPkgObjList *      pkgObjList,
870                                     QY2ListViewItem *   parent,
871                                     ZyppSel             selectable,
872                                     ZyppObj             zyppObj )
873     : QY2ListViewItem( parent )
874     , _pkgObjList( pkgObjList )
875     , _selectable( selectable )
876     , _zyppObj( zyppObj )
877     , _editable( true )
878     , _excluded( false )
879 {
880     init();
881 }
882
883
884 YQPkgObjListItem::~YQPkgObjListItem()
885 {
886     // NOP
887 }
888
889
890 void
891 YQPkgObjListItem::init()
892 {
893     if ( _zyppObj == 0 && _selectable )
894         _zyppObj = _selectable->theObj();
895
896     _debugIsBroken      = false;
897     _debugIsSatisfied   = false;
898     _candidateIsNewer   = false;
899     _installedIsNewer   = false;
900
901     const ZyppObj candidate = selectable()->candidateObj();
902     const ZyppObj installed = selectable()->installedObj();
903
904     if ( candidate && installed )
905     {
906         if ( candidate->edition() < installed->edition() )
907             _installedIsNewer = true;
908         else if ( installed->edition() < candidate->edition() )
909             _candidateIsNewer = true;
910     }
911
912     if ( nameCol()    >= 0 )    setText( nameCol(),     zyppObj()->name()       );
913     if ( summaryCol() >= 0 )    setText( summaryCol(),  zyppObj()->summary()    );
914
915     if ( sizeCol()    >= 0 )
916     {
917         zypp::ByteCount size = zyppObj()->size();
918
919         if ( size > 0L )
920             setText( sizeCol(), size.asString() + "  " );
921     }
922
923     if ( instVersionCol() >= 0 )
924     {
925         if ( selectable()->hasInstalledObj() )
926              setText( instVersionCol(), installed->edition() );
927
928         if ( zyppObj() != selectable()->installedObj() &&
929              zyppObj() != selectable()->candidateObj()   )
930         {
931             setText( versionCol(), zyppObj()->edition() );
932         }
933         else if ( selectable()->hasCandidateObj() )
934         {
935             setText( versionCol(), candidate->edition() );
936         }
937     }
938     else
939     {
940         setText( versionCol(),  zyppObj()->edition() );
941     }
942
943     setStatusIcon();
944 }
945
946
947 void
948 YQPkgObjListItem::updateData()
949 {
950     init();
951 }
952
953
954 void
955 YQPkgObjListItem::setText( int column, const string text )
956 {
957     QTreeWidgetItem::setText( column, fromUTF8( text.c_str() ) );
958 }
959
960
961 void
962 YQPkgObjListItem::setText( int column, const zypp::Edition & edition )
963 {
964     setText( column, edition.asString() );
965 }
966
967
968 ZyppStatus
969 YQPkgObjListItem::status() const
970 {
971     if ( ! selectable() )
972     {
973         y2error( "No selectable" );
974         return S_NoInst;
975     }
976
977     return selectable()->status();
978 }
979
980
981 bool
982 YQPkgObjListItem::bySelection() const
983 {
984     zypp::ResStatus::TransactByValue modifiedBy = selectable()->modifiedBy();
985
986     return ( modifiedBy == zypp::ResStatus::APPL_LOW ||
987              modifiedBy == zypp::ResStatus::APPL_HIGH  );
988 }
989
990
991 void
992 YQPkgObjListItem::setStatus( ZyppStatus newStatus, bool sendSignals )
993 {
994     ZyppStatus oldStatus = selectable()->status();
995     selectable()->set_status( newStatus );
996
997     if ( oldStatus != selectable()->status() )
998     {
999         applyChanges();
1000
1001         if ( sendSignals )
1002         {
1003             _pkgObjList->updateItemStates();
1004             _pkgObjList->sendUpdatePackages();
1005         }
1006     }
1007
1008     setStatusIcon();
1009 }
1010
1011
1012 void
1013 YQPkgObjListItem::solveResolvableCollections()
1014 {
1015 #if EXTRA_SOLVE_COLLECTIONS
1016     zypp::Resolver_Ptr resolver = zypp::getZYpp()->resolver();
1017
1018     resolver->transactReset( zypp::ResStatus::APPL_LOW );
1019
1020     resolver->transactResKind( zypp::ResTraits<zypp::Product  >::kind );
1021     resolver->transactResKind( zypp::ResTraits<zypp::Selection>::kind );
1022     resolver->transactResKind( zypp::ResTraits<zypp::Pattern  >::kind );
1023     resolver->transactResKind( zypp::ResTraits<zypp::Language >::kind );
1024     resolver->transactResKind( zypp::ResTraits<zypp::Patch    >::kind );
1025     resolver->transactResKind( zypp::ResTraits<zypp::Atom     >::kind );
1026 #endif
1027 }
1028
1029
1030
1031 void
1032 YQPkgObjListItem::updateStatus()
1033 {
1034     setStatusIcon();
1035 }
1036
1037
1038 void
1039 YQPkgObjListItem::setStatusIcon()
1040 {
1041 #if FIXME
1042     if ( statusCol() >= 0 )
1043     {
1044         bool enabled = editable() && _pkgObjList->editable();
1045         setPixmap( statusCol(), _pkgObjList->statusIcon( status(), enabled, bySelection() ) );
1046     }
1047
1048
1049     if ( brokenIconCol() >= 0 )
1050     {
1051         // Reset this icon now - it might be the same column as satisfiedIconCol()
1052         setPixmap( brokenIconCol(), QPixmap() );
1053     }
1054
1055     if ( satisfiedIconCol() >= 0 )
1056     {
1057         // Set special icon for zyppObjs that are not marked as installed,
1058         // but satisfied anyway (e.g. for patches or patterns where the user
1059         // selected all required packages manually)
1060
1061         setPixmap( satisfiedIconCol(), isSatisfied() ? YQIconPool::pkgSatisfied() : QPixmap() );
1062     }
1063
1064     if ( brokenIconCol() >= 0 )
1065     {
1066         // Set special icon for zyppObjs that are installed, but broken
1067         // (dependencies no longer satisfied, e.g. for patches or patterns)
1068
1069         if ( isBroken() )
1070         {
1071             setPixmap( brokenIconCol(), YQIconPool::warningSign() );
1072
1073             y2warning( "Broken object: %s - %s",
1074                        _selectable->theObj()->name().c_str(),
1075                        _selectable->theObj()->summary().c_str() );
1076         }
1077     }
1078 #endif
1079 }
1080
1081
1082 bool
1083 YQPkgObjListItem::isSatisfied() const
1084 {
1085     if ( _debugIsSatisfied )
1086         return true;
1087
1088     if ( _selectable->hasInstalledObj() )
1089         return false;
1090
1091     return _selectable->candidatePoolItem().status().isSatisfied();
1092 }
1093
1094
1095 bool YQPkgObjListItem::isBroken() const
1096 {
1097     if ( _debugIsBroken )
1098         return true;
1099
1100     if ( ! _selectable->hasInstalledObj() )
1101         return false;           // can't be broken if not installed
1102
1103     switch ( status() )
1104     {
1105         case S_KeepInstalled:
1106         case S_Protected:
1107
1108             return _selectable->installedPoolItem().status().isIncomplete();
1109
1110         case S_Update:          // will be fixed by updating
1111         case S_AutoUpdate:
1112         case S_Del:             // will no longer be relevant after deleting
1113         case S_AutoDel:
1114
1115             return false;
1116
1117         case S_NoInst:          // should not happen - no installed obj
1118         case S_Install:
1119         case S_AutoInstall:
1120         case S_Taboo:
1121
1122             y2error( "Expected uninstalled zyppObj" );
1123             return false;
1124     }
1125
1126     y2error( "Should never get here" );
1127     return false;
1128 }
1129
1130
1131 void
1132 YQPkgObjListItem::cycleStatus()
1133 {
1134     if ( ! _editable || ! _pkgObjList->editable() )
1135         return;
1136
1137     ZyppStatus oldStatus = status();
1138     ZyppStatus newStatus = oldStatus;
1139
1140     if ( selectable()->hasInstalledObj() )
1141     {
1142         switch ( oldStatus )
1143         {
1144             case S_Protected:
1145                 newStatus = selectable()->hasCandidateObj() ?
1146                     S_KeepInstalled: S_NoInst;
1147                 break;
1148
1149             case S_KeepInstalled:
1150                 newStatus = selectable()->hasCandidateObj() ?
1151                     S_Update : S_Del;
1152                 break;
1153
1154             case S_Update:
1155                 newStatus = S_Del;
1156                 break;
1157
1158             case S_Del:
1159                 newStatus = S_KeepInstalled;
1160                 break;
1161
1162             default:
1163                 newStatus = S_KeepInstalled;
1164                 break;
1165         }
1166     }
1167     else        // Pkg not installed
1168     {
1169         switch ( oldStatus )
1170         {
1171             case S_NoInst:
1172                 if ( selectable()->hasCandidateObj() )
1173                 {
1174                     newStatus = S_Install;
1175                 }
1176                 else
1177                 {
1178                     y2warning( "No candidate for %s", selectable()->theObj()->name().c_str() );
1179                     newStatus = S_NoInst;
1180                 }
1181                 break;
1182
1183             case S_AutoInstall:
1184                 newStatus =  S_Taboo;
1185                 break;
1186
1187             default:
1188                 newStatus = S_NoInst;
1189                 break;
1190         }
1191     }
1192
1193     if ( oldStatus != newStatus )
1194     {
1195         setStatus( newStatus );
1196
1197         if ( showLicenseAgreement() )
1198         {
1199             showNotifyTexts( newStatus );
1200         }
1201         else // License not confirmed?
1202         {
1203             // Status is now S_Taboo or S_Del - update status icon
1204             setStatusIcon();
1205         }
1206
1207         _pkgObjList->sendStatusChanged();
1208     }
1209 }
1210
1211
1212 void
1213 YQPkgObjListItem::showNotifyTexts( ZyppStatus status )
1214 {
1215     string text;
1216
1217     switch ( status )
1218     {
1219         case S_Install:
1220             if ( selectable()->hasCandidateObj() )
1221                 text = selectable()->candidateObj()->insnotify();
1222             break;
1223
1224         case S_NoInst:
1225         case S_Del:
1226         case S_Taboo:
1227             if ( selectable()->hasCandidateObj() )
1228                 text = selectable()->candidateObj()->delnotify();
1229             break;
1230
1231         default: break;
1232     }
1233
1234     if ( ! text.empty() )
1235     {
1236         y2debug( "Showing notify text" );
1237         YQPkgTextDialog::showText( _pkgObjList, selectable(), text );
1238     }
1239 }
1240
1241
1242 bool
1243 YQPkgObjListItem::showLicenseAgreement()
1244 {
1245     return showLicenseAgreement( selectable() );
1246 }
1247
1248
1249 bool
1250 YQPkgObjListItem::showLicenseAgreement( ZyppSel sel )
1251 {
1252     string licenseText;
1253
1254     switch ( sel->status() )
1255     {
1256         case S_Install:
1257         case S_AutoInstall:
1258         case S_Update:
1259         case S_AutoUpdate:
1260
1261             if ( sel->hasLicenceConfirmed() )
1262                 return true;
1263
1264             if ( sel->candidateObj() )
1265                 licenseText = sel->candidateObj()->licenseToConfirm();
1266             break;
1267
1268         default: return true;
1269     }
1270
1271     if ( licenseText.empty() )
1272         return true;
1273
1274     y2debug( "Showing license agreement for %s", sel->name().c_str() );
1275     bool confirmed = YQPkgTextDialog::confirmText( 0, sel, licenseText );
1276
1277     if ( confirmed )
1278     {
1279         y2milestone( "User confirmed license agreement for %s", sel->name().c_str() );
1280         sel->setLicenceConfirmed( true );
1281     }
1282     else
1283     {
1284         // The user rejected the license agreement -
1285         // make sure the package gets unselected.
1286
1287         switch ( sel->status() )
1288         {
1289             case S_Install:
1290             case S_AutoInstall:
1291
1292                 y2warning( "User rejected license agreement for %s - setting to TABOO",
1293                            sel->name().c_str() );
1294
1295                 sel->set_status( S_Taboo );
1296                 break;
1297
1298
1299             case S_Update:
1300             case S_AutoUpdate:
1301
1302                 y2warning( "User rejected license agreement for %s  - setting to PROTECTED",
1303                            sel->name().c_str() );
1304
1305                 sel->set_status( S_Protected );
1306                 // S_Keep wouldn't be good enough: The next solver run might
1307                 // set it to S_AutoUpdate again
1308                 break;
1309
1310             default: break;
1311         }
1312     }
1313
1314     return confirmed;
1315 }
1316
1317
1318 QString
1319 YQPkgObjListItem::toolTip( int col )
1320 {
1321     if ( col == statusCol() )
1322     {
1323         QString tip = _pkgObjList->statusText( status() );
1324
1325         switch ( status() )
1326         {
1327             case S_AutoDel:
1328             case S_AutoInstall:
1329             case S_AutoUpdate:
1330
1331                 if ( bySelection() )
1332                     // Translators: Additional hint what caused an auto-status
1333                     tip += "\n" + _( "(by a software selection)" );
1334                 else
1335                     tip += "\n" + _( "(by dependencies)" );
1336
1337                 break;
1338
1339             default:
1340                 break;
1341         }
1342
1343         return tip;
1344     }
1345
1346     if ( col == brokenIconCol() )
1347     {
1348         if ( isBroken() )
1349             // Translators: tool tip for patches / patterns that are installed,
1350             // but whose dependencies are broken (no longer satisfied)
1351             return _( "Dependencies broken" );
1352     }
1353
1354     // don't use "else if" here, it might be the same colum as another one!
1355
1356     if ( col == satisfiedIconCol() )
1357     {
1358         if ( isSatisfied() )
1359             // Translators: tool tip for patches / patterns that are not installed,
1360             // but whose dependencies are satisfied
1361             return _( "All dependencies satisfied" );
1362     }
1363
1364     return QString::null;
1365 }
1366
1367
1368 /**
1369  * Comparison function used for sorting the list.
1370  * Returns:
1371  * -1 if this <  other
1372  *  0 if this == other
1373  * +1 if this >  other
1374  **/
1375 int
1376 YQPkgObjListItem::compare( QTreeWidgetItem *    otherListViewItem,
1377                            int                  col,
1378                            bool                 ascending ) const
1379 {
1380     YQPkgObjListItem * other = dynamic_cast<YQPkgObjListItem *> (otherListViewItem);
1381
1382     if ( other )
1383     {
1384         if ( col == sizeCol() )
1385         {
1386             // Numeric sort by size
1387
1388             if ( this->zyppObj()->size() < other->zyppObj()->size() ) return -1;
1389             if ( this->zyppObj()->size() > other->zyppObj()->size() ) return 1;
1390             return 0;
1391         }
1392         else if ( col == statusCol() )
1393         {
1394             // Sorting by status depends on the numeric value of the
1395             // ZyppStatus enum, thus it is important to insert new
1396             // package states there where they make most sense. We want to show
1397             // dangerous or noteworthy states first - e.g., "taboo" which should
1398             // seldeom occur, but when it does, it is important.
1399
1400             if ( this->status() < other->status() ) return -1;
1401             if ( this->status() > other->status() ) return 1;
1402             return 0;
1403         }
1404         else if ( col == instVersionCol() ||
1405                   col == versionCol() )
1406         {
1407             // Sorting by version numbers doesn't make too much sense, so let's
1408             // sort by package relation:
1409             // - Installed newer than candidate (red)
1410             // - Candidate newer than installed (blue) - worthwhile updating
1411             // - Installed
1412             // - Not installed, but candidate available
1413             //
1414             // Within these categories, sort versions by ASCII - OK, it's
1415             // pretty random, but predictable.
1416
1417             int thisPoints  = this->versionPoints();
1418             int otherPoints = other->versionPoints();
1419
1420             if ( thisPoints > otherPoints ) return -1;
1421             if ( thisPoints < otherPoints ) return  1;
1422             return QY2ListViewItem::compare( otherListViewItem, col, ascending );
1423         }
1424     }
1425
1426     // Fallback: Use parent class method
1427     return QY2ListViewItem::compare( otherListViewItem, col, ascending );
1428 }
1429
1430
1431 int
1432 YQPkgObjListItem::versionPoints() const
1433 {
1434     int points = 0;
1435
1436     if ( installedIsNewer() )                   points += 1000;
1437     if ( candidateIsNewer() )                   points += 100;
1438     if ( selectable()->hasInstalledObj() )      points += 10;
1439     if ( selectable()->hasCandidateObj() )      points += 1;
1440
1441     return points;
1442 }
1443
1444
1445 void
1446 YQPkgObjListItem::setExcluded( bool excl )
1447 {
1448     _excluded = excl;
1449 }
1450
1451
1452
1453
1454 YQPkgObjList::ExcludeRule::ExcludeRule( YQPkgObjList *  parent,
1455                                         const QRegExp & regexp,
1456                                         int             column )
1457     : _parent( parent )
1458     , _regexp( regexp )
1459     , _column( column )
1460     , _enabled( true )
1461 {
1462     _parent->addExcludeRule( this );
1463 }
1464
1465
1466 void
1467 YQPkgObjList::ExcludeRule::enable( bool enable )
1468 {
1469     _enabled = enable;
1470
1471 #if VERBOSE_EXCLUDE_RULES
1472     y2debug( "%s exclude rule %s",
1473              enable ? "Enabling" : "Disabling",
1474              _regexp.pattern().ascii() );
1475 #endif
1476 }
1477
1478
1479 void
1480 YQPkgObjList::ExcludeRule::setRegexp( const QRegExp & regexp )
1481 {
1482     _regexp = regexp;
1483 }
1484
1485
1486 void
1487 YQPkgObjList::ExcludeRule::setColumn( int column )
1488 {
1489     _column = column;
1490 }
1491
1492
1493 bool
1494 YQPkgObjList::ExcludeRule::match( QTreeWidgetItem * item )
1495 {
1496     if ( ! _enabled )
1497         return false;
1498
1499     QString text = item->text( _column );
1500
1501     if ( text.isEmpty() )
1502         return false;
1503
1504     return _regexp.exactMatch( text );
1505 }
1506
1507
1508
1509
1510
1511
1512 YQPkgObjList::ExcludedItems::ExcludedItems( YQPkgObjList * parent )
1513     : _pkgObjList( parent )
1514 {
1515 }
1516
1517
1518 YQPkgObjList::ExcludedItems::~ExcludedItems()
1519 {
1520     clear();
1521 }
1522
1523
1524 void YQPkgObjList::ExcludedItems::add( QTreeWidgetItem * item, QTreeWidgetItem * oldParent )
1525 {
1526     _excludeMap.insert( ItemPair( item, oldParent ) );
1527 }
1528
1529
1530 void YQPkgObjList::ExcludedItems::remove( QTreeWidgetItem * item )
1531 {
1532     ItemMap::iterator it = _excludeMap.find( item );
1533
1534     if ( it != _excludeMap.end() )
1535     {
1536         _excludeMap.erase( it );
1537     }
1538 }
1539
1540
1541 void YQPkgObjList::ExcludedItems::clear()
1542 {
1543     for ( ItemMap::iterator it = _excludeMap.begin();
1544           it != _excludeMap.end();
1545           ++it )
1546     {
1547         delete it->first;
1548     }
1549
1550     _excludeMap.clear();
1551 }
1552
1553
1554 bool YQPkgObjList::ExcludedItems::contains( QTreeWidgetItem * item )
1555 {
1556     return ( _excludeMap.find( item ) != _excludeMap.end() );
1557 }
1558
1559
1560 QTreeWidgetItem * YQPkgObjList::ExcludedItems::oldParentItem( QTreeWidgetItem * item )
1561 {
1562     ItemMap::iterator it = _excludeMap.find( item );
1563
1564     if ( it == _excludeMap.end() )
1565         return 0;
1566
1567     return it->second;
1568 }
1569
1570
1571
1572 #include "YQPkgObjList.moc"