kwave  18.07.70
FileInfoDialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  FileInfoDialog.cpp - dialog for editing file properties
3  -------------------
4  begin : Sat Jul 20 2002
5  copyright : (C) 2002 by Thomas Eschenbacher
6  email : Thomas.Eschenbacher@gmx.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "config.h"
19 
20 #include <QCheckBox>
21 #include <QDateTime>
22 #include <QDialog>
23 #include <QFileInfo>
24 #include <QLabel>
25 #include <QListWidget>
26 #include <QPushButton>
27 #include <QRadioButton>
28 #include <QSlider>
29 #include <QSpinBox>
30 #include <QString>
31 #include <QStringList>
32 #include <QToolTip>
33 #include <QWhatsThis>
34 #include <QtGlobal>
35 #include <QUrl>
36 #include <QLineEdit>
37 #include <QLocale>
38 #include <QSpinBox>
39 #include <QDateEdit>
40 
41 #include <KComboBox>
42 #include <KConfig>
43 #include <KConfigGroup>
44 #include <KHelpClient>
45 #include <KLocalizedString>
46 #include <KSharedConfig>
47 
48 #include "libkwave/CodecManager.h"
49 #include "libkwave/Compression.h"
50 #include "libkwave/Encoder.h"
51 #include "libkwave/FileInfo.h"
52 #include "libkwave/GenreType.h"
53 #include "libkwave/SampleFormat.h"
54 #include "libkwave/String.h"
55 #include "libkwave/Utils.h"
56 
57 #include "BitrateWidget.h"
58 #include "CompressionWidget.h"
59 #include "FileInfoDialog.h"
60 #include "KeywordWidget.h"
61 #include "SelectDateDialog.h"
62 
64 #define CONFIG_DEFAULT_SECTION "plugin fileinfo - setup dialog"
65 
66 //***************************************************************************
68  :QDialog(parent), Ui::FileInfoDlg(), m_info(info)
69 {
70  setupUi(this);
71 
72  connect(cbCompression, SIGNAL(currentIndexChanged(int)),
73  this, SLOT(compressionChanged()));
74  connect(cbMpegLayer, SIGNAL(currentIndexChanged(int)),
75  this, SLOT(mpegLayerChanged()));
76  connect(chkMpegCopyrighted, SIGNAL(clicked(bool)),
77  this, SLOT(mpegCopyrightedChanged(bool)));
78  connect(chkMpegOriginal, SIGNAL(clicked(bool)),
79  this, SLOT(mpegOriginalChanged(bool)));
80  connect(btHelp->button(QDialogButtonBox::Help), SIGNAL(clicked()),
81  this, SLOT(invokeHelp()));
82 
83  // open config for reading default settings
84  KConfigGroup cfg = KSharedConfig::openConfig()->group(CONFIG_DEFAULT_SECTION);
85 
88  setupMpegTab();
93 
94  // set the focus onto the "OK" button
95  buttonBox->button(QDialogButtonBox::Ok)->setFocus();
96 }
97 
98 //***************************************************************************
100 {
101 }
102 
103 //***************************************************************************
105  const QString &name,
106  const QString &description)
107 {
108  if (!widget) return;
109  widget->setToolTip(description);
110  widget->setWhatsThis(_("<b>") + name + _("</b><br>") + description);
111 }
112 
113 //***************************************************************************
114 void Kwave::FileInfoDialog::initInfo(QLabel *label, QWidget *widget,
115  Kwave::FileProperty property)
116 {
117  if (label) label->setText(i18n(UTF8(m_info.name(property))) + _(":"));
118  if (widget) describeWidget(widget,
119  i18n(UTF8(m_info.name(property))),
120  i18n(UTF8(m_info.description(property))));
121 }
122 
123 //***************************************************************************
124 void Kwave::FileInfoDialog::initInfoText(QLabel *label, QLineEdit *edit,
125  Kwave::FileProperty property)
126 {
127  initInfo(label, edit, property);
128  if (edit) edit->setText(QVariant(m_info.get(property)).toString());
129 }
130 
131 //***************************************************************************
133 {
134  /* filename */
135  initInfo(lblFileName, edFileName, Kwave::INF_FILENAME);
136  QFileInfo fi(QVariant(m_info.get(Kwave::INF_FILENAME)).toString());
137  QString file_name = fi.fileName();
138  edFileName->setText(file_name);
139  edFileName->setEnabled(file_name.length() != 0);
140 
141  /* mime type */
142  QString mimetype = QVariant(m_info.get(Kwave::INF_MIMETYPE)).toString();
143  if (!mimetype.length())
144  mimetype = _("audio/x-wav"); // default mimetype
145 
146  qDebug("mimetype = %s", DBG(mimetype));
147 
148  /*
149  * Check if the file name, mime type and compression match. If not,
150  * we might be in the "SaveAs" mode and the compression belongs to
151  * the old file name
152  */
153  if (file_name.length()) {
154  QString mt = Kwave::CodecManager::mimeTypeOf(QUrl(file_name));
156  if (encoder) {
157  // encoder does not support the file's mime type -> switch
158  if (!encoder->supports(mt)) {
159  qDebug("switching mime type to '%s'", DBG(mt));
161  mimetype = mt;
162  }
163 
164  // encoder does not support compression -> switch
165  QList<Kwave::Compression::Type> comps = encoder->compressionTypes();
168  );
169  if (!comps.contains(comp)) {
170  Kwave::Compression comp_old(comp);
171  Kwave::Compression comp_new(!comps.isEmpty() ?
172  comps.last() : Kwave::Compression::NONE
173  );
174  qDebug("compression '%s' not supported: switch to '%s'",
175  DBG(comp_old.name()), DBG(comp_new.name()));
177  Kwave::Compression(comp).toInt());
178  }
179 
180  // mime type does not match compression -> switch
181  QList<Kwave::Compression::Type> comps_found;
182  foreach (Kwave::Compression::Type c, comps) {
184  if ((cmp.preferredMimeType() == mimetype) &&
185  comps.contains(c))
186  {
187  comps_found.append(c);
188  break;
189  }
190  }
191  if (!comps_found.isEmpty() && !comps_found.contains(comp)) {
193  (comps_found.isEmpty() && !comps.isEmpty()) ?
194  comps.last() : comps_found.first();
195  Kwave::Compression comp_old(comp);
196  Kwave::Compression comp_new(cn);
197  qDebug("mime type/compression mismatch: "
198  "switch from '%s' to '%s'",
199  DBG(comp_old.name()), DBG(comp_new.name()));
200  m_info.set(Kwave::INF_COMPRESSION, comp_new.toInt());
201  }
202  }
203  }
204  edFileFormat->setText(mimetype);
205 
206  /* file size in bytes */
207  initInfo(lblFileSize, edFileSize, Kwave::INF_FILESIZE);
209  unsigned int size = QVariant(m_info.get(Kwave::INF_FILESIZE)).toUInt();
210  QString dotted = QLocale().toString(size);
211  if (size < 10*1024) {
212  edFileSize->setText(i18n("%1 bytes", dotted));
213  } else if (size < 10*1024*1024) {
214  edFileSize->setText(i18n("%1 kB (%2 byte)",
215  (size / 1024), dotted));
216  } else {
217  edFileSize->setText(i18n("%1 MB (%2 byte)",
218  (size / (1024*1024)), dotted));
219  }
220  } else {
221  edFileSize->setEnabled(false);
222  }
223 
224  /* file format (from mime type) */
225 
226  // use mimetype instead
227  initInfoText(lblFileFormat, edFileFormat, Kwave::INF_MIMETYPE);
228 
229  /* sample rate */
230  lblSampleRate->setText(i18n("Sample rate:"));
231  describeWidget(cbSampleRate, lblSampleRate->text().left(
232  lblSampleRate->text().length() - 1),
233  i18n("Here you can select one of the predefined\n"
234  "well-known sample rates or you can enter\n"
235  "any sample rate on your own."));
236  cbSampleRate->setEditText(QString::number(m_info.rate()));
237 
238  /* bits per sample */
239  lblResolution->setText(i18n("Resolution:"));
240  describeWidget(sbResolution, lblResolution->text().left(
241  lblResolution->text().length() - 1),
242  i18n("Select a resolution in bits in which the file\n"
243  "will be saved."));
244  sbResolution->setValue(m_info.bits());
245 
246  /* number of tracks */
247  lblChannels->setText(i18n("Tracks:"));
248  describeWidget(sbChannels, lblChannels->text().left(
249  lblChannels->text().length() - 1),
250  i18n("Shows the number of tracks of the signal.\n"
251  "You can add or delete tracks via the Edit menu."));
252  sbChannels->setMaximum(m_info.tracks());
253  sbChannels->setMinimum(m_info.tracks());
254  sbChannels->setValue(m_info.tracks());
255  connect(sbChannels, SIGNAL(valueChanged(int)),
256  this, SLOT(tracksChanged(int)));
257  tracksChanged(sbChannels->value());
258 
259  /* length of the signal */
260  lblLength->setText(i18n("Length:"));
261  describeWidget(txtLength, lblLength->text().left(
262  lblLength->text().length() - 1),
263  i18n("Shows the length of the file in samples\n"
264  "and if possible as time."));
265  sample_index_t samples = m_info.length();
266  double rate = m_info.rate();
267  if (!qFuzzyIsNull(rate)) {
268  double ms = static_cast<double>(samples) * 1E3 / rate;
269  txtLength->setText(i18n("%1 (%2 samples)",
270  Kwave::ms2string(ms),
271  Kwave::samples2string(samples)));
272  } else {
273  txtLength->setText(i18n("%1 samples",
274  Kwave::samples2string(samples)));
275  }
276 
277  /* sample format */
278  initInfo(lblSampleFormat, cbSampleFormat, Kwave::INF_SAMPLE_FORMAT);
279  cbSampleFormat->clear();
281  const QList<int> formats = sf.keys();
282  foreach (const int &k, formats) {
283  cbSampleFormat->addItem(
284  sf.description(k, true),
285  QVariant(Kwave::SampleFormat(sf.data(k)).toInt())
286  );
287  }
288 
289  int format = QVariant(m_info.get(Kwave::INF_SAMPLE_FORMAT)).toInt();
290  if (format == 0)
291  format = Kwave::SampleFormat::Signed; // default = signed int
292 
293  cbSampleFormat->setCurrentIndex(cbSampleFormat->findData(format));
294 }
295 
296 //***************************************************************************
298 {
299 
300  /*
301  * mime type @ file info -> available compressions
302  * compression @ file info / available compressions -> selected compression
303  * selected compression -> mime type (edit field)
304  * mime type -> mpeg/ogg/flac mode
305  * mgeg layer -> compression
306  */
307 
308  /* compression */
310  initInfo(lblCompression, cbCompression, Kwave::INF_COMPRESSION);
311 
312  compressionWidget->init(m_info);
313  compressionWidget->setMode(m_info.contains(Kwave::INF_VBR_QUALITY) ?
316 
317  // ABR bitrate settings
318  int abr_bitrate = m_info.contains(Kwave::INF_BITRATE_NOMINAL) ?
320  cfg.readEntry("default_abr_nominal_bitrate", -1);
321  int min_bitrate = m_info.contains(Kwave::INF_BITRATE_LOWER) ?
323  cfg.readEntry("default_abr_lower_bitrate",-1);
324  int max_bitrate = m_info.contains(Kwave::INF_BITRATE_UPPER) ?
326  cfg.readEntry("default_abr_upper_bitrate",-1);
327  compressionWidget->setBitrates(abr_bitrate, min_bitrate, max_bitrate);
328 
329  // VBR base quality
330  int quality = m_info.contains(Kwave::INF_VBR_QUALITY) ?
331  QVariant(m_info.get(Kwave::INF_VBR_QUALITY)).toInt() :
332  cfg.readEntry("default_vbr_quality", -1);
333  compressionWidget->setQuality(quality);
334 
336 
337 // // this is not visible, not implemented yet...
338 // InfoTab->setCurrentPage(5);
339 // QWidget *page = InfoTab->currentPage();
340 // InfoTab->removePage(page);
341 // InfoTab->setCurrentPage(0);
342 // return;
343 }
344 
345 //***************************************************************************
347 {
348  // the whole tab is only enabled in mpeg mode
349  InfoTab->setTabEnabled(2, isMpeg());
350 
351  /* MPEG layer */
352  initInfo(lblMpegLayer, cbMpegLayer, Kwave::INF_MPEG_LAYER);
353  int layer = m_info.get(Kwave::INF_MPEG_LAYER).toInt();
354  if ((layer < 1) || (layer > 3))
355  layer = 3; // default = layer III
356  cbMpegLayer->setCurrentIndex(layer - 1);
357 
358  /* MPEG version */
359  initInfo(lblMpegVersion, cbMpegVersion, Kwave::INF_MPEG_VERSION);
360  int ver = Kwave::toInt(
361  (2.0 * QVariant(m_info.get(Kwave::INF_MPEG_VERSION)).toDouble()));
362  // 1, 2, 2.5 -> 2, 4, 5
363  if ((ver < 1) || (ver > 5)) ver = 4; // default = version 2
364  if (ver > 3) ver++; // 2, 4, 6
365  ver >>= 1; // 1, 2, 3
366  ver--; // 0, 1, 2
367  if ((ver < 0) || (ver > 2)) ver = 1; // default = version 2
368  cbMpegVersion->setCurrentIndex(ver);
369 
370  /* Mode extension */
371  initInfo(lblMpegModeExt, cbMpegModeExt, Kwave::INF_MPEG_MODEEXT);
372  // only in "Joint Stereo" mode, then depends on Layer
373  //
374  // Layer I+II | Layer III
375  // | Intensity stereo MS Stereo
376  //--------------------------------------------------
377  // 0 - bands 4 to 31 | off off -> 4
378  // 1 - bands 8 to 31 | on off -> 5
379  // 2 - bands 12 to 31 | off on -> 6
380  // 3 - bands 16 to 31 | on on -> 7
381 
382  int modeext = -1;
384  modeext = QVariant(m_info.get(Kwave::INF_MPEG_MODEEXT)).toInt();
385  if (modeext < 0) {
386  // find some reasonable default
387  if (m_info.tracks() < 2) {
388  // mono -> -1
389  } else if (layer < 3) {
390  // Layer I or II -> 0
391  modeext = 0;
392  } else {
393  // Layer III -> 7
394  modeext = 7;
395  }
396  }
397 
398  if ((modeext >= 0) && (modeext <= 3)) {
399  cbMpegModeExt->setEnabled(true);
400  cbMpegModeExt->setCurrentIndex(modeext);
401  chkMpegIntensityStereo->setEnabled(false);
402  chkMpegMSStereo->setEnabled(false);
403  } else if ((modeext >= 4) && (modeext <= 7)) {
404  cbMpegModeExt->setEnabled(false);
405  cbMpegModeExt->setCurrentIndex(-1);
406  chkMpegIntensityStereo->setEnabled(true);
407  chkMpegIntensityStereo->setChecked(modeext & 0x01);
408  chkMpegMSStereo->setEnabled(true);
409  chkMpegMSStereo->setChecked(modeext & 0x02);
410  } else {
411  cbMpegModeExt->setEnabled(false);
412  cbMpegModeExt->setCurrentIndex(-1);
413  chkMpegIntensityStereo->setEnabled(false);
414  chkMpegMSStereo->setEnabled(false);
415  }
416 
417  /* Emphasis */
418  initInfo(lblMpegEmphasis, cbMpegEmphasis, Kwave::INF_MPEG_EMPHASIS);
419  int emphasis = QVariant(m_info.get(Kwave::INF_MPEG_EMPHASIS)).toInt();
420  switch (emphasis) {
421  case 0: cbMpegEmphasis->setCurrentIndex(0); break;
422  case 1: cbMpegEmphasis->setCurrentIndex(1); break;
423  case 3: cbMpegEmphasis->setCurrentIndex(2); break;
424  default: cbMpegEmphasis->setEnabled(false); break;
425  }
426 
427  /* Copyrighted */
428  initInfo(lblMpegCopyrighted, chkMpegCopyrighted, Kwave::INF_COPYRIGHTED);
429  bool copyrighted = QVariant(m_info.get(Kwave::INF_COPYRIGHTED)).toBool();
430  chkMpegCopyrighted->setChecked(copyrighted);
431  mpegCopyrightedChanged(copyrighted);
432 
433  /* Original */
434  initInfo(lblMpegOriginal, chkMpegOriginal, Kwave::INF_ORIGINAL);
435  bool original = QVariant(m_info.get(Kwave::INF_ORIGINAL)).toBool();
436  chkMpegOriginal->setChecked(original);
437  mpegOriginalChanged(original);
438 
440 }
441 
442 //***************************************************************************
444 {
445  /* name, subject, version, genre, title, author, organization,
446  copyright, license */
447  initInfoText(lblName, edName, Kwave::INF_NAME);
448  initInfoText(lblSubject, edSubject, Kwave::INF_SUBJECT);
449  initInfoText(lblVersion, edVersion, Kwave::INF_VERSION);
450 
451  // genre type
452  cbGenre->addItems(Kwave::GenreType::allTypes());
453  QString genre = m_info.get(Kwave::INF_GENRE).toString();
454  int genre_id = Kwave::GenreType::id(genre);
455  if (genre_id >= 0) {
456  // well known genre type
457  genre = Kwave::GenreType::name(genre_id, true);
458  } else {
459  // user defined genre type
460  cbGenre->addItem(genre);
461  }
462  initInfo(lblGenre, cbGenre, Kwave::INF_GENRE);
463  cbGenre->setCurrentIndex(cbGenre->findText(genre));
464 
465  /* date widget */
466  initInfo(lblDate, dateEdit, Kwave::INF_CREATION_DATE);
467  QDate date;
468  QString date_str = QVariant(m_info.get(Kwave::INF_CREATION_DATE)).toString();
470  if (date_str.length())
471  date = QDate::fromString(date_str, Qt::ISODate);
472  }
473  if (!date.isValid()) {
474  // fall back to "year only"
475  int year = date_str.toInt();
476  if ((year > 0) && (year <= 9999))
477  date = QDate(year, 1, 1);
478  }
479  if (!date.isValid()) {
480  // fall back to "now"
481  date = QDate::currentDate();
482  }
483 
484  dateEdit->setDate(date);
485  connect(btSelectDate, SIGNAL(clicked()), this, SLOT(selectDate()));
486  connect(btSelectDateNow, SIGNAL(clicked()), this, SLOT(setDateNow()));
487 }
488 
489 //***************************************************************************
491 {
492  /* source, source form */
493  initInfoText(lblSource, edSource, Kwave::INF_SOURCE);
494  initInfoText(lblSourceForm, edSourceForm, Kwave::INF_SOURCE_FORM);
495 
496  /* Album, CD and track */
497  initInfoText(lblAlbum, edAlbum, Kwave::INF_ALBUM);
498  initInfo(lblCD, sbCD, Kwave::INF_CD);
499  int cd = (m_info.contains(Kwave::INF_CD)) ?
500  QVariant(m_info.get(Kwave::INF_CD)).toInt() : 0;
501  sbCD->setValue(cd);
502 
503  initInfo(Q_NULLPTR, sbCDs, Kwave::INF_CDS);
504  int cds = (m_info.contains(Kwave::INF_CDS)) ?
505  QVariant(m_info.get(Kwave::INF_CDS)).toInt() : 0;
506  sbCDs->setValue(cds);
507 
508  initInfo(lblTrack, sbTrack, Kwave::INF_TRACK);
509  int track = (m_info.contains(Kwave::INF_TRACK)) ?
510  QVariant(m_info.get(Kwave::INF_TRACK)).toInt() : 0;
511  sbTrack->setValue(track);
512 
513  initInfo(Q_NULLPTR, sbTracks, Kwave::INF_TRACKS);
514  int tracks = (m_info.contains(Kwave::INF_TRACKS)) ?
515  QVariant(m_info.get(Kwave::INF_TRACKS)).toInt() : 0;
516  sbTracks->setValue(tracks);
517 
518  /* software, engineer, technician */
519  initInfoText(lblSoftware, edSoftware, Kwave::INF_SOFTWARE);
520  initInfoText(lblEngineer, edEngineer, Kwave::INF_ENGINEER);
521  initInfoText(lblTechnican, edTechnican, Kwave::INF_TECHNICAN);
522 
523 }
524 
525 //***************************************************************************
527 {
528  /* author organization, copyright, license, ISRC */
529  initInfoText(lblAuthor, edAuthor, Kwave::INF_AUTHOR);
530  initInfoText(lblOrganization, edOrganization, Kwave::INF_ORGANIZATION);
531  initInfoText(lblCopyright, edCopyright, Kwave::INF_COPYRIGHT);
532  initInfoText(lblLicense, edLicense, Kwave::INF_LICENSE);
533  initInfoText(lblISRC, edISRC, Kwave::INF_ISRC);
534 
535  /* product, archival, contact */
536  initInfoText(lblProduct, edProduct, Kwave::INF_PRODUCT);
537  initInfoText(lblArchival, edArchival, Kwave::INF_ARCHIVAL);
538  initInfoText(lblContact, edContact, Kwave::INF_CONTACT);
539 }
540 
541 //***************************************************************************
543 {
544  /* commissioned */
545  initInfoText(lblCommissioned, edCommissioned, Kwave::INF_COMMISSIONED);
546 
547  /* list of keywords */
548  lblKeywords->setText(i18n(m_info.name(Kwave::INF_KEYWORDS).toLatin1()));
549  lstKeywords->setWhatsThis(_("<b>") +
550  i18n(m_info.name(Kwave::INF_KEYWORDS).toLatin1()) +
551  _("</b><br>") + i18n(m_info.description(Kwave::INF_KEYWORDS).toLatin1()));
553  QString keywords = QVariant(m_info.get(Kwave::INF_KEYWORDS)).toString();
554  lstKeywords->setKeywords(keywords.split(_(";")));
555  }
556  connect(lstKeywords, SIGNAL(autoGenerate()),
557  this, SLOT(autoGenerateKeywords()));
558 
559 }
560 
561 //***************************************************************************
563 {
564  QDate date(dateEdit->date());
565  Kwave::SelectDateDialog date_dialog(this, date);
566  if (date_dialog.exec() == QDialog::Accepted) {
567  date = date_dialog.date();
568  dateEdit->setDate(date);
569  }
570 }
571 
572 //***************************************************************************
574 {
575  dateEdit->setDate(QDate::currentDate());
576 }
577 
578 //***************************************************************************
580 {
581  switch (tracks) {
582  case 1:
583  lblChannelsVerbose->setText(i18n("(Mono)"));
584  break;
585  case 2:
586  lblChannelsVerbose->setText(i18n("(Stereo)"));
587  break;
588  case 4:
589  lblChannelsVerbose->setText(i18n("(Quadro)"));
590  break;
591  default:
592  lblChannelsVerbose->setText(_(""));
593  break;
594  }
595 }
596 
597 //***************************************************************************
599 {
600  cbCompression->blockSignals(true);
601 
602  QList<Kwave::Compression::Type> supported_compressions;
603  QString mime_type = m_info.get(Kwave::INF_MIMETYPE).toString();
604 
605  // switch by mime type:
606  if (mime_type.length()) {
607  // mime type is present -> offer only matching compressions
608  Kwave::Encoder *encoder = Kwave::CodecManager::encoder(mime_type);
609  if (encoder) supported_compressions = encoder->compressionTypes();
610  } else {
611  // no mime type -> allow all mimetypes suitable for encoding
612  supported_compressions.append(Kwave::Compression::NONE);
613 
614  QStringList mime_types = Kwave::CodecManager::encodingMimeTypes();
615  foreach (QString m, mime_types) {
617  if (!encoder) continue;
618  QList<Kwave::Compression::Type> comps = encoder->compressionTypes();
619  foreach (Kwave::Compression::Type c, comps)
620  if (!supported_compressions.contains(c))
621  supported_compressions.append(c);
622  }
623  }
624 
625  // if nothing is supported, then use only "none"
626  if (supported_compressions.isEmpty())
627  supported_compressions.append(Kwave::Compression::NONE);
628 
629  // add supported compressions to the combo box
630  cbCompression->clear();
631  foreach (Kwave::Compression::Type c, supported_compressions) {
632  Kwave::Compression compression(c);
633  cbCompression->addItem(compression.name(), compression.toInt());
634  }
635 
636  cbCompression->blockSignals(false);
637 
638  // update the selection of the compression type
639  int c = QVariant(m_info.get(Kwave::INF_COMPRESSION)).toInt();
640  int new_index = cbCompression->findData(c);
641 
642  // take the highest supported compression if changed to "invalid"
643  // (assuming that the last entry in the list is the best one)
644  if (new_index < 0)
645  new_index = cbCompression->count() - 1;
646 
647  cbCompression->setCurrentIndex(new_index);
648 }
649 
650 //***************************************************************************
652 {
653  if (!cbCompression || !edFileFormat) return;
654 
655  Kwave::Compression::Type compression =
656  Kwave::Compression::fromInt(cbCompression->itemData(
657  cbCompression->currentIndex()).toInt()
658  );
659 
660  const Kwave::Compression comp(compression);
661  const QString preferred_mime_type = comp.preferredMimeType();
662 
663  // selected compression -> mime type (edit field)
664 
665  if (preferred_mime_type.length()) {
666  // if a compression implies a specific mime type -> select it
667  edFileFormat->setText(preferred_mime_type);
668  } else {
669  // if mime type is given by file info -> keep it
670  // otherwise select one by evaluating the compression <-> encoder
671  QString file_mime_type = m_info.get(Kwave::INF_MIMETYPE).toString();
672  if (!file_mime_type.length()) {
673  // determine mime type from a matching encoder.
674  // This should work for compression types that are supported by
675  // only one single encoder which also supports only one single
676  // mime type
677  QStringList mime_types = Kwave::CodecManager::encodingMimeTypes();
678  foreach (const QString &mime_type, mime_types) {
679  Kwave::Encoder *encoder =
680  Kwave::CodecManager::encoder(mime_type);
681  if (!encoder) continue;
682  QList<Kwave::Compression::Type> comps =
683  encoder->compressionTypes();
684  if (comps.contains(compression)) {
685  edFileFormat->setText(mime_type);
686  break;
687  }
688  }
689  }
690  }
691 
692  // if mpeg mode selected -> select mpeg layer
693  int mpeg_layer = -1;
694  switch (compression)
695  {
696  case Kwave::Compression::MPEG_LAYER_I: mpeg_layer = 1; break;
697  case Kwave::Compression::MPEG_LAYER_II: mpeg_layer = 2; break;
698  case Kwave::Compression::MPEG_LAYER_III: mpeg_layer = 3; break;
699  default: break;
700  }
701 
702  InfoTab->setTabEnabled(2, isMpeg());
703  if ((mpeg_layer > 0) && (cbMpegLayer->currentIndex() != (mpeg_layer - 1)))
704  cbMpegLayer->setCurrentIndex(mpeg_layer - 1);
705 
706  // enable/disable ABR/VBR controls, depending on mime type
707  const bool abr = comp.hasABR();
708  const bool lower = abr && m_info.contains(Kwave::INF_BITRATE_LOWER);
709  const bool upper = abr && m_info.contains(Kwave::INF_BITRATE_UPPER);
710  const bool vbr = comp.hasVBR();
711  compressionWidget->enableABR(abr, lower, upper);
712  compressionWidget->enableVBR(vbr);
713  cbSampleFormat->setEnabled(!comp.sampleFormats().isEmpty());
714 
715  if (abr && !vbr)
716  compressionWidget->setMode(Kwave::CompressionWidget::ABR_MODE);
717  else if (!abr && vbr)
718  compressionWidget->setMode(Kwave::CompressionWidget::VBR_MODE);
719 
720 }
721 
722 //***************************************************************************
724 {
725  int compression = cbCompression->itemData(
726  cbCompression->currentIndex()).toInt();
727  switch (compression)
728  {
732  return true;
733  default:
734  return false;
735  }
736 }
737 
738 //***************************************************************************
740 {
741  if (!cbMpegLayer || !isMpeg()) return;
742 
743  int layer = cbMpegLayer->currentIndex() + 1;
744  int compression = Kwave::Compression::NONE;
745  switch (layer) {
746  case 1:
747  compression = Kwave::Compression::MPEG_LAYER_I;
748  break;
749  case 2:
750  compression = Kwave::Compression::MPEG_LAYER_II;
751  break;
752  case 3:
754  break;
755  }
756 
757  if (compression != Kwave::Compression::NONE) {
758  int index = cbCompression->findData(compression);
759  if (index >= 0) cbCompression->setCurrentIndex(index);
760  }
761 
762  /* Mode extension */
763  // only in "Joint Stereo" mode, then depends on Layer
764  //
765  // Layer I+II | Layer III
766  // | Intensity stereo MS Stereo
767  //--------------------------------------------------
768  // 0 - bands 4 to 31 | off off -> 4
769  // 1 - bands 8 to 31 | on off -> 5
770  // 2 - bands 12 to 31 | off on -> 6
771  // 3 - bands 16 to 31 | on on -> 7
772  if (m_info.tracks() < 2) {
773  // mono
774  cbMpegModeExt->setEnabled(false);
775  cbMpegModeExt->setCurrentIndex(-1);
776 
777  chkMpegIntensityStereo->setEnabled(false);
778  chkMpegIntensityStereo->setChecked(false);
779  chkMpegMSStereo->setEnabled(false);
780  chkMpegMSStereo->setChecked(false);
781  } else if (cbMpegModeExt->isEnabled() && (layer >= 3)) {
782  // switched from layer I or II to layer III
783  cbMpegModeExt->setEnabled(false);
784 
785  int modeext = QVariant(m_info.get(Kwave::INF_MPEG_MODEEXT)).toInt();
786  if ((modeext < 4) || (modeext > 7)) {
787  modeext = 7; // default to MS stereo + Intensity stereo
788  chkMpegIntensityStereo->setChecked(modeext & 0x01);
789  chkMpegMSStereo->setChecked(modeext & 0x02);
790  }
791 
792  chkMpegIntensityStereo->setEnabled(true);
793  chkMpegMSStereo->setEnabled(true);
794  } else if (!cbMpegModeExt->isEnabled() && (layer <= 2)) {
795  // switched from layer III to layer I or II
796  int modeext = (m_info.contains(Kwave::INF_MPEG_MODEEXT)) ?
797  QVariant(m_info.get(Kwave::INF_MPEG_MODEEXT)).toInt() : -1;
798  if ((modeext < 0) || (modeext > 3)) {
799  modeext = 0; // default bands 4 to 31
800  cbMpegModeExt->setCurrentIndex(modeext);
801  }
802  cbMpegModeExt->setEnabled(true);
803 
804  chkMpegIntensityStereo->setEnabled(false);
805  chkMpegMSStereo->setEnabled(false);
806  }
807 }
808 
809 //***************************************************************************
811 {
812  chkMpegCopyrighted->setText((checked) ? i18n("Yes") : i18n("No"));
813 }
814 
815 //***************************************************************************
817 {
818  chkMpegOriginal->setText((checked) ? i18n("Yes") : i18n("No"));
819 }
820 
821 //***************************************************************************
823 {
824  // start with the current list
825  QStringList list = lstKeywords->keywords();
826 
827  // name, subject, version, genre, author, organization,
828  // copyright, license, source, source form, album,
829  // product, archival, contact, software, technician, engineer,
830  // commissioned, ISRC
831  const QString space = _(" ");
832  list += edName->text().split(space);
833  list += edSubject->text().split(space);
834  list += edVersion->text().split(space);
835  list += cbGenre->currentText();
836  list += edAuthor->text().split(space);
837  list += edOrganization->text().split(space);
838  list += edCopyright->text().split(space);
839  list += edLicense->text().split(space);
840  list += edSource->text().split(space);
841  list += edSourceForm->text().split(space);
842  list += edAlbum->text().split(space);
843  list += edProduct->text().split(space);
844  list += edArchival->text().split(space);
845  list += edContact->text().split(space);
846  list += edSoftware->text().split(space);
847  list += edTechnican->text().split(space);
848  list += edEngineer->text().split(space);
849  list += edCommissioned->text().split(space);
850  list += edISRC->text().split(space);
851 
852  // filter out all useless stuff
853  QMutableStringListIterator it(list);
854  while (it.hasNext()) {
855  QString token = it.next();
856 
857  // remove punktation characters like '.', ',', '!' from start and end
858  while (token.length()) {
859  QString old_value = token;
860 
861  QChar c = token[token.length()-1];
862  if (c.isPunct() || c.isMark() || c.isSpace())
863  token = token.left(token.length()-1);
864  if (!token.length()) break;
865 
866  c = token[0];
867  if (c.isPunct() || c.isMark() || c.isSpace())
868  token = token.right(token.length()-1);
869 
870  if (token == old_value) break; // no (more) change(s)
871  }
872 
873  // remove empty entries
874  if (!token.length()) {
875  it.remove();
876  continue;
877  }
878 
879  // remove simple numbers and too short stuff
880  bool ok = false;
881  token.toInt(&ok);
882  if ((ok) || (token.length() < 3)) {
883  it.remove(); // number or less than 3 characters -> remove
884  continue;
885  }
886 
887  // remove duplicates that differ in case
888  bool is_duplicate = false;
889  QStringListIterator it2(list);
890  while (it2.hasNext()) {
891  QString token2 = it2.next();
892  if (list.indexOf(token) == list.lastIndexOf(token2)) continue;
893  if (token2.compare(token, Qt::CaseInsensitive) == 0) {
894  // take the one with less uppercase characters
895  unsigned int upper1 = 0;
896  unsigned int upper2 = 0;
897  for (int i=0; i < token.length(); ++i)
898  if (token[i].category() == QChar::Letter_Uppercase)
899  upper1++;
900  for (int i=0; i < token2.length(); ++i)
901  if (token2[i].category() == QChar::Letter_Uppercase)
902  upper2++;
903  if (upper2 < upper1) {
904  is_duplicate = true;
905  break;
906  }
907  }
908  }
909  if (is_duplicate) {
910  it.remove();
911  continue;
912  }
913 
914  it.setValue(token);
915  }
916  // other stuff like empty strings and duplicates are handled in
917  // the list itself, we don't need to take care of that here :)
918 
919  lstKeywords->setKeywords(list);
920 }
921 
922 //***************************************************************************
924  QString value)
925 {
926  value = value.simplified();
927  if (!m_info.contains(property) && !value.length()) return;
928 
929  if (!value.length()) {
930  m_info.set(property, QVariant());
931  } else {
932  m_info.set(property, value);
933  }
934 }
935 
936 //***************************************************************************
938 {
939  // save defaults for next time...
940  KConfigGroup cfg = KSharedConfig::openConfig()->group(CONFIG_DEFAULT_SECTION);
941  cfg.sync();
942  {
943  int nominal, upper, lower;
944  compressionWidget->getABRrates(nominal, lower, upper);
945  cfg.writeEntry("default_abr_nominal_bitrate", nominal);
946  cfg.writeEntry("default_abr_upper_bitrate", upper);
947  cfg.writeEntry("default_abr_lower_bitrate", lower);
948 
949  int quality = compressionWidget->baseQuality();
950  cfg.writeEntry("default_vbr_quality", quality);
951  }
952  cfg.sync();
953 
954  qDebug("FileInfoDialog::accept()");
955  m_info.dump();
956 
957  /* mime type */
958  m_info.set(Kwave::INF_MIMETYPE, edFileFormat->text());
959 
960  /* bits per sample */
961  m_info.setBits(sbResolution->value());
962 
963  /* sample rate */
964  m_info.setRate(cbSampleRate->currentText().toDouble());
965 
966  /* sample format */
967  Kwave::SampleFormat::Map sample_formats;
968  int sample_format =
969  cbSampleFormat->itemData(cbSampleFormat->currentIndex()).toInt();
970  m_info.set(Kwave::INF_SAMPLE_FORMAT, QVariant(sample_format));
971 
972  /* compression */
974  cbCompression->itemData(cbCompression->currentIndex()).toInt()
975  );
977  (compression != Kwave::Compression::NONE) ?
978  QVariant(Kwave::Compression(compression).toInt()) :
979  QVariant());
980 
981  /* MPEG layer */
982  if (isMpeg()) {
983  int layer = cbMpegLayer->currentIndex() + 1;
985 
986  // only in "Joint Stereo" mode, then depends on Layer
987  //
988  // Layer I+II | Layer III
989  // | Intensity stereo MS Stereo
990  //--------------------------------------------------
991  // 0 - bands 4 to 31 | off off -> 4
992  // 1 - bands 8 to 31 | on off -> 5
993  // 2 - bands 12 to 31 | off on -> 6
994  // 3 - bands 16 to 31 | on on -> 7
995  if (m_info.tracks() < 2) {
996  // mono -> no mode ext.
997  m_info.set(Kwave::INF_MPEG_MODEEXT, QVariant());
998  } else if (cbMpegModeExt->isEnabled()) {
999  // Layer I+II
1000  int modeext = cbMpegModeExt->currentIndex();
1002  } else {
1003  // Layer III
1004  int modeext = 4;
1005  if (chkMpegIntensityStereo->isChecked()) modeext |= 1;
1006  if (chkMpegMSStereo->isChecked()) modeext |= 2;
1008  }
1009 
1010  int emphasis = 0;;
1011  switch (cbMpegEmphasis->currentIndex()) {
1012  case 1: emphasis = 1; break; /* 1 -> 1 */
1013  case 2: emphasis = 3; break; /* 2 -> 3 */
1014  case 0: /* FALLTHROUGH */
1015  default: emphasis = 0; break; /* 0 -> 0 */
1016  }
1017  m_info.set(Kwave::INF_MPEG_EMPHASIS, emphasis);
1018 
1019  bool copyrighted = chkMpegCopyrighted->isChecked();
1020  m_info.set(Kwave::INF_COPYRIGHTED, copyrighted);
1021 
1022  bool original = chkMpegOriginal->isChecked();
1023  m_info.set(Kwave::INF_ORIGINAL, original);
1024  } else {
1025  m_info.set(Kwave::INF_MPEG_MODEEXT, QVariant());
1026  m_info.set(Kwave::INF_MPEG_EMPHASIS, QVariant());
1027  m_info.set(Kwave::INF_COPYRIGHTED, QVariant());
1028  m_info.set(Kwave::INF_ORIGINAL, QVariant());
1029  }
1030 
1031  /* bitrate in Ogg/Vorbis or MPEG mode */
1032  const Kwave::Compression comp(compression);
1033  if (comp.hasABR() || comp.hasVBR()) {
1034  Kwave::CompressionWidget::Mode mode = compressionWidget->mode();
1035  QVariant del;
1036 
1037  switch (mode) {
1039  int nominal, upper, lower;
1040  compressionWidget->getABRrates(nominal, lower, upper);
1041  bool use_lowest = compressionWidget->lowestEnabled();
1042  bool use_highest = compressionWidget->highestEnabled();
1043 
1044  m_info.set(Kwave::INF_BITRATE_NOMINAL, QVariant(nominal));
1046  (use_lowest) ? QVariant(lower) : del);
1048  (use_highest) ? QVariant(upper) : del);
1050  break;
1051  }
1053  int quality = compressionWidget->baseQuality();
1054 
1058  m_info.set(Kwave::INF_VBR_QUALITY, QVariant(quality));
1059  break;
1060  }
1061  }
1062  }
1063 
1064  /* name, subject, version, genre, title, author, organization,
1065  copyright */
1066  acceptEdit(Kwave::INF_NAME, edName->text());
1067  acceptEdit(Kwave::INF_SUBJECT, edSubject->text());
1068  acceptEdit(Kwave::INF_VERSION, edVersion->text());
1069  acceptEdit(Kwave::INF_GENRE, cbGenre->currentText());
1070  acceptEdit(Kwave::INF_AUTHOR, edAuthor->text());
1071  acceptEdit(Kwave::INF_ORGANIZATION, edOrganization->text());
1072  acceptEdit(Kwave::INF_COPYRIGHT, edCopyright->text());
1073  acceptEdit(Kwave::INF_LICENSE, edLicense->text());
1074 
1075  /* date */
1076  QDate date = dateEdit->date();
1077  if ( (date != QDate::currentDate()) ||
1079  {
1080  m_info.set(Kwave::INF_CREATION_DATE, QVariant(date).toString());
1081  }
1082 
1083  /* source, source form, album */
1084  acceptEdit(Kwave::INF_SOURCE, edSource->text());
1085  acceptEdit(Kwave::INF_SOURCE_FORM, edSourceForm->text());
1086  acceptEdit(Kwave::INF_ALBUM, edAlbum->text());
1087 
1088  /* CD and track */
1089  int cd = sbCD->value();
1090  int cds = sbCDs->value();
1091  int track = sbTrack->value();
1092  int tracks = sbTracks->value();
1093  m_info.set(Kwave::INF_CD, (cd != 0) ? QVariant(cd) : QVariant());
1094  m_info.set(Kwave::INF_CDS, (cds != 0) ? QVariant(cds) : QVariant());
1095  m_info.set(Kwave::INF_TRACK, (track != 0) ? QVariant(track) : QVariant());
1096  m_info.set(Kwave::INF_TRACKS, (tracks != 0) ? QVariant(tracks) : QVariant());
1097 
1098  /* product, archival, contact */
1099  acceptEdit(Kwave::INF_PRODUCT, edProduct->text());
1100  acceptEdit(Kwave::INF_ARCHIVAL, edArchival->text());
1101  acceptEdit(Kwave::INF_CONTACT, edContact->text());
1102 
1103  /* software, engineer, technician, commissioned, ISRC, keywords */
1104  acceptEdit(Kwave::INF_SOFTWARE, edSoftware->text());
1105  acceptEdit(Kwave::INF_ENGINEER, edEngineer->text());
1106  acceptEdit(Kwave::INF_TECHNICAN, edTechnican->text());
1107  acceptEdit(Kwave::INF_COMMISSIONED,edCommissioned->text());
1108 // acceptEdit(Kwave::INF_ISRC, edISRC->text()); <- READ-ONLY
1109 
1110  // list of keywords
1112  lstKeywords->keywords().join(_("; ")));
1113 
1114  qDebug("FileInfoDialog::accept() [done]");
1115  m_info.dump();
1116 
1117  QDialog::accept();
1118 }
1119 
1120 //***************************************************************************
1122 {
1123  KHelpClient::invokeHelp(_("fileinfo"));
1124 }
1125 
1126 //***************************************************************************
1127 //***************************************************************************
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
QString preferredMimeType() const
Definition: Compression.cpp:52
static QString name(int id, bool localized)
Definition: GenreType.cpp:34
FileInfoDialog(QWidget *parent, Kwave::FileInfo &info)
double rate() const
Definition: FileInfo.cpp:415
void acceptEdit(Kwave::FileProperty property, QString value)
QString Q_DECL_EXPORT ms2string(double ms, int precision=6)
Definition: Utils.cpp:66
QString Q_DECL_EXPORT samples2string(sample_index_t samples)
Definition: Utils.cpp:98
QString description(IDX type, bool localized) const
Definition: TypesMap.h:128
DATA data(IDX type) const
Definition: TypesMap.h:110
bool hasABR() const
Definition: Compression.cpp:66
QString name(FileProperty key) const
Definition: FileInfo.h:227
void mpegOriginalChanged(bool checked)
QString name() const
Definition: Compression.cpp:45
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
void describeWidget(QWidget *widget, const QString &name, const QString &description)
static Kwave::Compression::Type fromInt(int i)
Definition: Compression.cpp:78
quint64 sample_index_t
Definition: Sample.h:28
virtual ~FileInfoDialog() Q_DECL_OVERRIDE
virtual const QList< Kwave::Compression::Type > compressionTypes()
Definition: CodecBase.cpp:134
static QString mimeTypeOf(const QUrl &url)
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
void set(FileProperty key, const QVariant &value)
Definition: FileInfo.cpp:363
static bool cmp(const Kwave::Curve::Point &a, const Kwave::Curve::Point &b)
Definition: Curve.cpp:245
void mpegCopyrightedChanged(bool checked)
virtual bool supports(const QMimeType &mimetype)
Definition: CodecBase.cpp:100
void setRate(double rate)
Definition: FileInfo.cpp:424
const char name[16]
Definition: memcpy.c:510
virtual void accept() Q_DECL_OVERRIDE
QList< IDX > keys() const
Definition: TypesMap.h:150
QString description(FileProperty key) const
Definition: FileInfo.h:234
sample_index_t length() const
Definition: FileInfo.cpp:400
#define CONFIG_DEFAULT_SECTION
int toInt(T x)
Definition: Utils.h:127
bool hasVBR() const
Definition: Compression.cpp:72
static int id(const QString &name)
Definition: GenreType.cpp:63
static QStringList encodingMimeTypes()
unsigned int tracks() const
Definition: FileInfo.cpp:445
void setBits(unsigned int bits)
Definition: FileInfo.cpp:439
static Kwave::Encoder * encoder(const QString &mimetype_name)
Kwave::FileInfo m_info
#define _(m)
Definition: memcpy.c:66
#define DBG(qs)
Definition: String.h:55
static QStringList allTypes()
Definition: GenreType.cpp:78
unsigned int bits() const
Definition: FileInfo.cpp:430
void tracksChanged(int tracks)
void initInfoText(QLabel *label, QLineEdit *edit, Kwave::FileProperty property)
FileProperty
Definition: FileInfo.h:45
void setupCompressionTab(KConfigGroup &cfg)
void initInfo(QLabel *label, QWidget *widget, Kwave::FileProperty property)
#define UTF8(qs)
Definition: String.h:48
int toInt() const
Definition: Compression.h:122
virtual void dump() const Q_DECL_OVERRIDE
Definition: FileInfo.cpp:460