File indexing completed on 2024-06-16 07:42:26

0001 /*
0002     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include <config-k3b.h>
0007 
0008 #include "k3bmedium.h"
0009 #include "k3bmedium_p.h"
0010 #include "k3bcddb.h"
0011 #include "k3bdeviceglobals.h"
0012 #include "k3bglobals.h"
0013 #include "k3biso9660.h"
0014 #include "k3biso9660backend.h"
0015 #include "k3b_i18n.h"
0016 
0017 #include <KIO/Global>
0018 
0019 #include <QList>
0020 #include <QSharedData>
0021 
0022 #include <KCDDB/CDInfo>
0023 
0024 
0025 
0026 K3b::MediumPrivate::MediumPrivate()
0027     : device( 0 ),
0028       content( K3b::Medium::ContentNone )
0029 {
0030 }
0031 
0032 
0033 K3b::Medium::Medium()
0034 {
0035     d = new K3b::MediumPrivate;
0036 }
0037 
0038 
0039 
0040 K3b::Medium::Medium( const K3b::Medium& other )
0041 {
0042     d = other.d;
0043 }
0044 
0045 
0046 K3b::Medium::Medium( K3b::Device::Device* dev )
0047 {
0048     d = new K3b::MediumPrivate;
0049     d->device = dev;
0050 }
0051 
0052 
0053 K3b::Medium::~Medium()
0054 {
0055 }
0056 
0057 
0058 K3b::Medium& K3b::Medium::operator=( const K3b::Medium& other )
0059 {
0060     d = other.d;
0061     return *this;
0062 }
0063 
0064 
0065 bool K3b::Medium::isValid() const
0066 {
0067     return d->device != 0;
0068 }
0069 
0070 
0071 void K3b::Medium::setDevice( K3b::Device::Device* dev )
0072 {
0073     if( d->device != dev ) {
0074         reset();
0075         d->device = dev;
0076     }
0077 }
0078 
0079 K3b::Device::Device* K3b::Medium::device() const
0080 {
0081     return d->device;
0082 }
0083 
0084 
0085 K3b::Device::DiskInfo K3b::Medium::diskInfo() const
0086 {
0087     return d->diskInfo;
0088 }
0089 
0090 
0091 K3b::Device::Toc K3b::Medium::toc() const
0092 {
0093     return d->toc;
0094 }
0095 
0096 
0097 K3b::Device::CdText K3b::Medium::cdText() const
0098 {
0099     return d->cdText;
0100 }
0101 
0102 
0103 KCDDB::CDInfo K3b::Medium::cddbInfo() const
0104 {
0105     return d->cddbInfo;
0106 }
0107 
0108 
0109 QList<int> K3b::Medium::writingSpeeds() const
0110 {
0111     return d->writingSpeeds;
0112 }
0113 
0114 
0115 K3b::Medium::MediumContents K3b::Medium::content() const
0116 {
0117     return d->content;
0118 }
0119 
0120 
0121 const K3b::Iso9660SimplePrimaryDescriptor& K3b::Medium::iso9660Descriptor() const
0122 {
0123     return d->isoDesc;
0124 }
0125 
0126 
0127 K3b::Msf K3b::Medium::actuallyUsedCapacity() const
0128 {
0129     // DVD+RW, BD-RE, and DVD-RW in restricted overwrite mode have a single track that does not
0130     // change in size. Thus, the remainingSize value from the disk info is of no great value.
0131     if ( !d->diskInfo.empty() &&
0132          d->diskInfo.mediaType() & ( Device::MEDIA_DVD_PLUS_RW|Device::MEDIA_DVD_RW_OVWR|Device::MEDIA_BD_RE ) ) {
0133         return d->isoDesc.volumeSpaceSize;
0134     }
0135     else {
0136         return d->diskInfo.size();
0137     }
0138 }
0139 
0140 
0141 K3b::Msf K3b::Medium::actuallyRemainingSize() const
0142 {
0143     // DVD+RW, BD-RE, and DVD-RW in restricted overwrite mode have a single track that does not
0144     // change in size. Thus, the remainingSize value from the disk info is of no great value.
0145     if ( !d->diskInfo.empty() &&
0146          d->diskInfo.mediaType() & ( Device::MEDIA_DVD_PLUS_RW|Device::MEDIA_DVD_RW_OVWR|Device::MEDIA_BD_RE ) ) {
0147         return d->diskInfo.capacity() - d->isoDesc.volumeSpaceSize;
0148     }
0149     else {
0150         return d->diskInfo.remainingSize();
0151     }
0152 }
0153 
0154 
0155 void K3b::Medium::reset()
0156 {
0157     d->diskInfo = K3b::Device::DiskInfo();
0158     d->toc.clear();
0159     d->cdText.clear();
0160     d->writingSpeeds.clear();
0161     d->content = ContentNone;
0162     d->cddbInfo.clear();
0163 
0164     // clear the desc
0165     d->isoDesc = K3b::Iso9660SimplePrimaryDescriptor();
0166 }
0167 
0168 
0169 void K3b::Medium::update()
0170 {
0171     if( d->device ) {
0172         reset();
0173 
0174         d->diskInfo = d->device->diskInfo();
0175 
0176         if( d->diskInfo.diskState() != K3b::Device::STATE_NO_MEDIA ) {
0177             qDebug() << "found medium: (" << d->device->blockDeviceName() << ')' << Qt::endl
0178                      << "=====================================================";
0179             d->diskInfo.debug();
0180             qDebug() << "=====================================================";
0181         }
0182         else {
0183             qDebug() << "no medium found";
0184         }
0185 
0186         if( diskInfo().diskState() == K3b::Device::STATE_COMPLETE ||
0187             diskInfo().diskState() == K3b::Device::STATE_INCOMPLETE ) {
0188             d->toc = d->device->readToc();
0189             if( d->toc.contentType() == K3b::Device::AUDIO ||
0190                 d->toc.contentType() == K3b::Device::MIXED ) {
0191 
0192                 // update CD-Text
0193                 d->cdText = d->device->readCdText();
0194             }
0195         }
0196 
0197         if( diskInfo().mediaType() & K3b::Device::MEDIA_WRITABLE ) {
0198             d->writingSpeeds = d->device->determineSupportedWriteSpeeds();
0199         }
0200 
0201         analyseContent();
0202     }
0203 }
0204 
0205 
0206 void K3b::Medium::analyseContent()
0207 {
0208     // set basic content types
0209     switch( d->toc.contentType() ) {
0210     case K3b::Device::AUDIO:
0211         d->content = ContentAudio;
0212         break;
0213     case K3b::Device::DATA:
0214         d->content = ContentData;
0215         break;
0216     case K3b::Device::MIXED:
0217         d->content = ContentAudio|ContentData;
0218         break;
0219     default:
0220         d->content = ContentNone;
0221     }
0222 
0223     // analyze filesystem
0224     if( d->content & ContentData ) {
0225         //qDebug() << "(K3b::Medium) Checking file system.";
0226 
0227         unsigned long startSec = 0;
0228 
0229         if( diskInfo().numSessions() > 1 && !d->toc.isEmpty() ) {
0230             // We use the last data track
0231             // this way we get the latest session on a ms cd
0232             for( int i = d->toc.size()-1; i >= 0; --i ) {
0233                 if( d->toc.at(i).type() == K3b::Device::Track::TYPE_DATA ) {
0234                     startSec = d->toc.at(i).firstSector().lba();
0235                     break;
0236                 }
0237             }
0238         }
0239         else if( !d->toc.isEmpty() ) {
0240             // use first data track
0241             for( int i = 0; i < d->toc.size(); ++i ) {
0242                 if( d->toc.at(i).type() == K3b::Device::Track::TYPE_DATA ) {
0243                     startSec = d->toc.at(i).firstSector().lba();
0244                     break;
0245                 }
0246             }
0247         }
0248         else {
0249             qDebug() << "(K3b::Medium) ContentData is set and Toc is empty, disk is probably broken!";
0250         }
0251 
0252         //qDebug() << "(K3b::Medium) Checking file system at " << startSec;
0253 
0254         // force the backend since we don't need decryption
0255         // which just slows down the whole process
0256         K3b::Iso9660 iso( new K3b::Iso9660DeviceBackend( d->device ) );
0257         iso.setStartSector( startSec );
0258         iso.setPlainIso9660( true );
0259         if( iso.open() ) {
0260             d->isoDesc = iso.primaryDescriptor();
0261             qDebug() << "(K3b::Medium) found volume id from start sector " << startSec
0262                      << ": '" << d->isoDesc.volumeId << "'" ;
0263 
0264             if( const Iso9660Directory* firstDirEntry = iso.firstIsoDirEntry() ) {
0265                 if( Device::isDvdMedia( diskInfo().mediaType() ) ) {
0266                     // Every VideoDVD needs to have a VIDEO_TS.IFO file
0267                     if( firstDirEntry->entry( "VIDEO_TS/VIDEO_TS.IFO" ) != 0 )
0268                         d->content |= ContentVideoDVD;
0269                 }
0270                 else {
0271                     qDebug() << "(K3b::Medium) checking for VCD.";
0272 
0273                     // check for VCD
0274                     const K3b::Iso9660Entry* vcdEntry = firstDirEntry->entry( "VCD/INFO.VCD" );
0275                     const K3b::Iso9660Entry* svcdEntry = firstDirEntry->entry( "SVCD/INFO.SVD" );
0276                     const K3b::Iso9660File* vcdInfoFile = 0;
0277                     if( vcdEntry ) {
0278                         qDebug() << "(K3b::Medium) found vcd entry.";
0279                         if( vcdEntry->isFile() )
0280                             vcdInfoFile = static_cast<const K3b::Iso9660File*>(vcdEntry);
0281                     }
0282                     if( svcdEntry && !vcdInfoFile ) {
0283                         qDebug() << "(K3b::Medium) found svcd entry.";
0284                         if( svcdEntry->isFile() )
0285                             vcdInfoFile = static_cast<const K3b::Iso9660File*>(svcdEntry);
0286                     }
0287 
0288                     if( vcdInfoFile ) {
0289                         char buffer[8];
0290 
0291                         if ( vcdInfoFile->read( 0, buffer, 8 ) == 8 &&
0292                             ( !qstrncmp( buffer, "VIDEO_CD", 8 ) ||
0293                             !qstrncmp( buffer, "SUPERVCD", 8 ) ||
0294                             !qstrncmp( buffer, "HQ-VCD  ", 8 ) ) )
0295                             d->content |= ContentVideoCD;
0296                     }
0297                 }
0298             }
0299             else {
0300                 qDebug() << "(K3b::Medium) root ISO directory is null, disk is probably broken!";
0301             }
0302         }  // opened iso9660
0303     }
0304 }
0305 
0306 
0307 QString K3b::Medium::contentTypeString() const
0308 {
0309     QString mediaTypeString = K3b::Device::mediaTypeString( diskInfo().mediaType(), true );
0310 
0311     switch( d->toc.contentType() ) {
0312     case K3b::Device::AUDIO:
0313         return i18n("Audio CD");
0314 
0315     case K3b::Device::MIXED:
0316         return i18n("Mixed CD");
0317 
0318     case K3b::Device::DATA:
0319         if( content() & ContentVideoDVD ) {
0320             return i18n("Video DVD");
0321         }
0322         else if( content() & ContentVideoCD ) {
0323             return i18n("Video CD");
0324         }
0325         else if( diskInfo().diskState() == K3b::Device::STATE_INCOMPLETE ) {
0326             return i18n("Appendable Data %1", mediaTypeString );
0327         }
0328         else {
0329             return i18n("Complete Data %1", mediaTypeString );
0330         }
0331 
0332     case K3b::Device::NONE:
0333         return i18n("Empty");
0334     }
0335 
0336     // make gcc shut up
0337     return QString();
0338 }
0339 
0340 
0341 QString K3b::Medium::shortString( MediumStringFlags flags ) const
0342 {
0343     QString mediaTypeString = K3b::Device::mediaTypeString( diskInfo().mediaType(), true );
0344 
0345     if( diskInfo().diskState() == K3b::Device::STATE_UNKNOWN ) {
0346         return i18n("No medium information");
0347     }
0348 
0349     else if( diskInfo().diskState() == K3b::Device::STATE_NO_MEDIA ) {
0350         return i18n("No medium present");
0351     }
0352 
0353     else if( diskInfo().diskState() == K3b::Device::STATE_EMPTY ) {
0354         return i18n("Empty %1 medium", mediaTypeString );
0355     }
0356 
0357     else {
0358         if( flags & WithContents ) {
0359             // AUDIO + MIXED
0360             if( d->toc.contentType() == K3b::Device::AUDIO ||
0361                 d->toc.contentType() == K3b::Device::MIXED ) {
0362                 QString title = cdText().title();
0363                 QString performer = cdText().performer();
0364                 if ( title.isEmpty() ) {
0365                     title = cddbInfo().get( KCDDB::Title ).toString();
0366                 }
0367                 if ( performer.isEmpty() ) {
0368                     performer = cddbInfo().get( KCDDB::Artist ).toString();
0369                 }
0370                 if( !performer.isEmpty() && !title.isEmpty() ) {
0371                     return QString("%1 - %2")
0372                         .arg( performer )
0373                         .arg( title );
0374                 }
0375                 else if( d->toc.contentType() == K3b::Device::AUDIO ) {
0376                     return contentTypeString();
0377                 }
0378                 else {
0379                     return beautifiedVolumeId();
0380                 }
0381             }
0382 
0383             // DATA CD and DVD
0384             else if( !volumeId().isEmpty() ) {
0385                 return beautifiedVolumeId();
0386             }
0387             else {
0388                 return contentTypeString();
0389             }
0390         }
0391 
0392         // without content
0393         else {
0394             if( diskInfo().diskState() == K3b::Device::STATE_INCOMPLETE ) {
0395                 return i18n("Appendable %1 medium", mediaTypeString );
0396             }
0397             else {
0398                 return i18n("Complete %1 medium", mediaTypeString );
0399             }
0400         }
0401     }
0402 }
0403 
0404 
0405 QString K3b::Medium::longString( MediumStringFlags flags ) const
0406 {
0407     QString s = QString("<p><nobr><b style=\"font-size:large;\">%1</b></nobr><br/>(%2)")
0408                 .arg( shortString( flags ) )
0409                 .arg( flags & WithContents
0410                       ? contentTypeString()
0411                       : K3b::Device::mediaTypeString( diskInfo().mediaType(), true ) );
0412 
0413     if( diskInfo().diskState() == K3b::Device::STATE_COMPLETE ||
0414         diskInfo().diskState() == K3b::Device::STATE_INCOMPLETE  ) {
0415         s += "<br/>" + i18np("%2 in %1 track", "%2 in %1 tracks",
0416                              d->toc.count(),
0417                              KIO::convertSize(diskInfo().size().mode1Bytes()) );
0418         if( diskInfo().numSessions() > 1 )
0419             s += i18np(" and %1 session", " and %1 sessions", diskInfo().numSessions() );
0420     }
0421 
0422     if( diskInfo().diskState() == K3b::Device::STATE_EMPTY ||
0423         diskInfo().diskState() == K3b::Device::STATE_INCOMPLETE  )
0424         s += "<br/>" + i18n("Free space: %1",
0425                             KIO::convertSize( diskInfo().remainingSize().mode1Bytes() ) );
0426 
0427     if( !diskInfo().empty() && diskInfo().rewritable() )
0428         s += "<br/>" + i18n("Capacity: %1",
0429                             KIO::convertSize( diskInfo().capacity().mode1Bytes() ) );
0430 
0431     if( flags & WithDevice )
0432         s += QString("<br/><small><nobr>%1 %2 (%3)</nobr></small>")
0433              .arg( d->device->vendor() )
0434              .arg( d->device->description() )
0435              .arg( d->device->blockDeviceName() );
0436 
0437     return s;
0438 }
0439 
0440 
0441 QString K3b::Medium::volumeId() const
0442 {
0443     return iso9660Descriptor().volumeId;
0444 }
0445 
0446 
0447 QString K3b::Medium::beautifiedVolumeId() const
0448 {
0449     const QString oldId = volumeId();
0450     QString newId;
0451 
0452     bool newWord = true;
0453     for( int i = 0; i < oldId.length(); ++i ) {
0454         QChar c = oldId[i];
0455         //
0456         // first let's handle the cases where we do not change
0457         // the id anyway
0458         //
0459         // In case the id already contains spaces or lower case chars
0460         // it is likely that it already looks good and does ignore
0461         // the restricted iso9660 charset (like almost every project
0462         // created with K3b)
0463         //
0464         if( c.isLetter() && c.toLower() == c )
0465             return oldId;
0466         else if( c.isSpace() )
0467             return oldId;
0468 
0469         // replace underscore with space
0470         else if( c.unicode() == 95 ) {
0471             newId.append( ' ' );
0472             newWord = true;
0473         }
0474 
0475         // from here on only upper case chars and numbers and stuff
0476         else if( c.isLetter() ) {
0477             if( newWord ) {
0478                 newId.append( c );
0479                 newWord = false;
0480             }
0481             else {
0482                 newId.append( c.toLower() );
0483             }
0484         }
0485         else {
0486             newId.append( c );
0487         }
0488     }
0489 
0490     return newId;
0491 }
0492 
0493 
0494 QIcon K3b::Medium::icon() const
0495 {
0496     if( diskInfo().diskState() == Device::STATE_NO_MEDIA ) {
0497         return QIcon::fromTheme( "media-optical" );
0498     }
0499     else if( diskInfo().diskState() == Device::STATE_EMPTY ) {
0500         return QIcon::fromTheme( "media-optical-recordable" );
0501     }
0502     else if( content() == (ContentAudio | ContentData) ) {
0503         return QIcon::fromTheme( "media-optical-mixed-cd" );
0504     }
0505     else if( content() == ContentAudio ) {
0506         return QIcon::fromTheme( "media-optical-audio" );
0507     }
0508     else if( content() == ContentData ) {
0509         return QIcon::fromTheme( "media-optical-data" );
0510     }
0511     else if( content() & ContentVideoDVD ) {
0512         return QIcon::fromTheme( "media-optical-dvd-video" );
0513     }
0514     else if( content() & ContentVideoCD ) {
0515         return QIcon::fromTheme( "media-optical-cd-video" );
0516     }
0517     else {
0518         return QIcon::fromTheme( "media-optical" );
0519     }
0520 }
0521 
0522 
0523 bool K3b::Medium::operator==( const K3b::Medium& other ) const
0524 {
0525     if( this->d == other.d )
0526         return true;
0527 
0528     return( this->device() == other.device() &&
0529             this->diskInfo() == other.diskInfo() &&
0530             this->toc() == other.toc() &&
0531             this->cdText() == other.cdText() &&
0532             d->cddbInfo == other.d->cddbInfo &&
0533             this->content() == other.content() &&
0534             this->iso9660Descriptor() == other.iso9660Descriptor() );
0535 }
0536 
0537 
0538 bool K3b::Medium::operator!=( const K3b::Medium& other ) const
0539 {
0540     if( this->d == other.d )
0541         return false;
0542 
0543     return( this->device() != other.device() ||
0544             this->diskInfo() != other.diskInfo() ||
0545             this->toc() != other.toc() ||
0546             this->cdText() != other.cdText() ||
0547             d->cddbInfo != other.d->cddbInfo ||
0548             this->content() != other.content() ||
0549             this->iso9660Descriptor() != other.iso9660Descriptor() );
0550 }
0551 
0552 
0553 bool K3b::Medium::sameMedium( const K3b::Medium& other ) const
0554 {
0555     if( this->d == other.d )
0556         return true;
0557 
0558     // here we do ignore cddb info
0559     return( this->device() == other.device() &&
0560             this->diskInfo() == other.diskInfo() &&
0561             this->toc() == other.toc() &&
0562             this->cdText() == other.cdText() &&
0563             this->content() == other.content() &&
0564             this->iso9660Descriptor() == other.iso9660Descriptor() );
0565 }
0566 
0567 
0568 // static
0569 QStringList K3b::Medium::mediaRequestStrings(QList< K3b::Medium > unsuitableMediums, K3b::Device::MediaTypes requestedMediaTypes, K3b::Device::MediaStates requestedMediaStates, const K3b::Msf& requestedSize, K3b::Device::Device* dev)
0570 {
0571     QStringList toReturn;
0572 
0573     bool okMediaType;
0574     bool okMediaState;
0575     bool okSize;
0576     QString deviceString;
0577 
0578     Q_FOREACH(K3b::Medium medium, unsuitableMediums) {
0579         K3b::Device::Device *device = medium.device();
0580 
0581         if ( dev && ( device->blockDeviceName() != dev->blockDeviceName() ) )
0582             continue;
0583 
0584         K3b::Device::DiskInfo diskInfo = medium.diskInfo();
0585 
0586         okMediaType = ( diskInfo.mediaType() & requestedMediaTypes );
0587         okMediaState = ( diskInfo.diskState() & requestedMediaStates );
0588         okSize = ( diskInfo.capacity() >= requestedSize );
0589 
0590         deviceString = device->vendor() + ' ' + device->description() + QLatin1String(" (") + device->blockDeviceName() + ')';
0591 
0592         if (!okMediaType) {
0593             QString desiredMedium;
0594             if( requestedMediaTypes == (Device::MEDIA_WRITABLE_DVD|Device::MEDIA_WRITABLE_BD) ||
0595                 requestedMediaTypes == (Device::MEDIA_WRITABLE_DVD_DL|Device::MEDIA_WRITABLE_BD) )
0596                 desiredMedium = i18nc("To be shown when a DVD or Blu-ray is required but another type of medium is inserted.", "DVD or Blu-ray");
0597             else if( requestedMediaTypes == Device::MEDIA_WRITABLE_BD )
0598                 desiredMedium = i18nc("To be shown when a Blu-ray is required but another type of medium is inserted.", "Blu-ray");
0599             else if( requestedMediaTypes == Device::MEDIA_WRITABLE_CD )
0600                 desiredMedium = i18nc("To be shown when a CD is required but another type of medium is inserted.", "CD");
0601             else if( requestedMediaTypes == Device::MEDIA_WRITABLE_DVD )
0602                 desiredMedium = i18nc("To be shown when a DVD is required but another type of medium is inserted.", "DVD");
0603             else if( requestedMediaTypes == Device::MEDIA_WRITABLE_DVD_DL )
0604                 desiredMedium = i18nc("To be shown when a DVD-DL is required but another type of medium is inserted.", "DVD-DL");
0605 
0606             if ( requestedMediaTypes == Device::MEDIA_REWRITABLE ) {
0607                 if ( desiredMedium.isEmpty() ) {
0608                     desiredMedium = i18n("rewritable medium");
0609                 }
0610                 else {
0611                     desiredMedium = i18nc("%1 is type of medium (e.g. DVD)", "rewritable %1", desiredMedium);
0612                 }
0613             }
0614 
0615             if ( desiredMedium.isEmpty() )
0616                 desiredMedium = i18nc("To be shown when a specific type of medium is required but another type of medium is inserted.", "suitable medium");
0617 
0618             toReturn.append(i18n("Medium in %1 is not a %2.", deviceString, desiredMedium));
0619         }
0620         else if (!okMediaState) {
0621             QString desiredState;
0622             if( requestedMediaStates == Device::STATE_EMPTY )
0623                 desiredState = i18nc("To be shown when an empty medium is required", "empty");
0624             else if (requestedMediaStates == (Device::STATE_EMPTY|Device::STATE_INCOMPLETE) )
0625                 desiredState = i18nc("To be shown when an empty or appendable medium is required", "empty or appendable");
0626             else if( requestedMediaStates == (Device::STATE_COMPLETE|Device::STATE_INCOMPLETE) )
0627                 desiredState = i18nc("To be shown when an non-empty medium is required", "non-empty");
0628             else
0629                 desiredState = i18nc("To be shown when the state of the inserted medium is not suitable.", "suitable");
0630 
0631             toReturn.append(i18n("Medium in %1 is not %2.", deviceString, desiredState));
0632         }
0633         else if ( !okSize ) {
0634             toReturn.append(i18n("Capacity of the medium in %1 is smaller than required.", deviceString));
0635         }
0636     }
0637 
0638     if (toReturn.isEmpty())
0639         toReturn.append(mediaRequestString( requestedMediaTypes, requestedMediaStates, requestedSize, dev));
0640     return toReturn;
0641 }
0642 
0643 // static
0644 QString K3b::Medium::mediaRequestString( Device::MediaTypes requestedMediaTypes, Device::MediaStates requestedMediaStates, const K3b::Msf& requestedSize, Device::Device* dev )
0645 {
0646     //
0647     // The following cases make sense and are used in K3b:
0648     //  0. empty writable medium (data/emovix project and image)
0649     //  1. empty writable CD (audio/vcd project and copy and image)
0650     //  2. empty writable DVD (video dvd project and copy)
0651     //  2.1 empty writable DL DVD (video dvd project and copy)
0652     //  3. empty writable Blu-ray (copy and image)
0653     //  3.1 empty writable DL Blu-ray (image, copy)
0654     //  3.2 empty writable DVD or Blu-ray (image)
0655     //  4. non-empty rewritable medium (format)
0656     //  5. empty or appendable medium (data/emovix project)
0657     //  6. empty or appendable DVD or Blu-ray (could be handled via size)
0658     //  7. empty or appendable Blu-ray (could be handled via size)
0659     //  8. non-empty CD (CD cloning)
0660     //  9. non-empty medium (copy)
0661 
0662     QString deviceString;
0663     if( dev )
0664         deviceString = dev->vendor() + ' ' + dev->description() + QLatin1String(" (") + dev->blockDeviceName() + ')';
0665 
0666     // restrict according to requested size
0667     // FIXME: this does not handle all cases, for example: we have SL and DL DVD in the media types, but only plain BD
0668     if( requestedSize > 0 ) {
0669         if( requestedSize > K3b::MediaSizeCd100Min )
0670             requestedMediaTypes &= ~Device::MEDIA_CD_ALL;
0671         if( requestedSize > K3b::MediaSizeDvd4Gb )
0672             requestedMediaTypes &= ~Device::MEDIA_WRITABLE_DVD_SL;
0673         if( requestedSize > K3b::MediaSizeDvd8Gb )
0674             requestedMediaTypes &= ~Device::MEDIA_WRITABLE_DVD_DL;
0675     }
0676 
0677 #ifdef __GNUC__
0678 #warning Use the i18n string formatting like <strong> or whatever instead of normal html/rtf like <b>
0679 #endif
0680     if( requestedMediaStates == Device::STATE_EMPTY ) {
0681         if( requestedMediaTypes == Device::MEDIA_WRITABLE ) {
0682             if( dev )
0683                 return i18n("Please insert an empty medium into drive<p><b>%1</b>", deviceString);
0684             else
0685                 return i18n("Please insert an empty medium");
0686         }
0687         else if( requestedMediaTypes == (Device::MEDIA_WRITABLE_DVD|Device::MEDIA_WRITABLE_BD) ||
0688                  requestedMediaTypes == (Device::MEDIA_WRITABLE_DVD_DL|Device::MEDIA_WRITABLE_BD) ) { // special case for data job
0689             if( dev )
0690                 return i18n("Please insert an empty DVD or Blu-ray medium into drive<p><b>%1</b>", deviceString);
0691             else
0692                 return i18n("Please insert an empty DVD or Blu-ray medium");
0693         }
0694         else if( requestedMediaTypes == Device::MEDIA_WRITABLE_BD ) {
0695             if( dev )
0696                 return i18n("Please insert an empty Blu-ray medium into drive<p><b>%1</b>", deviceString);
0697             else
0698                 return i18n("Please insert an empty Blu-ray medium");
0699         }
0700         else if( requestedMediaTypes == Device::MEDIA_WRITABLE_CD ) {
0701             if( dev )
0702                 return i18n("Please insert an empty CD medium into drive<p><b>%1</b>", deviceString);
0703             else
0704                 return i18n("Please insert an empty CD medium");
0705         }
0706         else if( requestedMediaTypes == Device::MEDIA_WRITABLE_DVD ) {
0707             if( dev )
0708                 return i18n("Please insert an empty DVD medium into drive<p><b>%1</b>", deviceString);
0709             else
0710                 return i18n("Please insert an empty DVD medium");
0711         }
0712         else if( requestedMediaTypes == Device::MEDIA_WRITABLE_DVD_DL ) {
0713             if( dev )
0714                 return i18n("Please insert an empty DVD-DL medium into drive<p><b>%1</b>", deviceString);
0715             else
0716                 return i18n("Please insert an empty DVD-DL medium");
0717         }
0718         else if ( requestedSize > 0 ) {
0719             if ( dev )
0720                 return i18n( "Please insert an empty medium of size %1 or larger into drive<p><b>%2</b>",
0721                              KIO::convertSize( requestedSize.mode1Bytes() ), deviceString);
0722             else
0723                 return i18n( "Please insert an empty medium of size %1 or larger", KIO::convertSize( requestedSize.mode1Bytes() ) );
0724         }
0725     }
0726     else if( requestedMediaStates == (Device::STATE_EMPTY|Device::STATE_INCOMPLETE) ) {
0727         if( requestedMediaTypes == Device::MEDIA_WRITABLE ) {
0728             if( dev )
0729                 return i18n("Please insert an empty or appendable medium into drive<p><b>%1</b>", deviceString);
0730             else
0731                 return i18n("Please insert an empty or appendable medium");
0732         }
0733         else if( requestedMediaTypes == (Device::MEDIA_WRITABLE_DVD|Device::MEDIA_WRITABLE_BD) ) {
0734             if( dev )
0735                 return i18n("Please insert an empty or appendable DVD or Blu-ray medium into drive<p><b>%1</b>", deviceString);
0736             else
0737                 return i18n("Please insert an empty or appendable DVD or Blu-ray medium");
0738         }
0739         else if( requestedMediaTypes == Device::MEDIA_WRITABLE_BD ) {
0740             if( dev )
0741                 return i18n("Please insert an empty or appendable Blu-ray medium into drive<p><b>%1</b>", deviceString);
0742             else
0743                 return i18n("Please insert an empty or appendable Blu-ray medium");
0744         }
0745         else if( requestedMediaTypes == Device::MEDIA_WRITABLE_CD ) {
0746             if( dev )
0747                 return i18n("Please insert an empty or appendable CD medium into drive<p><b>%1</b>", deviceString);
0748             else
0749                 return i18n("Please insert an empty or appendable CD medium");
0750         }
0751         else if( requestedMediaTypes == Device::MEDIA_WRITABLE_DVD ) {
0752             if( dev )
0753                 return i18n("Please insert an empty or appendable DVD medium into drive<p><b>%1</b>", deviceString);
0754             else
0755                 return i18n("Please insert an empty or appendable DVD medium");
0756         }
0757         else if( requestedMediaTypes == Device::MEDIA_WRITABLE_DVD_DL ) {
0758             if( dev )
0759                 return i18n("Please insert an empty or appendable DVD-DL medium into drive<p><b>%1</b>", deviceString);
0760             else
0761                 return i18n("Please insert an empty or appendable DVD-DL medium");
0762         }
0763     }
0764     else if( requestedMediaStates == (Device::STATE_COMPLETE|Device::STATE_INCOMPLETE) ) {
0765         if( requestedMediaTypes == Device::MEDIA_ALL ) {
0766             if( dev )
0767                 return i18n("Please insert a non-empty medium into drive<p><b>%1</b>", deviceString);
0768             else
0769                 return i18n("Please insert a non-empty medium");
0770         }
0771         else if( requestedMediaTypes == Device::MEDIA_REWRITABLE ) {
0772             if( dev )
0773                 return i18n("Please insert a non-empty rewritable medium into drive<p><b>%1</b>", deviceString);
0774             else
0775                 return i18n("Please insert a non-empty rewritable medium");
0776         }
0777     }
0778     else if( requestedMediaStates == (Device::STATE_COMPLETE|Device::STATE_INCOMPLETE|Device::STATE_EMPTY) ) {
0779         if( requestedMediaTypes == Device::MEDIA_REWRITABLE ) {
0780             if( dev )
0781                 return i18n("Please insert a rewritable medium into drive<p><b>%1</b>", deviceString);
0782             else
0783                 return i18n("Please insert a rewritable medium");
0784         }
0785     }
0786 
0787     // fallback
0788     if( dev )
0789         return i18n("Please insert a suitable medium into drive<p><b>%1</b>", deviceString);
0790     else
0791         return i18n("Please insert a suitable medium");
0792 }
0793 
0794 
0795 // static
0796 QString K3b::Medium::mediaRequestString( MediumContents content, Device::Device* dev )
0797 {
0798     QString deviceString;
0799     if( dev )
0800         deviceString = dev->vendor() + ' ' + dev->description() + QLatin1String(" (") + dev->blockDeviceName() + ')';
0801 
0802     if( content == K3b::Medium::ContentVideoCD ) {
0803         if( dev )
0804             return i18n("Please insert a Video CD medium into drive<p><b>%1</b>", deviceString);
0805         else
0806             return i18n("Please insert a Video CD medium");
0807     }
0808     else if ( content == K3b::Medium::ContentVideoDVD ) {
0809         if( dev )
0810             return i18n("Please insert a Video DVD medium into drive<p><b>%1</b>", deviceString);
0811         else
0812             return i18n("Please insert a Video DVD medium");
0813     }
0814     else if( content == (K3b::Medium::ContentAudio|K3b::Medium::ContentData) ) {
0815         if( dev )
0816             return i18n("Please insert a Mixed Mode CD medium into drive<p><b>%1</b>", deviceString);
0817         else
0818             return i18n("Please insert a Mixed Mode CD medium");
0819     }
0820     else if( content == K3b::Medium::ContentAudio ) {
0821         if( dev )
0822             return i18n("Please insert an Audio CD medium into drive<p><b>%1</b>", deviceString);
0823         else
0824             return i18n("Please insert an Audio CD medium");
0825     }
0826     else if( content == K3b::Medium::ContentData ) {
0827         if( dev )
0828             return i18n("Please insert a Data medium into drive<p><b>%1</b>", deviceString);
0829         else
0830             return i18n("Please insert a Data medium");
0831     }
0832 
0833     // fallback
0834     if( dev )
0835         return i18n("Please insert a suitable medium into drive<p><b>%1</b>", deviceString);
0836     else
0837         return i18n("Please insert a suitable medium");
0838 }