runtime debug infrastructure
[kmk.git] / src / kmktaged.cpp
blob6be1302f2c069a03928d242a3718954fea5c7b73
1 /***************************************************************************
2 * KMK - KDE Music Cataloger - the tool for personal *
3 * audio collection management *
4 * *
5 * Copyright (C) 2006,2007 by Plamen Petrov *
6 * carpo@abv.bg *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
22 ***************************************************************************/
24 #include <qtooltip.h>
25 #include <qfileinfo.h>
26 #include <klocale.h>
27 #include <kdebug.h>
28 #include <kmessagebox.h>
29 #include <kapplication.h>
31 #include "tag.h"
32 #include "fileref.h"
33 #include "tstring.h"
34 #include "tfile.h"
36 #include "kmktaged.h"
38 #define TDLG "TagEdit Dialog: "
40 kmkTagEdit::kmkTagEdit( MmDataPList *files, uint *rm_flag )
41 : kmkTagEdBase( 0, "KMK Tag Editor Dialog", FALSE, Qt::WType_Dialog | Qt::WDestructiveClose )
43 s = new KmkGlobalSettings;
44 Q_CHECK_PTR( s );
45 s->readSettings( kapp->config() );
46 if( s->dbg() & KMK_DBG_CONFIG ) kdDebug() << TDLG"constructor: read config, now will use it..." << endl;
48 setModal( TRUE );
49 cbSaveOnNavigate->setChecked( s->saveOnNavigate() );
50 /* Disable Save button, as we have no chages yet */
51 pbSave->setEnabled( FALSE ); content_changed = FALSE; any_changed = FALSE;
52 remote_flag = rm_flag; *remote_flag = 0;
53 if (files)
55 fs = files;
56 if(fs->isEmpty()) {
57 KMessageBox::sorry( this, i18n("The Tag editor dialog cannot work without data."),
58 i18n("KDE Music Kataloger") );
59 done( Rejected ); // we have WDestructiveClose, so this should delete the dialog
60 return;
62 // Here we check if any of the items the given ptrlist points to is FOLDER. If so - bail out.
63 for ( current = fs->first(); current; current = fs->next() )
64 if((*current).IsDir())
66 if( s->dbg() & KMK_DBG_CAT_MEM_OPS )
67 kdDebug() << TDLG"constructor: DIR in recv. list! Stopping initialisation..." << endl;
68 done( Rejected );
70 current = fs->first();
71 pbFirst->setEnabled( FALSE ); pbPrev->setEnabled( FALSE );
72 if(fs->count()==1) { pbNext->setEnabled( FALSE ); pbLast->setEnabled( FALSE ); }
74 set_on_display( current );
76 if( s->dbg() & KMK_DBG_SIGNALS )
77 kdDebug() << TDLG"constructor: connecting signals to slots... " << endl;
79 connect( pbFirst, SIGNAL( clicked() ), this, SLOT( slotClicked_pbFirst() ) );
80 connect( pbPrev, SIGNAL( clicked() ), this, SLOT( slotClicked_pbPrev() ) );
81 connect( pbNext, SIGNAL( clicked() ), this, SLOT( slotClicked_pbNext() ) );
82 connect( pbLast, SIGNAL( clicked() ), this, SLOT( slotClicked_pbLast() ) );
83 connect( pbSave, SIGNAL( clicked() ), this, SLOT( slotClicked_pbSave() ) );
84 connect( pbClose, SIGNAL( clicked() ), this, SLOT( slotClicked_pbClose() ) );
86 handle_changes = FALSE;
87 connect( leArtist, SIGNAL( textChanged( const QString & ) ), this, SLOT( slotHandle_tag_change( const QString & ) ) );
88 connect( leTitle, SIGNAL( textChanged( const QString & ) ), this, SLOT( slotHandle_tag_change( const QString & ) ) );
89 connect( leAlbum, SIGNAL( textChanged( const QString & ) ), this, SLOT( slotHandle_tag_change( const QString & ) ) );
90 connect( leYear, SIGNAL( textChanged( const QString & ) ), this, SLOT( slotHandle_tag_change( const QString & ) ) );
91 connect( leTrackNum, SIGNAL( textChanged( const QString & ) ), this, SLOT( slotHandle_tag_change( const QString & ) ) );
92 connect( leGenre, SIGNAL( textChanged( const QString & ) ), this, SLOT( slotHandle_tag_change( const QString & ) ) );
93 connect( leComment, SIGNAL( textChanged( const QString & ) ), this, SLOT( slotHandle_tag_change( const QString & ) ) );
94 handle_changes = TRUE;
96 if( s->dbg() & KMK_DBG_SIGNALS )
97 kdDebug() << TDLG"constructor: done connecting signals!" << endl;
99 exec();
103 kmkTagEdit::~kmkTagEdit()
105 if (fs)
107 if( s->dbg() & KMK_DBG_CAT_MEM_OPS )
108 kdDebug() << TDLG"destructor: removing TagEd temp data from list..." << endl;
109 for ( current = fs->first(); current; current = fs->next() )
110 (*current).setIsDir( FALSE );
111 if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) kdDebug() << TDLG"destructor: done." << endl;
113 if( s->dbg() & KMK_DBG_CONFIG )
114 kdDebug() << TDLG"destructor: saving setting from SaveOnNavigate checkbox..." << endl;
115 s->setSaveOnNavigate( cbSaveOnNavigate->isChecked() );
116 if( s->dbg() & KMK_DBG_CONFIG )
117 kdDebug() << TDLG"destructor: ...and writing it on disk..." << endl;
118 s->saveSettings( kapp->config() );
119 if( s->dbg() & KMK_DBG_CONFIG ) kdDebug() << TDLG"destructor: ...done!" << endl;
120 delete s;
123 void kmkTagEdit::save_current()
125 if( content_changed )
127 if( s->dbg() & KMK_DBG_CAT_MEM_OPS )
128 kdDebug() << TDLG"save_current: saving changed content in memory..." << endl;
129 (*current).setArtist( leArtist->text() );
130 (*current).setTitle( leTitle->text() );
131 (*current).setAlbum( leAlbum->text() );
132 (*current).setTrackNum( leTrackNum->text().toInt() );
133 (*current).setYear( leYear->text().toInt() );
134 (*current).setGenre( leGenre->text() );
135 (*current).setComment( leComment->text() );
136 if( s->dbg() ) kdDebug() << TDLG"save_current: SHOULD BE saving tag in file..." << endl;
137 if( (*current).IsReadOnly() )
138 KMessageBox::sorry( this, i18n("According to the file info - it is read only.\n"
139 "This should have stopped you from getting here -\n"
140 "trying to save to a Read-only file."),
141 i18n("KDE Music Kataloger") );
142 using namespace TagLib;
143 /* Use TagLib's functions to save meta data and audio properties;
144 This tells TagLib to NOT read tags, and be as fast as possible */
145 QString fn = (*current).Folder()+"/"+(*current).FileName();
146 if( s->dbg() & KMK_DBG_FS_OPS )
147 kdDebug() << TDLG"save_current: saving tag for file: " << fn << "..." << endl;
148 TagLib::FileRef f( fn, FALSE, TagLib::AudioProperties::Fast );
149 /* If TagLib found the file to be valid - then add it to the catalog.
150 Maybe here would be a good place to update some global catalog stats,
151 like total storage used by the collection we are cataloguining, number
152 of files in it, average bitrate, highest one, lowest one, biggest file,
153 smallest file... and anything else someone might consider "interesting"!*/
154 if( f.file()->isValid() )
156 TagLib::String u;
157 u = (*current).Artist().latin1(); f.tag()->setArtist( u );
158 u = (*current).Title().latin1(); f.tag()->setTitle( u );
159 u = (*current).Album().latin1(); f.tag()->setAlbum( u );
160 u = (*current).Genre().latin1(); f.tag()->setGenre( u );
161 u = (*current).Comment().latin1(); f.tag()->setComment( u );
162 f.tag()->setTrack( (*current).TrackNum() );
163 f.tag()->setYear( (*current).Year() );
164 if( !f.save() )
165 KMessageBox::sorry( this, i18n("Something prevented KMK from writing\n"
166 "the tag to file [%1].").arg(fn),
167 i18n("KDE Music Kataloger") );
168 else
169 { // tag is saved, now get the last modified time for it
170 if( s->dbg() & KMK_DBG_FS_OPS )
171 kdDebug() << TDLG"save_current: getting [" << fn << "]'s \"last modified\" time..." << endl;
172 QFileInfo *fi = new QFileInfo( fn );
173 if( fi )
175 if( s->dbg() & KMK_DBG_CAT_MEM_OPS )
176 kdDebug() << TDLG"save_current: fixing [" << fn << "]'s \"last modified\" time..." << endl;
177 (*current).setModifiedTime( fi->lastModified().toTime_t() );
178 delete fi;
182 // after changing a file in the list, mark the hole list as changed,
183 // and also set the remote_flag accordingly - set on first save
184 any_changed = TRUE; *remote_flag = 1;
185 if( s->dbg() & KMK_DBG_FS_OPS )
186 kdDebug() << TDLG"save_current: ...done!" << endl;
188 content_changed = FALSE;
189 pbSave->setEnabled( FALSE );
192 void kmkTagEdit::slotHandle_tag_change( const QString & m )
194 Q_UNUSED(m);
195 if(!handle_changes) return;
196 if( s->dbg() & KMK_DBG_SIGNALS )
197 kdDebug() << TDLG"slotHandle_tag_change: processing request..." << endl;
198 bool new_tag_is_different = FALSE;
199 if( leArtist->text().compare( (*current).Artist() )!=0 ) new_tag_is_different = TRUE;
200 if( leTitle->text().compare( (*current).Title() )!=0 ) new_tag_is_different = TRUE;
201 if( leAlbum->text().compare( (*current).Album() )!=0 ) new_tag_is_different = TRUE;
202 if( leTrackNum->text().compare
203 (((*current).TrackNum())?QString::number((*current).TrackNum() ):"")!=0 ) new_tag_is_different = TRUE;
204 if( leYear->text().compare
205 (((*current).Year())?QString::number( (*current).Year() ):"")!=0 ) new_tag_is_different = TRUE;
206 if( leGenre->text().compare( (*current).Genre() )!=0 ) new_tag_is_different = TRUE;
207 if( leComment->text().compare( (*current).Comment() )!=0 ) new_tag_is_different = TRUE;
208 if( new_tag_is_different )
210 content_changed = TRUE;
211 pbSave->setEnabled( TRUE );
212 // we use MmData's IsDir property to know whether a file's tag is changed, and should be saved
213 (*current).setIsDir( TRUE );
215 else // maybe the user just set the data back to where it was...
217 content_changed = FALSE;
218 pbSave->setEnabled( FALSE );
219 (*current).setIsDir( FALSE );
221 if( s->dbg() & KMK_DBG_SIGNALS )
222 kdDebug() << TDLG"slotHandle_tag_change: done!" << endl;
225 void kmkTagEdit::set_on_display( MmData *i )
227 if( s->dbg() & KMK_DBG_OTHER ) kdDebug() << TDLG"set_on_display: " <<
228 (( (*i).IsDir() )?"item appears modified - enabling Save button"
229 :"no save needed - disabling Save button") << endl;
230 if( (*i).IsDir() ) pbSave->setEnabled( TRUE );
231 else pbSave->setEnabled( FALSE );
232 handle_changes = FALSE;
233 QToolTip::remove( tl_fn );
234 QToolTip::add( tl_fn, (*i).Folder() + "/" + (*i).FileName() );
235 tl_fn->setText( (*i).Folder() + "/" + (*i).FileName() );
236 leArtist->setText( (*i).Artist() );
237 leTitle->setText( (*i).Title() );
238 leAlbum->setText( (*i).Album() );
239 leTrackNum->setText( ((*i).TrackNum()!=0)?QString::number( (*i).TrackNum() ):"" );
240 leYear->setText( ((*i).Year()!=0)?QString::number( (*i).Year() ):"" );
241 leGenre->setText( (*i).Genre() );
242 leComment->setText( (*i).Comment() );
243 if( (*i).IsReadOnly() )
245 leArtist->setEnabled( FALSE );
246 leTitle->setEnabled( FALSE );
247 leAlbum->setEnabled( FALSE );
248 leTrackNum->setEnabled( FALSE );
249 leYear->setEnabled( FALSE );
250 leGenre->setEnabled( FALSE );
251 leComment->setEnabled( FALSE );
253 else
255 leArtist->setEnabled( TRUE );
256 leTitle->setEnabled( TRUE );
257 leAlbum->setEnabled( TRUE );
258 leTrackNum->setEnabled( TRUE );
259 leYear->setEnabled( TRUE );
260 leGenre->setEnabled( TRUE );
261 leComment->setEnabled( TRUE );
263 handle_changes = TRUE;
266 void kmkTagEdit::slotClicked_pbFirst()
268 if( s->dbg() & KMK_DBG_SIGNALS )
269 kdDebug() << TDLG"slotClicked_pbFirst: processing request..." << endl;
270 if( cbSaveOnNavigate->isChecked() ) save_current();
271 if(current != fs->getFirst())
273 current = fs->first();
274 if( fs->count()>1 )
276 pbNext->setEnabled( TRUE );
277 pbLast->setEnabled( TRUE );
279 set_on_display( current );
280 pbPrev->setEnabled( FALSE );
281 pbFirst->setEnabled( FALSE );
283 if( s->dbg() & KMK_DBG_SIGNALS )
284 kdDebug() << TDLG"slotClicked_pbFirst: done!" << endl;
287 void kmkTagEdit::slotClicked_pbPrev()
289 if( s->dbg() & KMK_DBG_SIGNALS )
290 kdDebug() << TDLG"slotClicked_pbPrev: processing request..." << endl;
291 // pbSave->setEnabled( FALSE );
292 if( cbSaveOnNavigate->isChecked() ) save_current();
293 if(current != fs->getFirst())
295 current = fs->prev();
296 if( fs->count()>1 )
298 pbNext->setEnabled( TRUE );
299 pbLast->setEnabled( TRUE );
301 set_on_display( current );
302 if( (current == fs->getFirst()) || (fs->count() == 2) )
304 pbPrev->setEnabled( FALSE );
305 pbFirst->setEnabled( FALSE );
308 if( s->dbg() & KMK_DBG_SIGNALS )
309 kdDebug() << TDLG"slotClicked_pbPrev: done!" << endl;
312 void kmkTagEdit::slotClicked_pbNext()
314 if( s->dbg() & KMK_DBG_SIGNALS )
315 kdDebug() << TDLG"slotClicked_pbNext: processing request..." << endl;
316 if( cbSaveOnNavigate->isChecked() ) save_current();
317 if( current != fs->getLast() )
319 current = fs->next();
320 if( fs->count()>1 )
322 pbPrev->setEnabled( TRUE );
323 pbFirst->setEnabled( TRUE );
325 set_on_display( current );
326 if( (current == fs->getLast()) || (fs->count() == 2) )
328 pbNext->setEnabled( FALSE );
329 pbLast->setEnabled( FALSE );
332 if( s->dbg() & KMK_DBG_SIGNALS )
333 kdDebug() << TDLG"slotClicked_pbNext: done!" << endl;
336 void kmkTagEdit::slotClicked_pbLast()
338 if( s->dbg() & KMK_DBG_SIGNALS )
339 kdDebug() << TDLG"slotClicked_pbLast: processing request..." << endl;
340 if( cbSaveOnNavigate->isChecked() ) save_current();
341 if( current != fs->getLast())
343 current = fs->last();
344 if( fs->count()>1 )
346 pbPrev->setEnabled( TRUE );
347 pbFirst->setEnabled( TRUE );
349 set_on_display( current );
350 pbNext->setEnabled( FALSE );
351 pbLast->setEnabled( FALSE );
353 if( s->dbg() & KMK_DBG_SIGNALS )
354 kdDebug() << TDLG"slotClicked_pbLast: done!" << endl;
357 void kmkTagEdit::slotClicked_pbSave()
359 if( s->dbg() & KMK_DBG_SIGNALS )
360 kdDebug() << TDLG"slotClicked_pbSave: processing request..." << endl;
361 save_current();
362 if( s->dbg() & KMK_DBG_SIGNALS )
363 kdDebug() << TDLG"slotClicked_pbSave: done!" << endl;
366 void kmkTagEdit::slotClicked_pbClose()
368 if( s->dbg() & KMK_DBG_SIGNALS )
369 kdDebug() << TDLG"slotClicked_pbClose: processing request..." << endl;
370 if( content_changed )
371 switch( KMessageBox::questionYesNoCancel( this,
372 i18n("The current file's tags were modified. Do you want "
373 "to save the changes before closing the dialog?"),
374 i18n("KDE Music Kataloger") ) ) {
375 case KMessageBox::Yes: // Save & Exit
376 save_current();
377 close();
378 break;
379 case KMessageBox::No: // Discard - just Exit
380 close();
381 break;
382 case KMessageBox::Cancel: // Cancel - no nothing
383 break;
385 else close();
386 if( s->dbg() & KMK_DBG_SIGNALS )
387 kdDebug() << TDLG"slotClicked_pbClose: done!" << endl;
390 #include "kmktaged.moc"