picking up branches/tmp/sh/qt4-port/, merging it with trunk
[duncan/yast2-qt4.git] / src / pkg / YQPkgList.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQPkgList.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   Textdomain "packages-qt"
18
19 /-*/
20
21 #define SOURCE_RPM_DISABLED 0
22
23 #define y2log_component "qt-pkg"
24 #include <ycp/y2log.h>
25 #include <qpixmap.h>
26 #include <q3action.h>
27 #include <q3popupmenu.h>
28 #include <qmessagebox.h>
29
30 #include "utf8.h"
31
32 #include "YQPkgList.h"
33 #include "YQUI.h"
34 #include "YQi18n.h"
35 #include "YQIconPool.h"
36
37
38 YQPkgList::YQPkgList( QWidget * parent )
39     : YQPkgObjList( parent )
40 {
41     _srpmStatusCol      = -42;
42
43     int numCol = 0;
44     addColumn( "" );                    _statusCol      = numCol++;
45     // _statusCol = numCol;
46     addColumn( _( "Package"     ) );    _nameCol        = numCol++;
47
48     addColumn( _( "Summary"     ) );    _summaryCol     = numCol++;
49     addColumn( _( "Size"        ) );    _sizeCol        = numCol++;
50
51     if ( haveInstalledPkgs() )
52     {
53         addColumn( _( "Avail. Ver." ) ); _versionCol     = numCol++;
54         addColumn( _( "Inst. Ver."  ) ); _instVersionCol = numCol++;
55     }
56     else
57     {
58         addColumn( _( "Version" ) );    _versionCol     = numCol++;
59         _instVersionCol = -1;
60     }
61
62 #if SOURCE_RPM_DISABLED
63 #warning Selecting source RPMs disabled!
64 #else
65     addColumn( _( "Source" ) );         _srpmStatusCol  = numCol++;
66 #endif
67
68     saveColumnWidths();
69     setSorting( nameCol() );
70     setColumnAlignment( sizeCol(), Qt::AlignRight );
71     setAllColumnsShowFocus( true );
72
73     createActions();
74     createSourceRpmContextMenu();
75 }
76
77
78 YQPkgList::~YQPkgList()
79 {
80     // NOP
81 }
82
83
84 void YQPkgList::addPkgItem( ZyppSel selectable,
85                             ZyppPkg zyppPkg )
86 {
87     addPkgItem( selectable, zyppPkg, false );
88 }
89
90
91 void YQPkgList::addPkgItemDimmed( ZyppSel selectable,
92                                   ZyppPkg zyppPkg )
93 {
94     addPkgItem( selectable, zyppPkg, true );
95 }
96
97
98 void
99 YQPkgList::addPkgItem( ZyppSel  selectable,
100                        ZyppPkg  zyppPkg,
101                        bool     dimmed )
102 {
103     if ( ! selectable )
104     {
105         y2error( "NULL zypp::ui::Selectable!" );
106         return;
107     }
108
109     YQPkgListItem * item = new YQPkgListItem( this, selectable, zyppPkg );
110     Q_CHECK_PTR( item );
111
112     item->setDimmed( dimmed );
113     applyExcludeRules( item );
114 }
115
116
117 bool
118 YQPkgList::haveInstalledPkgs()
119 {
120     for ( ZyppPoolIterator it = zyppPkgBegin();
121           it != zyppPkgEnd();
122           ++it )
123     {
124         if ( (*it)->installedObj() )
125             return true;
126     }
127
128     return false;
129 }
130
131
132 void
133 YQPkgList::pkgObjClicked( int                   button,
134                           Q3ListViewItem *      listViewItem,
135                           int                   col,
136                           const QPoint &        pos )
137 {
138     if ( col == srpmStatusCol() )
139     {
140         YQPkgListItem * item = dynamic_cast<YQPkgListItem *> (listViewItem);
141
142         if ( item )
143         {
144             if ( button == Qt::LeftButton )
145             {
146                 if ( editable() && item->editable() )
147                     item->toggleSourceRpmStatus();
148                 return;
149             }
150             else if ( button == Qt::RightButton )
151             {
152                 if ( editable() && item->editable() )
153                 {
154                     updateActions( item );
155
156                     if ( _sourceRpmContextMenu )
157                         _sourceRpmContextMenu->popup( pos );
158                 }
159
160                 return;
161             }
162         }
163     }
164
165     YQPkgObjList::pkgObjClicked( button, listViewItem, col, pos );
166 }
167
168
169 QSize
170 YQPkgList::sizeHint() const
171 {
172     return QSize( 600, 350 );
173 }
174
175
176 void
177 YQPkgList::createSourceRpmContextMenu()
178 {
179     _sourceRpmContextMenu = new Q3PopupMenu( this );
180
181     actionInstallSourceRpm->addTo( _sourceRpmContextMenu );
182     actionDontInstallSourceRpm->addTo( _sourceRpmContextMenu );
183
184     Q3PopupMenu * submenu = new Q3PopupMenu( _sourceRpmContextMenu );
185     Q_CHECK_PTR( submenu );
186     _sourceRpmContextMenu->insertItem( _( "&All in This List" ), submenu );
187
188     actionInstallListSourceRpms->addTo( submenu );
189     actionDontInstallListSourceRpms->addTo( submenu );
190 }
191
192
193 void
194 YQPkgList::setInstallCurrentSourceRpm( bool installSourceRpm,
195                                        bool selectNextItem )
196 {
197     Q3ListViewItem * listViewItem = selectedItem();
198
199     if ( ! listViewItem )
200         return;
201
202     YQPkgListItem * item = dynamic_cast<YQPkgListItem *> (listViewItem);
203
204     if ( item )
205     {
206         item->setInstallSourceRpm( installSourceRpm );
207
208         if ( selectNextItem && item->nextSibling() )
209         {
210             item->setSelected( false );                 // doesn't emit signals
211             setSelected( item->nextSibling(), true );   // emits signals
212         }
213     }
214 }
215
216
217 void
218 YQPkgList::setInstallListSourceRpms( bool installSourceRpm )
219 {
220     if ( ! _editable )
221         return;
222
223     Q3ListViewItem * listViewItem = firstChild();
224
225     while ( listViewItem )
226     {
227         YQPkgListItem * item = dynamic_cast<YQPkgListItem *> (listViewItem);
228
229         if ( item && item->editable() )
230         {
231             item->setInstallSourceRpm( installSourceRpm );
232         }
233
234         listViewItem = listViewItem->nextSibling();
235     }
236 }
237
238
239
240 void
241 YQPkgList::createNotInstalledContextMenu()
242 {
243     _notInstalledContextMenu = new Q3PopupMenu( this );
244     Q_CHECK_PTR( _notInstalledContextMenu );
245
246     actionSetCurrentInstall->addTo( _notInstalledContextMenu );
247     actionSetCurrentDontInstall->addTo( _notInstalledContextMenu );
248     actionSetCurrentTaboo->addTo( _notInstalledContextMenu );
249
250     addAllInListSubMenu( _notInstalledContextMenu );
251
252
253     _notInstalledContextMenu->insertSeparator();
254     _notInstalledContextMenu->insertItem( _( "Export This List to &Text File..." ),
255                                           this, SLOT( askExportList() ) );
256 }
257
258
259 void
260 YQPkgList::createInstalledContextMenu()
261 {
262     _installedContextMenu = new Q3PopupMenu( this );
263     Q_CHECK_PTR( _installedContextMenu );
264
265     actionSetCurrentKeepInstalled->addTo( _installedContextMenu );
266     actionSetCurrentDelete->addTo( _installedContextMenu );
267     actionSetCurrentUpdate->addTo( _installedContextMenu );
268     actionSetCurrentProtected->addTo( _installedContextMenu );
269
270     addAllInListSubMenu( _installedContextMenu );
271
272     _installedContextMenu->insertSeparator();
273     _installedContextMenu->insertItem( _( "Export This List to &Text File..." ),
274                                        this, SLOT( askExportList() ) );
275 }
276
277
278 Q3PopupMenu *
279 YQPkgList::addAllInListSubMenu( Q3PopupMenu * menu )
280 {
281     Q3PopupMenu * submenu = new Q3PopupMenu( menu );
282     Q_CHECK_PTR( submenu );
283
284     actionSetListInstall->addTo( submenu );
285     actionSetListDontInstall->addTo( submenu );
286     actionSetListKeepInstalled->addTo( submenu );
287     actionSetListDelete->addTo( submenu );
288     actionSetListUpdate->addTo( submenu );
289     actionSetListUpdateForce->addTo( submenu );
290     actionSetListTaboo->addTo( submenu );
291     actionSetListProtected->addTo( submenu );
292
293     menu->insertItem( _( "&All in This List" ), submenu );
294
295     return submenu;
296 }
297
298
299 void
300 YQPkgList::createActions()
301 {
302     actionInstallSourceRpm              = createAction( _( "&Install Source" ),
303                                                         statusIcon( S_Install, true ),
304                                                         statusIcon( S_Install, false ) );
305
306     actionDontInstallSourceRpm          = createAction( _( "Do &Not Install Source" ),
307                                                         statusIcon( S_NoInst, true ),
308                                                         statusIcon( S_NoInst, false ) );
309
310     actionInstallListSourceRpms         = createAction( _( "&Install All Available Sources" ),
311                                                         statusIcon( S_Install, true ),
312                                                         statusIcon( S_Install, false ),
313                                                         QString::null,          // key
314                                                         true );                 // enabled
315
316     actionDontInstallListSourceRpms     = createAction( _( "Do &Not Install Any Sources" ),
317                                                         statusIcon( S_NoInst, true ),
318                                                         statusIcon( S_NoInst, false ),
319                                                         QString::null,          // key
320                                                         true );                 // enabled
321
322     connect( actionInstallSourceRpm,            SIGNAL( activated() ), this, SLOT( setInstallCurrentSourceRpm()     ) );
323     connect( actionDontInstallSourceRpm,        SIGNAL( activated() ), this, SLOT( setDontInstallCurrentSourceRpm() ) );
324
325     connect( actionInstallListSourceRpms,       SIGNAL( activated() ), this, SLOT( setInstallListSourceRpms()       ) );
326     connect( actionDontInstallListSourceRpms,   SIGNAL( activated() ), this, SLOT( setDontInstallListSourceRpms()   ) );
327 }
328
329
330 void
331 YQPkgList::updateActions( YQPkgObjListItem * pkgObjListItem )
332 {
333     YQPkgObjList::updateActions( pkgObjListItem );
334
335     YQPkgListItem * item = dynamic_cast<YQPkgListItem *> (pkgObjListItem);
336
337     if ( item )
338     {
339         actionInstallSourceRpm->setEnabled( item->hasSourceRpm() );
340         actionDontInstallSourceRpm->setEnabled( item->hasSourceRpm() );
341     }
342     else
343     {
344         actionInstallSourceRpm->setEnabled( false );
345         actionDontInstallSourceRpm->setEnabled( false );
346     }
347 }
348
349
350 void
351 YQPkgList::askExportList() const
352 {
353     QString filename = YQUI::ui()->askForSaveFileName( "pkglist.txt",   // startsWith
354                                                            "*.txt",             // filter
355                                                            _( "Export Package List" ) );
356     if ( ! filename.isEmpty() )
357         exportList( filename, true );
358 }
359
360
361 void
362 YQPkgList::exportList( const QString filename, bool interactive ) const
363 {
364     // Open file
365
366     FILE * file = fopen( (const char *) filename, "w" );
367
368     if ( ! file )
369     {
370         y2error( "Can't open file %s", (const char *) filename );
371
372         if ( interactive )
373         {
374             // Post error popup.
375
376             QMessageBox::warning( 0,                                            // parent
377                                   _( "Error" ),                                 // caption
378                                   _( "Cannot open file %1" ).arg( filename ),
379                                   QMessageBox::Ok | QMessageBox::Default,       // button0
380                                   QMessageBox::NoButton,                        // button1
381                                   QMessageBox::NoButton );                      // button2
382         }
383         return;
384     }
385
386
387     //
388     // Write header
389     //
390
391     // Format the header line with QString::sprintf() because plain stdio
392     // fprintf() is not UTF-8 aware - it will count multi-byte characters
393     // wrong, so the formatting will be broken.
394
395     QString header;
396     header.sprintf( "# %-18s %-30s | %10s | %-16s | %-16s\n\n",
397                     (const char *) _( "Status"      ).utf8(),
398                     (const char *) _( "Package"     ).utf8(),
399                     (const char *) _( "Size"        ).utf8(),
400                     (const char *) _( "Avail. Ver." ).utf8(),
401                     (const char *) _( "Inst. Ver."  ).utf8()
402                     );
403     fputs( (const char *) header.utf8(), file );
404
405
406     //
407     // Write all items
408     //
409
410     const Q3ListViewItem * item = firstChild();
411
412     while ( item )
413     {
414         const YQPkgListItem * pkg = dynamic_cast<const YQPkgListItem *> (item);
415
416         if ( pkg )
417         {
418             QString candVersion = pkg->text( versionCol()     );
419             QString instVersion = pkg->text( instVersionCol() );
420
421             if ( candVersion.isEmpty() ) candVersion = "---";
422             if ( instVersion.isEmpty() ) instVersion = "---";
423
424             QString status = "[" + statusText( pkg->status() ) + "]";
425             fprintf( file, "%-20s %-30s | %10s | %-16s | %-16s\n",
426                      (const char *) status.utf8(),
427                      (const char *) pkg->text( nameCol()   ),
428                      (const char *) pkg->text( sizeCol()   ),
429                      (const char *) candVersion,
430                      (const char *) instVersion
431                      );
432         }
433
434         item = item->nextSibling();
435     }
436
437
438     // Clean up
439
440     if ( file )
441         fclose( file );
442 }
443
444
445 int
446 YQPkgList::globalSetPkgStatus( ZyppStatus newStatus, bool force, bool countOnly )
447 {
448     YQUI::ui()->busyCursor();
449     int changedCount = 0;
450
451     for ( ZyppPoolIterator it = zyppPkgBegin();
452           it != zyppPkgEnd();
453           ++it )
454     {
455         ZyppSel    selectable = *it;
456         ZyppStatus oldStatus  = selectable->status();
457
458         if ( newStatus != oldStatus )
459         {
460             bool doChange = false;
461
462             switch ( newStatus )
463             {
464                 case S_KeepInstalled:
465                 case S_Del:
466                 case S_AutoDel:
467                 case S_Protected:
468                     doChange = selectable->hasInstalledObj();
469                     break;
470
471                 case S_Update:
472                 case S_AutoUpdate:
473
474                     if ( force )
475                     {
476                         doChange = selectable->hasInstalledObj();
477                     }
478                     else // don't force - update only if useful (if candidate is newer)
479                     {
480                         const ZyppObj candidate = selectable->candidateObj();
481                         const ZyppObj installed = selectable->installedObj();
482
483                         if ( candidate && installed )
484                         {
485                             doChange = ( installed->edition() < candidate->edition() );
486                         }
487                     }
488                     break;
489
490                 case S_Install:
491                 case S_AutoInstall:
492                 case S_NoInst:
493                 case S_Taboo:
494                     doChange = ! selectable->hasInstalledObj();
495                     break;
496             }
497
498             if ( doChange )
499             {
500                 if ( ! countOnly )
501                     selectable->set_status( newStatus );
502
503                 changedCount++;
504                 // y2milestone( "Updating %s", selectable->name().c_str() );
505             }
506         }
507     }
508
509     if ( changedCount > 0 && ! countOnly )
510     {
511         emit updateItemStates();
512         emit updatePackages();
513         emit statusChanged();
514     }
515
516     YQUI::ui()->normalCursor();
517
518     return changedCount;
519 }
520
521
522
523
524
525
526 YQPkgListItem::YQPkgListItem( YQPkgList *               pkgList,
527                               ZyppSel   selectable,
528                               ZyppPkg   zyppPkg )
529     : YQPkgObjListItem( pkgList, selectable, zyppPkg )
530     , _pkgList( pkgList )
531     , _zyppPkg( zyppPkg )
532     , _dimmed( false )
533 {
534     if ( ! _zyppPkg )
535         _zyppPkg = tryCastToZyppPkg( selectable->theObj() );
536
537     setSourceRpmIcon();
538 }
539
540
541 YQPkgListItem::~YQPkgListItem()
542 {
543     // NOP
544 }
545
546
547 void
548 YQPkgListItem::updateData()
549 {
550     YQPkgObjListItem::updateData();
551     setSourceRpmIcon();
552 }
553
554
555 bool
556 YQPkgListItem::hasSourceRpm() const
557 {
558     if ( ! selectable() )
559         return false;
560
561 #ifdef FIXME
562     return selectable()->providesSources();
563 #else
564     return false;
565 #endif
566 }
567
568
569 bool
570 YQPkgListItem::installSourceRpm() const
571 {
572     if ( ! selectable() )
573         return false;
574
575 #ifdef FIXME
576     if ( ! selectable()->providesSources() )
577         return false;
578
579     return selectable()->source_install();
580 #else
581     return false;
582 #endif
583 }
584
585
586 void
587 YQPkgListItem::setSourceRpmIcon()
588 {
589     if ( srpmStatusCol() < 0 )
590         return;
591
592     QPixmap icon;
593
594     if ( hasSourceRpm() )
595     {
596
597         if ( editable() && _pkgObjList->editable() )
598         {
599             icon = installSourceRpm() ?
600                 YQIconPool::pkgInstall() :
601                 YQIconPool::pkgNoInst();
602         }
603         else
604         {
605             icon = installSourceRpm() ?
606                 YQIconPool::disabledPkgInstall() :
607                 YQIconPool::disabledPkgNoInst();
608         }
609     }
610
611     setPixmap( srpmStatusCol(), icon );
612 }
613
614
615 void
616 YQPkgListItem::setInstallSourceRpm( bool installSourceRpm )
617 {
618     if ( hasSourceRpm() )
619     {
620 #ifdef FIXME
621         if ( selectable() )
622             selectable()->set_source_install( installSourceRpm );
623 #endif
624     }
625
626     setSourceRpmIcon();
627 }
628
629
630 void
631 YQPkgListItem::toggleSourceRpmStatus()
632 {
633     setInstallSourceRpm( ! installSourceRpm() );
634 }
635
636
637 QString
638 YQPkgListItem::toolTip( int col )
639 {
640     QString text;
641     QString name = _zyppObj->name().c_str();
642
643     if ( col == statusCol() )
644     {
645         text = YQPkgObjListItem::toolTip( col );
646     }
647     else if ( col == srpmStatusCol() )
648     {
649         text = name + "\n\n";
650
651         if ( hasSourceRpm() )
652         {
653             text += installSourceRpm() ?
654                 _( "Install Sources" ) :
655                 _( "Do Not Install Sources" );
656         }
657         else
658         {
659             text += _( "No Sources Available" );
660         }
661     }
662     else
663     {
664         text = name + "\n\n";
665
666         QString installed;
667         QString candidate;
668
669         if ( selectable()->hasInstalledObj() )
670         {
671             installed  = selectable()->installedObj()->edition().asString().c_str();
672             installed += "-";
673             installed +=  selectable()->installedObj()->arch().asString().c_str();
674             installed  = _( "Installed Version: %1" ).arg( installed );
675         }
676
677         if (  selectable()->hasCandidateObj() )
678         {
679             candidate  = selectable()->candidateObj()->edition().asString().c_str();
680             candidate += "-";
681             candidate +=  selectable()->candidateObj()->arch().asString().c_str();
682         }
683
684         if ( selectable()->hasInstalledObj() )
685         {
686             text += installed + "\n";
687
688             if ( selectable()->hasCandidateObj() )
689             {
690                 // Translators: This is the relation between two versions of one package
691                 // if both versions are the same, e.g., both "1.2.3-42", "1.2.3-42"
692                 QString relation = _( "same" );
693
694                 if ( _candidateIsNewer )        relation = _( "newer" );
695                 if ( _installedIsNewer )        relation = _( "older" );
696
697                 // Translators: %1 is the version, %2 is one of "newer", "older", "same"
698                 text += _( "Available Version: %1 (%2)" ).arg( candidate ).arg( relation );
699             }
700             else
701             {
702                 text += _( "Not available for installation" );
703             }
704         }
705         else // not installed
706         {
707             text += candidate;
708         }
709     }
710
711     return text;
712 }
713
714
715
716 /**
717  * Comparison function used for sorting the list.
718  * Returns:
719  * -1 if this <  other
720  *  0 if this == other
721  * +1 if this >  other
722  **/
723 int
724 YQPkgListItem::compare( Q3ListViewItem *                otherListViewItem,
725                         int                     col,
726                         bool                    ascending ) const
727 {
728     if ( col == srpmStatusCol() )
729     {
730         YQPkgListItem * other = dynamic_cast<YQPkgListItem *> (otherListViewItem);
731
732         if ( other )
733         {
734             int thisPoints  = ( this->hasSourceRpm()  ? 1 : 0 ) + ( this->installSourceRpm()  ? 1 : 0 );
735             int otherPoints = ( other->hasSourceRpm() ? 1 : 0 ) + ( other->installSourceRpm() ? 1 : 0 );
736
737             // Intentionally inverting order: Pkgs with source RPMs are more interesting than without.
738             if ( thisPoints > otherPoints ) return -1;
739             if ( thisPoints < otherPoints ) return  1;
740             return 0;
741         }
742     }
743
744     // Fallback: Use parent class method
745     return YQPkgObjListItem::compare( otherListViewItem, col, ascending );
746 }
747
748
749 void
750 YQPkgListItem::paintCell( QPainter *            painter,
751                           const QColorGroup &   colorGroup,
752                           int                   column,
753                           int                   width,
754                           int                   alignment )
755 {
756     if ( isDimmed() && ! YQUI::ui()->usingVisionImpairedPalette() )
757     {
758         QColorGroup cg = colorGroup;
759         cg.setColor( QColorGroup::Text, QColor( 0xA0, 0xA0, 0xA0 ) );
760
761         Q3ListViewItem::paintCell( painter, cg, column, width, alignment );
762     }
763     else
764     {
765         if ( installedIsNewer() )
766         {
767             QColorGroup cg = colorGroup;
768
769             if ( ! YQUI::ui()->usingVisionImpairedPalette() )
770             {
771                 if ( column == instVersionCol() )
772                     cg.setColor( QColorGroup::Base, QColor( 0xFF, 0x30, 0x30 ) );       // Background
773                 else
774                     cg.setColor( QColorGroup::Text, QColor( 0xFF, 0, 0 ) );             // Foreground
775             }
776
777             Q3ListViewItem::paintCell( painter, cg, column, width, alignment );
778         }
779         else if ( candidateIsNewer() )
780         {
781             QColorGroup cg = colorGroup;
782
783             if ( ! YQUI::ui()->usingVisionImpairedPalette() )
784             {
785                 cg.setColor( QColorGroup::Text, QColor( 0, 0, 0xC0 ) );                 // Foreground
786
787                 if ( column == versionCol() )
788                     cg.setColor( QColorGroup::Base, QColor( 0xF0, 0xF0, 0xF0 ) );       // Background
789             }
790
791             Q3ListViewItem::paintCell( painter, cg, column, width, alignment );
792         }
793         else
794         {
795             Q3ListViewItem::paintCell( painter, colorGroup, column, width, alignment );
796         }
797     }
798 }
799
800
801
802 #include "YQPkgList.moc"