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