1 /*
2 SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
3 SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
6 #include "k3bdatamultisessionimportdialog.h"
7 #include "k3bcore.h"
8 #include "k3bdatadoc.h"
9 #include "k3btoc.h"
10 #include "k3bdevice.h"
11 #include "k3bdevicemanager.h"
12 #include "k3bdiskinfo.h"
13 #include "k3biso9660.h"
14 #include "k3bmedium.h"
15 #include "k3bmediacache.h"
16
17 #include "../k3bapplication.h"
18 #include "../k3b.h"
19
20 #include <KIconLoader>
21 #include <KLocalizedString>
22 #include <KMessageBox>
23
24 #include <QMap>
25 #include <QCursor>
26 #include <QFont>
27 #include <QDialogButtonBox>
28 #include <QLabel>
29 #include <QLayout>
30 #include <QPushButton>
31 #include <QTreeWidget>
32 #include <QVBoxLayout>
33
34 namespace {
35 class SessionInfo
36 {
37 public:
SessionInfo()38 SessionInfo()
39 : sessionNumber( 0 ),
40 device( 0 ) {}
41
SessionInfo(int num,K3b::Device::Device * dev)42 SessionInfo( int num, K3b::Device::Device* dev )
43 : sessionNumber( num ),
44 device( dev ) {}
45
46 int sessionNumber;
47 K3b::Device::Device* device;
48 };
49
50 typedef QMap<QTreeWidgetItem*, SessionInfo> Sessions;
51 }
52
53
54 class K3b::DataMultisessionImportDialog::Private
55 {
56 public:
57 K3b::DataDoc* doc;
58 QTreeWidget* sessionView;
59 QPushButton* okButton;
60
61 Sessions sessions;
62 };
63
64
importSession(K3b::DataDoc * doc,QWidget * parent)65 K3b::DataDoc* K3b::DataMultisessionImportDialog::importSession( K3b::DataDoc* doc, QWidget* parent )
66 {
67 K3b::DataMultisessionImportDialog dlg( parent );
68 dlg.importSession( doc );
69 dlg.exec();
70 return dlg.d->doc;
71 }
72
73
slotOk()74 void K3b::DataMultisessionImportDialog::slotOk()
75 {
76 Sessions::const_iterator session = d->sessions.constFind( d->sessionView->currentItem() );
77 if ( session != d->sessions.constEnd() ) {
78 QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
79
80 K3b::Device::Device* dev = session->device;
81
82 //
83 // Mkisofs does not properly import joliet filenames from an old session
84 //
85 // See bug 79215 for details
86 //
87 K3b::Iso9660 iso( dev );
88 if( iso.open() ) {
89 if( iso.firstRRDirEntry() == 0 && iso.jolietLevel() > 0 )
90 KMessageBox::sorry( this,
91 i18n("<p>K3b found session containing Joliet information for long filenames "
92 "but no Rock Ridge extensions."
93 "<p>The filenames in the imported session will be converted to a restricted "
94 "character set in the new session. This character set is based on the ISO 9660 "
95 "settings in the K3b project. K3b is not able to display these converted filenames yet."),
96 i18n("Session Import Warning") );
97 iso.close();
98 }
99
100 if( !d->doc ) {
101 d->doc = static_cast<K3b::DataDoc*>( k3bappcore->k3bMainWindow()->slotNewDataDoc() );
102 }
103
104 d->doc->setBurner( dev );
105 d->doc->importSession( dev, session->sessionNumber );
106
107 QApplication::restoreOverrideCursor();
108
109 done( 0 );
110 }
111 }
112
113
slotCancel()114 void K3b::DataMultisessionImportDialog::slotCancel()
115 {
116 reject();
117 }
118
119
importSession(K3b::DataDoc * doc)120 void K3b::DataMultisessionImportDialog::importSession( K3b::DataDoc* doc )
121 {
122 d->doc = doc;
123 updateMedia();
124 slotSelectionChanged();
125 }
126
127
updateMedia()128 void K3b::DataMultisessionImportDialog::updateMedia()
129 {
130 d->sessionView->clear();
131 d->sessions.clear();
132
133 QList<K3b::Device::Device*> devices = k3bcore->deviceManager()->allDevices();
134
135 bool haveMedium = false;
136 for( QList<K3b::Device::Device *>::const_iterator it = devices.constBegin();
137 it != devices.constEnd(); ++it ) {
138 K3b::Medium medium = k3bappcore->mediaCache()->medium( *it );
139
140 if ( medium.diskInfo().mediaType() & K3b::Device::MEDIA_WRITABLE &&
141 medium.diskInfo().diskState() == K3b::Device::STATE_INCOMPLETE ) {
142 addMedium( medium );
143 haveMedium = true;
144 }
145 else if ( !medium.diskInfo().empty() &&
146 medium.diskInfo().mediaType() & ( K3b::Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_RW_OVWR ) ) {
147 addMedium( medium );
148 haveMedium = true;
149 }
150 }
151
152 if ( !haveMedium ) {
153 QTreeWidgetItem* noMediaItem = new QTreeWidgetItem( d->sessionView );
154 QFont fnt( noMediaItem->font(0) );
155 fnt.setItalic( true );
156 noMediaItem->setText( 0, i18n( "Please insert an appendable medium" ) );
157 noMediaItem->setFont( 0, fnt );
158 }
159 else if( QTreeWidgetItem* firstMedium = d->sessionView->topLevelItem(0) ) {
160 if( firstMedium->childCount() > 0 )
161 d->sessionView->setCurrentItem( firstMedium->child( firstMedium->childCount()-1 ) );
162 else
163 d->sessionView->setCurrentItem( firstMedium );
164 }
165
166 d->sessionView->setEnabled( haveMedium );
167 }
168
169
addMedium(const K3b::Medium & medium)170 void K3b::DataMultisessionImportDialog::addMedium( const K3b::Medium& medium )
171 {
172 QTreeWidgetItem* mediumItem = new QTreeWidgetItem( d->sessionView );
173 QFont fnt( mediumItem->font(0) );
174 fnt.setBold( true );
175 mediumItem->setText( 0, medium.shortString() );
176 mediumItem->setFont( 0, fnt );
177 mediumItem->setIcon( 0, QIcon::fromTheme("media-optical-recordable") );
178
179 const K3b::Device::Toc& toc = medium.toc();
180 QTreeWidgetItem* sessionItem = 0;
181 int lastSession = 0;
182 for ( K3b::Device::Toc::const_iterator it = toc.begin(); it != toc.end(); ++it ) {
183 const K3b::Device::Track& track = *it;
184
185 if( track.session() != lastSession ) {
186 lastSession = track.session();
187 QString sessionInfo;
188 if ( track.type() == K3b::Device::Track::TYPE_DATA ) {
189 K3b::Iso9660 iso( medium.device(), track.firstSector().lba() );
190 if ( iso.open() ) {
191 sessionInfo = iso.primaryDescriptor().volumeId;
192 }
193 }
194 else {
195 int numAudioTracks = 1;
196 while ( it != toc.end()
197 && ( *it ).type() == K3b::Device::Track::TYPE_AUDIO
198 && ( *it ).session() == lastSession ) {
199 ++it;
200 ++numAudioTracks;
201 }
202 --it;
203 sessionInfo = i18np("1 audio track", "%1 audio tracks", numAudioTracks );
204 }
205
206 sessionItem = new QTreeWidgetItem( mediumItem, sessionItem );
207 sessionItem->setText( 0, i18n( "Session %1", lastSession )
208 + ( sessionInfo.isEmpty() ? QString() : " (" + sessionInfo + ')' ) );
209 if ( track.type() == K3b::Device::Track::TYPE_AUDIO )
210 sessionItem->setIcon( 0, QIcon::fromTheme( "audio-x-generic" ) );
211 else
212 sessionItem->setIcon( 0, QIcon::fromTheme( "application-x-tar" ) );
213
214 d->sessions.insert( sessionItem, SessionInfo( lastSession, medium.device() ) );
215 }
216 }
217
218 if( 0 == lastSession ) {
219 // the medium item in case we have no session info (will always use the last session)
220 d->sessions.insert( mediumItem, SessionInfo( 0, medium.device() ) );
221 }
222 else {
223 // we have a session item, there is no need to select the medium as a whole
224 mediumItem->setFlags( mediumItem->flags() ^ Qt::ItemIsSelectable );
225 }
226
227 mediumItem->setExpanded( true );
228 }
229
230
slotSelectionChanged()231 void K3b::DataMultisessionImportDialog::slotSelectionChanged()
232 {
233 Sessions::const_iterator session = d->sessions.constFind( d->sessionView->currentItem() );
234 if ( session != d->sessions.constEnd() ) {
235 d->okButton->setEnabled( true );
236 }
237 else {
238 d->okButton->setEnabled( false );
239 }
240 }
241
242
DataMultisessionImportDialog(QWidget * parent)243 K3b::DataMultisessionImportDialog::DataMultisessionImportDialog( QWidget* parent )
244 : QDialog( parent),
245 d( new Private() )
246 {
247 setModal(true);
248 setWindowTitle(i18n("Session Import"));
249 QVBoxLayout* layout = new QVBoxLayout( this );
250
251 QLabel* label = new QLabel( i18n( "Please select a session to import." ), this );
252 d->sessionView = new QTreeWidget( this );
253 d->sessionView->setHeaderHidden( true );
254 d->sessionView->setItemsExpandable( false );
255 d->sessionView->setRootIsDecorated( false );
256
257 QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this );
258 d->okButton = buttonBox->button( QDialogButtonBox::Ok );
259 connect( buttonBox, SIGNAL(accepted()), SLOT(accept()) );
260 connect( buttonBox, SIGNAL(rejected()), SLOT(reject()) );
261
262 layout->addWidget( label );
263 layout->addWidget( d->sessionView );
264 layout->addWidget( buttonBox );
265
266 connect( k3bappcore->mediaCache(), SIGNAL(mediumChanged(K3b::Device::Device*)),
267 this, SLOT(updateMedia()) );
268 connect( d->sessionView, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
269 this, SLOT(slotSelectionChanged()) );
270 connect(d->sessionView, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SLOT(slotOk()) );
271 connect(d->okButton, SIGNAL(clicked()), this, SLOT(slotOk()));
272 connect(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(slotCancel()));
273 }
274
275
~DataMultisessionImportDialog()276 K3b::DataMultisessionImportDialog::~DataMultisessionImportDialog()
277 {
278 delete d;
279 }
280
281
282