File indexing completed on 2024-04-14 04:45:14

0001 /*
0002     SPDX-FileCopyrightText: 2005-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "k3bmediaselectioncombobox.h"
0009 #include "k3bapplication.h"
0010 #include "k3bmediacache.h"
0011 #include "k3bmediumdelegate.h"
0012 
0013 #include "k3bglobalsettings.h"
0014 #include "k3bdevice.h"
0015 #include "k3bdevicemanager.h"
0016 #include "k3bdeviceglobals.h"
0017 #include "k3bdiskinfo.h"
0018 #include "k3bglobals.h"
0019 #include "k3btoc.h"
0020 #include "k3bcdtext.h"
0021 
0022 #include <KLocalizedString>
0023 
0024 #include <QDebug>
0025 #include <QMap>
0026 #include <QVector>
0027 #include <QList>
0028 #include <QFont>
0029 
0030 Q_DECLARE_METATYPE(K3b::Medium)
0031 
0032 class K3b::MediaSelectionComboBox::Private
0033 {
0034 public:
0035     Private()
0036         : ignoreDevice( 0 ) {
0037     }
0038 
0039     QMap<K3b::Device::Device*, int> deviceIndexMap;
0040     QVector<K3b::Device::Device*> devices;
0041 
0042     K3b::Device::Device* ignoreDevice;
0043 
0044     // medium strings for every entry
0045     QMap<QString, int> mediaStringMap;
0046 
0047     Device::MediaTypes wantedMediumType;
0048     Device::MediaStates wantedMediumState;
0049     Medium::MediumContents wantedMediumContent;
0050     K3b::Msf wantedMediumSize;
0051 
0052     QList<Medium> excludedMediums;
0053 
0054     QFont origFont;
0055 };
0056 
0057 
0058 K3b::MediaSelectionComboBox::MediaSelectionComboBox( QWidget* parent )
0059     : KComboBox( false, parent )
0060 {
0061     d = new Private();
0062     d->origFont = font();
0063 
0064     // set defaults
0065     d->wantedMediumType = K3b::Device::MEDIA_WRITABLE_CD;
0066     d->wantedMediumState = K3b::Device::STATE_EMPTY;
0067     d->wantedMediumContent = K3b::Medium::ContentAll;
0068 
0069     setItemDelegate( new MediumDelegate( this ) );
0070 
0071     connect( this, SIGNAL(activated(int)),
0072              this, SLOT(slotActivated(int)) );
0073     connect( k3bcore->deviceManager(), SIGNAL(changed(K3b::Device::DeviceManager*)),
0074              this, SLOT(slotDeviceManagerChanged(K3b::Device::DeviceManager*)) );
0075     connect( k3bappcore->mediaCache(), SIGNAL(mediumChanged(K3b::Device::Device*)),
0076              this, SLOT(slotMediumChanged(K3b::Device::Device*)) );
0077     connect( this, SIGNAL(selectionChanged(K3b::Device::Device*)),
0078              this, SLOT(slotUpdateToolTip(K3b::Device::Device*)) );
0079 
0080     updateMedia();
0081 }
0082 
0083 
0084 K3b::MediaSelectionComboBox::~MediaSelectionComboBox()
0085 {
0086     delete d;
0087 }
0088 
0089 
0090 void K3b::MediaSelectionComboBox::setIgnoreDevice( K3b::Device::Device* dev )
0091 {
0092     d->ignoreDevice = dev;
0093     updateMedia();
0094 }
0095 
0096 
0097 K3b::Device::Device* K3b::MediaSelectionComboBox::selectedDevice() const
0098 {
0099     if( d->devices.count() > currentIndex() &&
0100         currentIndex() >= 0 )
0101         return d->devices[currentIndex()];
0102     else
0103         return 0;
0104 }
0105 
0106 
0107 QList<K3b::Device::Device*> K3b::MediaSelectionComboBox::allDevices() const
0108 {
0109     QList<K3b::Device::Device*> l;
0110     for( int i = 0; i < d->devices.count(); ++i )
0111         l.append( d->devices[i] );
0112     return l;
0113 }
0114 
0115 
0116 void K3b::MediaSelectionComboBox::setSelectedDevice( K3b::Device::Device* dev )
0117 {
0118     if( dev && d->deviceIndexMap.contains( dev ) ) {
0119         setCurrentIndex( d->deviceIndexMap[dev] );
0120         emit selectionChanged( dev );
0121     }
0122 }
0123 
0124 
0125 void K3b::MediaSelectionComboBox::setWantedMediumType( K3b::Device::MediaTypes type )
0126 {
0127     if( type != 0 && type != d->wantedMediumType) {
0128         d->wantedMediumType = type;
0129         updateMedia();
0130     }
0131 }
0132 
0133 
0134 void K3b::MediaSelectionComboBox::setWantedMediumState( K3b::Device::MediaStates state )
0135 {
0136     if( state != 0 && state != d->wantedMediumState ) {
0137         d->wantedMediumState = state;
0138         updateMedia();
0139     }
0140 }
0141 
0142 
0143 void K3b::MediaSelectionComboBox::setWantedMediumContent( K3b::Medium::MediumContents content )
0144 {
0145     if( content != d->wantedMediumContent ) {
0146         d->wantedMediumContent = content;
0147         updateMedia();
0148     }
0149 }
0150 
0151 
0152 void K3b::MediaSelectionComboBox::setWantedMediumSize( const K3b::Msf& minSize )
0153 {
0154     if ( d->wantedMediumSize != minSize ) {
0155         d->wantedMediumSize = minSize;
0156         updateMedia();
0157     }
0158 }
0159 
0160 
0161 K3b::Device::MediaTypes K3b::MediaSelectionComboBox::wantedMediumType() const
0162 {
0163     return d->wantedMediumType;
0164 }
0165 
0166 
0167 K3b::Device::MediaStates K3b::MediaSelectionComboBox::wantedMediumState() const
0168 {
0169     return d->wantedMediumState;
0170 }
0171 
0172 
0173 K3b::Medium::MediumContents K3b::MediaSelectionComboBox::wantedMediumContent() const
0174 {
0175     return d->wantedMediumContent;
0176 }
0177 
0178 
0179 K3b::Msf K3b::MediaSelectionComboBox::wantedMediumSize() const
0180 {
0181     return d->wantedMediumSize;
0182 }
0183 
0184 void K3b::MediaSelectionComboBox::slotActivated( int i )
0185 {
0186     if( d->devices.count() > 0 )
0187         emit selectionChanged( d->devices[i] );
0188 }
0189 
0190 
0191 void K3b::MediaSelectionComboBox::slotMediumChanged( K3b::Device::Device* dev )
0192 {
0193     updateMedium( dev );
0194 }
0195 
0196 
0197 void K3b::MediaSelectionComboBox::clear()
0198 {
0199     d->deviceIndexMap.clear();
0200     d->mediaStringMap.clear();
0201     d->devices.clear();
0202     KComboBox::clear();
0203     setFont( d->origFont );
0204 }
0205 
0206 
0207 void K3b::MediaSelectionComboBox::showNoMediumMessage()
0208 {
0209     // make it italic
0210     QFont f( font() );
0211     f.setItalic( true );
0212     setFont( f );
0213     if ( d->excludedMediums.isEmpty() ) {
0214         addItem( noMediumMessage() );
0215     }
0216     else {
0217         addItems( noMediumMessages() );
0218     }
0219     setItemData( 0, f, Qt::FontRole );
0220 }
0221 
0222 
0223 void K3b::MediaSelectionComboBox::updateMedia()
0224 {
0225     // remember set of devices
0226     QVector<K3b::Device::Device*> oldDevices = d->devices;
0227 
0228     // remember last selected medium
0229     K3b::Device::Device* selected = selectedDevice();
0230 
0231     clear();
0232     d->excludedMediums.clear();
0233 
0234     //
0235     // We need to only check a selection of the available devices based on the
0236     // wanted media type.
0237     //
0238 
0239     // no ROM media -> we most likely want only CD/DVD writers
0240     bool rwOnly = !( wantedMediumType() & (K3b::Device::MEDIA_CD_ROM|K3b::Device::MEDIA_DVD_ROM) );
0241     bool dvdOnly = !( wantedMediumType() & (K3b::Device::MEDIA_CD_ROM|K3b::Device::MEDIA_WRITABLE_CD) );
0242 
0243     QList<K3b::Device::Device *> devices(k3bcore->deviceManager()->allDevices());
0244     if( dvdOnly ) {
0245         if( rwOnly )
0246             devices = k3bcore->deviceManager()->dvdWriter();
0247         else
0248             devices = k3bcore->deviceManager()->dvdReader();
0249     }
0250     else if( rwOnly )
0251         devices = k3bcore->deviceManager()->cdWriter();
0252     else
0253         devices = k3bcore->deviceManager()->cdReader();
0254 
0255     for( QList<K3b::Device::Device *>::const_iterator it = devices.constBegin();
0256          it != devices.constEnd(); ++it ) {
0257         if ( d->ignoreDevice == *it ) {
0258             continue;
0259         }
0260 
0261         K3b::Medium medium = k3bappcore->mediaCache()->medium( *it );
0262 
0263         if( showMedium( medium ) ) {
0264             addMedium( *it );
0265         }
0266         else if( !( medium.diskInfo().diskState() & (Device::STATE_NO_MEDIA|Device::STATE_UNKNOWN) ) ) {
0267             d->excludedMediums.append( medium );
0268         }
0269     }
0270 
0271     //
0272     // Now in case no usable medium was found show the user a little message
0273     //
0274     if( d->devices.isEmpty() ) {
0275         showNoMediumMessage();
0276         if( selected != 0 ) {
0277             // inform that we have no medium at all
0278             emit selectionChanged( 0 );
0279         }
0280     }
0281     else if( selected && d->deviceIndexMap.contains( selected ) ) {
0282         setCurrentIndex( d->deviceIndexMap[selected] );
0283     }
0284     else {
0285         emit selectionChanged( selectedDevice() );
0286     }
0287 
0288     // did the selection of devices change
0289     if( !( d->devices == oldDevices ) ) {
0290         emit newMedia();
0291         for( int i = 0; i < d->devices.count(); ++i ) {
0292             int j = 0;
0293             for( j = 0; j < oldDevices.count(); ++j ) {
0294                 if( oldDevices[j] == d->devices[i] )
0295                     break;
0296             }
0297             if( j == oldDevices.count() ) {
0298                 // prefer a newly inserted medium over the previously selected
0299                 setSelectedDevice( d->devices[i] );
0300                 emit newMedium( d->devices[i] );
0301             }
0302         }
0303     }
0304 }
0305 
0306 
0307 void K3b::MediaSelectionComboBox::updateMedium( K3b::Device::Device* )
0308 {
0309     // for now we simply rebuild the whole list
0310     updateMedia();
0311 }
0312 
0313 
0314 void K3b::MediaSelectionComboBox::addMedium( K3b::Device::Device* dev )
0315 {
0316     //
0317     // In case we only want an empty medium (this might happen in case the
0318     // the medium is rewritable) we do not care about the contents but tell
0319     // the user that the medium is rewritable.
0320     // Otherwise we show the contents type since this might also be used
0321     // for source selection.
0322     //
0323     QString s = mediumString( k3bappcore->mediaCache()->medium( dev ) );
0324 
0325     //
0326     // Now let's see if this string is already contained in the list
0327     // and if so add the device name to both
0328     //
0329     if( d->mediaStringMap.contains( s ) ) {
0330         //
0331         // insert the modified string
0332         //
0333         addItem( s + QString(" (%1 - %2)").arg(dev->vendor()).arg(dev->description()) );
0334         setItemData( count()-1, QVariant::fromValue(k3bappcore->mediaCache()->medium( dev )), MediumDelegate::MediumRole );
0335 
0336         //
0337         // change the already existing string if we did not already do so
0338         // (which happens if more than 2 entries have the same medium string)
0339         //
0340         int prevIndex = d->mediaStringMap[s];
0341         if( prevIndex >= 0 )
0342             setItemText( prevIndex,itemText(prevIndex) + QString(" (%1 - %2)").arg(d->devices[prevIndex]->vendor()).arg(d->devices[prevIndex]->description() ));
0343 
0344         //
0345         // mark the string as already changed
0346         //
0347         d->mediaStringMap[s] = -1;
0348     }
0349     else {
0350         //
0351         // insert the plain medium string
0352         //
0353         addItem( s );
0354         setItemData( count()-1, QVariant::fromValue(k3bappcore->mediaCache()->medium( dev )), MediumDelegate::MediumRole );
0355         d->mediaStringMap[s] = count()-1;
0356     }
0357 
0358     //
0359     // update the helper structures
0360     //
0361     d->deviceIndexMap[dev] = count()-1;
0362     d->devices.append( dev );
0363 
0364     setItemData( count()-1, mediumToolTip( k3bappcore->mediaCache()->medium( dev ) ), Qt::ToolTipRole );
0365 }
0366 
0367 
0368 void K3b::MediaSelectionComboBox::slotDeviceManagerChanged( K3b::Device::DeviceManager* )
0369 {
0370     updateMedia();
0371 }
0372 
0373 
0374 bool K3b::MediaSelectionComboBox::showMedium( const K3b::Medium& m ) const
0375 {
0376     //
0377     // also use if wantedMediumState empty and medium rewritable
0378     // because we can always format/erase/overwrite it
0379     //
0380     // DVD+RW and DVD-RW restr. ovwr. are never reported as appendable
0381     //
0382     return( m.diskInfo().mediaType() & d->wantedMediumType
0383 
0384             &&
0385 
0386             ( m.content() & d->wantedMediumContent )
0387 
0388             &&
0389 
0390             ( m.diskInfo().diskState() & d->wantedMediumState
0391               ||
0392               ( d->wantedMediumState & K3b::Device::STATE_EMPTY &&
0393                 m.diskInfo().rewritable() )
0394               ||
0395               ( d->wantedMediumState & K3b::Device::STATE_INCOMPLETE &&
0396                 !m.diskInfo().empty() &&
0397                 m.diskInfo().mediaType() & (K3b::Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_RW_OVWR) ) )
0398 
0399             &&
0400 
0401             ( d->wantedMediumSize == 0 ||                                        // no specific size requested
0402               d->wantedMediumSize <= m.diskInfo().capacity() ||                  // size fits
0403               ( !d->wantedMediumState.testFlag( K3b::Device::STATE_COMPLETE ) && // size does not fit but an empty/appendable medium in overburn mode is requested
0404                 IsOverburnAllowed( d->wantedMediumSize, m.diskInfo().capacity() ) ) )
0405         );
0406 }
0407 
0408 
0409 QString K3b::MediaSelectionComboBox::mediumString( const K3b::Medium& medium ) const
0410 {
0411     return medium.shortString();
0412 }
0413 
0414 
0415 QString K3b::MediaSelectionComboBox::mediumToolTip( const K3b::Medium& m ) const
0416 {
0417     return m.longString( Medium::WithContents|Medium::WithDevice );
0418 }
0419 
0420 
0421 QString K3b::MediaSelectionComboBox::noMediumMessage() const
0422 {
0423     if( d->wantedMediumContent && d->wantedMediumContent != Medium::ContentAll )
0424         return Medium::mediaRequestString( d->wantedMediumContent );
0425     else
0426         return Medium::mediaRequestString( d->wantedMediumType, d->wantedMediumState, d->wantedMediumSize );
0427 }
0428 
0429 QStringList K3b::MediaSelectionComboBox::noMediumMessages() const
0430 {
0431     if( d->wantedMediumContent && d->wantedMediumContent != Medium::ContentAll )
0432         return QStringList( Medium::mediaRequestString( d->wantedMediumContent ) );
0433     else
0434         return Medium::mediaRequestStrings( d->excludedMediums, d->wantedMediumType, d->wantedMediumState, d->wantedMediumSize );
0435 }
0436 
0437 
0438 void K3b::MediaSelectionComboBox::slotUpdateToolTip( K3b::Device::Device* dev )
0439 {
0440     // update the tooltip for the combobox (the tooltip for the dropdown box is created in addMedium)
0441     setToolTip( dev ? mediumToolTip( k3bappcore->mediaCache()->medium( dev ) ) : QString() );
0442 }
0443 
0444 #include "moc_k3bmediaselectioncombobox.cpp"