kwave  18.07.70
K3BExportPlugin.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  * K3BExportPlugin.cpp - export of K3b project files
3  * -------------------
4  * begin : Thu Apr 13 2017
5  * copyright : (C) 2017 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 <errno.h>
21 
22 #include <QBuffer>
23 #include <QByteArray>
24 #include <QDir>
25 #include <QDomDocument>
26 #include <QDomElement>
27 #include <QFileInfo>
28 #include <QIODevice>
29 #include <QMap>
30 #include <QProcess>
31 #include <QRegExp>
32 #include <QTextStream>
33 
34 #include <KLocalizedString> // for the i18n macro
35 #include <KZip>
36 
37 #include "libkwave/CodecManager.h"
38 #include "libkwave/Encoder.h"
39 #include "libkwave/FileInfo.h"
40 #include "libkwave/Label.h"
41 #include "libkwave/LabelList.h"
42 #include "libkwave/Logger.h"
43 #include "libkwave/MessageBox.h"
44 #include "libkwave/MetaDataList.h"
45 #include "libkwave/Parser.h"
46 #include "libkwave/Plugin.h"
47 #include "libkwave/PluginManager.h"
48 #include "libkwave/SignalManager.h"
49 #include "libkwave/String.h"
50 #include "libkwave/Utils.h"
51 
52 #include "K3BExportDialog.h"
53 #include "K3BExportPlugin.h"
54 
55 KWAVE_PLUGIN(export_k3b, K3BExportPlugin)
56 
57 
58 #define K3B_PROJECT_MIME_TYPE "application/x-k3b"
59 
61 #define K3B_FILE_SUFFIX _("*.k3b")
62 
64 #define OUTFILE_DIGITS 4
65 
67 #define OUTFILE_PATTERN (_("[%0") + _("%1nr]").arg(OUTFILE_DIGITS))
68 
70 #define OUTFILE_SUFFIX _(".wav")
71 
72 //***************************************************************************
74  const QVariantList &args)
75  :Kwave::Plugin(parent, args),
76  m_url(),
77  m_pattern(),
78  m_selection_only(false),
79  m_export_location(EXPORT_TO_SUB_DIR),
80  m_overwrite_policy(USE_NEW_FILE_NAMES),
81  m_block_info()
82 {
83 }
84 
85 //***************************************************************************
87 {
88 }
89 
90 //***************************************************************************
92 {
93  bool ok;
94  QString param;
95 
96  // evaluate the parameter list
97  if (params.count() != 5)
98  return -EINVAL;
99 
100  // the selected URL
101  m_url = QUrl::fromUserInput(Kwave::Parser::unescape(params[0]));
102  if (!m_url.isValid()) return -EINVAL;
103 
104  // label pattern
105  m_pattern = Kwave::Parser::unescape(params[1]);
106 
107  // selection only
108  param = params[2];
109  int v = param.toInt(&ok);
110  Q_ASSERT(ok);
111  if (!ok) return -EINVAL;
112  m_selection_only = (v != 0);
113 
114  // export location
115  param = params[3];
116  int where = param.toInt(&ok);
117  Q_ASSERT(ok);
118  if (!ok) return -EINVAL;
119  if ((where != EXPORT_TO_SAME_DIR) &&
120  (where != EXPORT_TO_SUB_DIR)) return -EINVAL;
121  m_export_location = static_cast<export_location_t>(where);
122 
123  // overwrite policy
124  param = params[4];
125  int overwrite = param.toInt(&ok);
126  Q_ASSERT(ok);
127  if (!ok) return -EINVAL;
128  if ((overwrite != OVERWRITE_EXISTING_FILES) &&
129  (overwrite != USE_NEW_FILE_NAMES)) return -EINVAL;
130  m_overwrite_policy = static_cast<overwrite_policy_t>(overwrite);
131 
132  return 0;
133 }
134 
135 //***************************************************************************
137  sample_index_t selection_left,
138  sample_index_t selection_right)
139 {
140  sample_index_t block_start;
141  sample_index_t block_end = 0;
142 
143  Kwave::LabelList labels(signalManager().metaData());
144  Kwave::LabelListIterator it(labels);
145  Kwave::Label label = (it.hasNext()) ? it.next() : Kwave::Label();
146 
147  // get the title of the whole file, in case that a block does not have
148  // an own title
149  FileInfo info(signalManager().metaData());
150  QString file_title = info.get(INF_NAME).toString();
151  QString file_artist = info.get(INF_AUTHOR).toString();
152 
153  // fallback: if there is no INF_NAME either, fall back to the file
154  // name as last resort
155  if (!file_title.length()) file_title = base;
156 
157  m_block_info.clear();
158  QString prev_title = file_title;
159  for (unsigned int index = 1; ; ++index) {
160  block_start = block_end;
161  block_end = (label.isNull()) ? signalLength() : label.pos();
162 
163  QString block_title = (!label.isNull() && label.name().length()) ?
164  label.name() : prev_title;
165 
166  if ((block_end > selection_left) && (block_start <= selection_right)) {
167  BlockInfo block;
168 
169  // init and set reasonable defaults
170  block.m_index = index;
171  block.m_filename = QString();
172  block.m_start = block_start;
173  block.m_length = block_end - block_start;
174  block.m_title = prev_title;
175  block.m_artist = file_artist;
176 
177  // detect title and artist
178  detectBlockMetaData(prev_title, m_pattern, block);
179  m_block_info.append(block);
180 
181  prev_title = block_title;
182 
183 // qDebug("#%d [%llu...%llu]", index, block_start, block_end);
184 // qDebug(" title = '%s'", DBG(block.m_title));
185 // qDebug(" artist = '%s'", DBG(block.m_artist));
186  } else {
187  prev_title = block_title;
188  }
189 
190  if (label.isNull()) break;
191  label = (it.hasNext()) ? it.next() : Kwave::Label();
192  }
193 }
194 
195 //***************************************************************************
196 QString Kwave::K3BExportPlugin::createFileName(const QString &pattern,
197  unsigned int index)
198 {
199  QString name = pattern;
200  QString num = _("%1").arg(index, OUTFILE_DIGITS, 10, QLatin1Char('0'));
201  name.replace(OUTFILE_PATTERN, num);
202  name += OUTFILE_SUFFIX;
203  return name;
204 }
205 
206 //***************************************************************************
208  const QString &text,
209  const QString &pattern,
211 )
212 {
213  if (!pattern.length()) {
214  // auto detect -> try all known patterns
215  foreach (const QString &p, knownPatterns())
216  if (detectBlockMetaData(text, p, block))
217  return true;
218  return false;
219  }
220 
221  // list of placeholders and pointers to the resulting strings
222  QMap <QString, QString *> map_patterns;
223  map_patterns.insert(_("[%artist]"), &block.m_artist);
224  map_patterns.insert(_("[%title]"), &block.m_title);
225 
226  // try to find the placeholders within the pattern
227  // NOTE: we use a map because it will automatically be sorted (by pos)
228  QString pattern_esc = Kwave::Parser::escape(pattern);
229  QMap <int, QString *> map_result;
230  foreach (const QString &placeholder, map_patterns.keys()) {
231  QString placeholder_esc;
232  placeholder_esc = Kwave::Parser::escape(placeholder);
233  if (pattern_esc.contains(placeholder_esc)) {
234  const QString rx_string = _("(.+)");
235  int pos = pattern.indexOf(placeholder);
236  pattern_esc.replace(placeholder_esc, rx_string);
237  map_result.insert(pos, map_patterns[placeholder]);
238  }
239  }
240  if (map_result.isEmpty())
241  return false; // no placeholders found in the patterns
242 
243  // relax the pattern: turn single whitespace to one or more whitespaces
244  pattern_esc.replace(QRegExp(_("(\\\\\\s)+")), _("\\s+"));
245 
246  // try to match the pattern on the given text
247  QRegExp rx(pattern_esc, Qt::CaseInsensitive);
248  if (!rx.exactMatch(text.trimmed()))
249  return false; // does not match :-(
250 
251  // we found a match
252  // -> now map the results into the corresponding result strings
253  for (int index = 0; index < map_result.count(); ++index) {
254  QString value = rx.cap(index + 1).trimmed();
255  if (value.length()) {
256  QString *result = map_result[map_result.keys()[index]];
257  if (result) *result = value;
258  }
259  }
260 
261  return true;
262 }
263 
264 //***************************************************************************
265 void Kwave::K3BExportPlugin::load(QStringList &params)
266 {
267  Q_UNUSED(params);
268 
269  QString menu_path = _("File/Save/%1").arg(_(I18N_NOOP2(
270  "menu: /File/Save/Export to K3b Project...",
271  "Export to K3b Project..."
272  )));
273  emitCommand(_("menu(plugin:setup(export_k3b),%1%2)").arg(
274  menu_path).arg(_("/#group(@SIGNAL)")));
275  emitCommand(_("menu(plugin:setup(export_k3b),%1%2)").arg(
276  menu_path).arg(_("/#icon(application-x-k3b)")));
277 }
278 
279 //***************************************************************************
280 QStringList *Kwave::K3BExportPlugin::setup(QStringList &params)
281 {
282  // try to interpret the previous parameters
283  interpreteParameters(params);
284 
285  sample_index_t selection_left = 0;
286  sample_index_t selection_right = 0;
287  selection(Q_NULLPTR, &selection_left, &selection_right, false);
288 
289  // enable the "selection only" checkbox only if there is something
290  // selected but not everything
291  bool selected_something = (selection_left != selection_right);
292  bool selected_all = ((selection_left == 0) &&
293  (selection_right + 1 >= signalLength()));
294  bool enable_selection_only = selected_something && !selected_all;
295 
296  // show a "File / Save As..." dialog for the *.k3b file
297  QPointer<Kwave::K3BExportDialog> dialog =
298  new(std::nothrow) Kwave::K3BExportDialog(
299  _("kfiledialog:///kwave_export_k3b"),
300  K3B_FILE_SUFFIX + _("|") + i18nc(
301  "file type filter when exporting to K3b",
302  "K3b project file (*.k3b)"
303  ),
304  parentWidget(),
305  QUrl::fromUserInput(signalName()),
306  _("*.k3b"),
307  m_pattern,
309  enable_selection_only,
312  );
313  if (!dialog) return Q_NULLPTR;
314 
315  dialog->setWindowTitle(description());
316  if (dialog->exec() != QDialog::Accepted) {
317  delete dialog;
318  return Q_NULLPTR;
319  }
320 
321  QStringList *list = new(std::nothrow) QStringList();
322  Q_ASSERT(list);
323  if (!list) {
324  delete dialog;
325  return Q_NULLPTR;
326  }
327 
328  // user has pressed "OK"
329  QUrl url = dialog->selectedUrl();
330  if (url.isEmpty()) {
331  delete dialog;
332  delete list;
333  return Q_NULLPTR;
334  }
335 
336  QString name = url.path();
337  QFileInfo path(name);
338 
339  // add the correct extension if necessary
340  if (path.suffix() != K3B_FILE_SUFFIX.mid(2))
341  url.setPath(name + K3B_FILE_SUFFIX.mid(1));
342 
343  name = Kwave::Parser::escape(url.toString());
344  QString pattern = Kwave::Parser::escape(dialog->pattern());
345  int export_location = static_cast<int>(dialog->exportLocation());
346  int overwrite_policy = static_cast<int>(dialog->overwritePolicy());
347  bool selection_only = (enable_selection_only) ?
348  dialog->selectionOnly() : m_selection_only;
349 
350  *list << name; // url
351  *list << pattern; // pattern
352  *list << QString::number(selection_only); // selection only
353  *list << QString::number(export_location); // export location
354  *list << QString::number(overwrite_policy); // overwrite policy
355 
356  emitCommand(_("plugin:execute(export_k3b,") +
357  name + _(",") + pattern + _(",") +
358  QString::number(selection_only) + _(",") +
359  QString::number(export_location) + _(",") +
360  QString::number(overwrite_policy) + _(")")
361  );
362 
363  if (dialog) delete dialog;
364  return list;
365 }
366 
367 //***************************************************************************
368 /*
369  * taken from K3b, libk3b/projects/k3bdoc.cpp
370  *
371  * Copyright (C) 2003-2008 Sebastian Trueg <trueg@k3b.org>
372  *
373  */
375 {
376  QDomDocument doc = part->ownerDocument();
377  QDomElement mainElem = doc.createElement(_("general"));
378 
379  QDomElement propElem = doc.createElement(_("writing_mode"));
380  propElem.appendChild(doc.createTextNode(_("auto")));
381  mainElem.appendChild(propElem);
382 
383  propElem = doc.createElement(_("dummy"));
384  propElem.setAttribute(_("activated"), _("no"));
385  mainElem.appendChild(propElem);
386 
387  propElem = doc.createElement(_("on_the_fly"));
388  propElem.setAttribute(_("activated"), _("true"));
389  mainElem.appendChild(propElem);
390 
391  propElem = doc.createElement(_("only_create_images"));
392  propElem.setAttribute(_("activated"), _("no"));
393  mainElem.appendChild(propElem);
394 
395  propElem = doc.createElement(_("remove_images"));
396  propElem.setAttribute(_("activated"), _("no"));
397  mainElem.appendChild(propElem);
398 
399  part->appendChild( mainElem );
400 }
401 
402 //***************************************************************************
403 /*
404  * taken from K3b, libk3b/projects/audiocd/k3baudiodoc.cpp
405  *
406  * Copyright (C) 2003-2008 Sebastian Trueg <trueg@k3b.org>
407  * Copyright (C) 2009 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
408  * Copyright (C) 2010 Michal Malek <michalm@jabster.pl>
409  */
411 {
412  #define GET_INF(inf) doc.createTextNode(info.get(inf).toString())
413 
414  const Kwave::FileInfo info(signalManager().metaData());
415 
416  QDomDocument doc = docElem->ownerDocument();
417  saveGeneralDocumentData(docElem);
418 
419  // add normalize
420  QDomElement normalizeElem = doc.createElement(_("normalize"));
421  normalizeElem.appendChild(doc.createTextNode(_("no")));
422  docElem->appendChild(normalizeElem);
423 
424  // add hide track
425  QDomElement hideFirstTrackElem = doc.createElement(_("hide_first_track"));
426  hideFirstTrackElem.appendChild(doc.createTextNode(_("no")));
427  docElem->appendChild(hideFirstTrackElem);
428 
429  // save the audio cd ripping settings
430  // paranoia mode, read retries, and ignore read errors
431  // ------------------------------------------------------------
432  QDomElement ripMain = doc.createElement(_("audio_ripping"));
433  docElem->appendChild(ripMain);
434 
435  QDomElement ripElem = doc.createElement(_("paranoia_mode"));
436  ripElem.appendChild(doc.createTextNode(_("0")));
437  ripMain.appendChild(ripElem);
438 
439  ripElem = doc.createElement(_("read_retries"));
440  ripElem.appendChild(doc.createTextNode(_("0")));
441  ripMain.appendChild(ripElem);
442 
443  ripElem = doc.createElement(_("ignore_read_errors"));
444  ripElem.appendChild(doc.createTextNode(_("no")));
445  ripMain.appendChild(ripElem);
446  // ------------------------------------------------------------
447 
448  // save disc cd-text
449  // -------------------------------------------------------------
450  QDomElement cdTextMain = doc.createElement(_("cd-text"));
451  cdTextMain.setAttribute(_("activated"), _("yes"));
452 
453  QDomElement cdTextElem = doc.createElement(_("title"));
454  cdTextElem.appendChild(GET_INF(INF_NAME));
455  cdTextMain.appendChild(cdTextElem);
456 
457  cdTextElem = doc.createElement(_("artist"));
458  cdTextElem.appendChild(GET_INF(INF_AUTHOR));
459  cdTextMain.appendChild(cdTextElem);
460 
461  cdTextElem = doc.createElement(_("arranger"));
462  cdTextElem.appendChild(GET_INF(INF_TECHNICAN));
463  cdTextMain.appendChild(cdTextElem);
464 
465  cdTextElem = doc.createElement(_("songwriter"));
466  cdTextElem.appendChild(GET_INF(INF_PERFORMER));
467  cdTextMain.appendChild(cdTextElem);
468 
469  cdTextElem = doc.createElement(_("composer"));
470  cdTextElem.appendChild(GET_INF(INF_ORGANIZATION));
471  cdTextMain.appendChild(cdTextElem);
472 
473  cdTextElem = doc.createElement(_("disc_id"));
474  cdTextElem.appendChild(GET_INF(INF_CD));
475  cdTextMain.appendChild(cdTextElem);
476 
477  cdTextElem = doc.createElement(_("upc_ean"));
478  cdTextElem.appendChild(GET_INF(INF_ISRC));
479  cdTextMain.appendChild(cdTextElem);
480 
481  cdTextElem = doc.createElement(_("message"));
482  cdTextElem.appendChild(GET_INF(INF_COMMENTS));
483  cdTextMain.appendChild(cdTextElem);
484 
485  docElem->appendChild( cdTextMain );
486  // -------------------------------------------------------------
487 
488  // save the tracks
489  // -------------------------------------------------------------
490  QDomElement contentsElem = doc.createElement(_("contents"));
491 
492  unsigned int index = 1;
493  foreach (const Kwave::K3BExportPlugin::BlockInfo &block, m_block_info) {
494  QString title = block.m_title;
495  QString artist = block.m_artist;
496  QString songwriter = QString();
497  QString url = block.m_filename;
498 
499  QDomElement trackElem = doc.createElement(_("track"));
500 
501  // add sources
502  QDomElement sourcesParent = doc.createElement(_("sources"));
503  QDomElement sourceElem = doc.createElement(_("file"));
504  sourceElem.setAttribute(_("url"), url);
505  sourceElem.setAttribute(_("start_offset"), _("00:00:00"));
506  sourceElem.setAttribute(_("end_offset"), _("00:00:00"));
507  sourcesParent.appendChild(sourceElem);
508  trackElem.appendChild(sourcesParent);
509 
510  // index 0
511  QDomElement index0Elem = doc.createElement(_("index0"));
512  index0Elem.appendChild(doc.createTextNode(QString::number(index)));
513  trackElem.appendChild(index0Elem);
514 
515  // add cd-text
516  cdTextMain = doc.createElement(_("cd-text"));
517  cdTextElem = doc.createElement(_("title"));
518  cdTextElem.appendChild(doc.createTextNode(title));
519  cdTextMain.appendChild(cdTextElem);
520 
521  cdTextElem = doc.createElement(_("artist"));
522  cdTextElem.appendChild(doc.createTextNode(artist));
523  cdTextMain.appendChild(cdTextElem);
524 
525  cdTextElem = doc.createElement(_("arranger"));
526  cdTextElem.appendChild(GET_INF(INF_TECHNICAN));
527  cdTextMain.appendChild(cdTextElem);
528 
529  cdTextElem = doc.createElement(_("songwriter"));
530  cdTextElem.appendChild(doc.createTextNode(songwriter));
531  cdTextMain.appendChild(cdTextElem );
532 
533  cdTextElem = doc.createElement(_("composer"));
534  cdTextElem.appendChild(GET_INF(INF_ORGANIZATION));
535  cdTextMain.appendChild(cdTextElem);
536 
537  cdTextElem = doc.createElement(_("isrc"));
538  cdTextElem.appendChild(GET_INF(INF_ISRC));
539  cdTextMain.appendChild(cdTextElem);
540 
541  cdTextElem = doc.createElement(_("message"));
542  cdTextElem.appendChild(GET_INF(INF_COMMENTS));
543  cdTextMain.appendChild(cdTextElem);
544 
545  trackElem.appendChild(cdTextMain);
546 
547  // add copy protection
548  QDomElement copyElem = doc.createElement(_("copy_protection"));
549  copyElem.appendChild(doc.createTextNode(
550  info.get(INF_COPYRIGHTED).toInt() ? _("yes") : _("no")
551  ));
552  trackElem.appendChild(copyElem);
553 
554  // add pre emphasis
555  copyElem = doc.createElement(_("pre_emphasis"));
556  copyElem.appendChild(doc.createTextNode(_("no")));
557  trackElem.appendChild(copyElem);
558 
559  contentsElem.appendChild(trackElem);
560  index++;
561  }
562  // -------------------------------------------------------------
563 
564  docElem->appendChild(contentsElem);
565 }
566 
567 //***************************************************************************
568 int Kwave::K3BExportPlugin::start(QStringList &params)
569 {
570  qDebug("K3BExportPlugin::start()");
571 
572  // interpret the parameters
573  int result = interpreteParameters(params);
574  if (result) return result;
575 
576  // check the output file
577  if (!m_url.isLocalFile())
578  return -EINVAL; // sorry, KZip supports only local files
579 
580  // determine output directory and file name pattern
581  QString k3b_filename = m_url.path();
582  QFileInfo fi(k3b_filename);
583  QString base = fi.completeBaseName();
584  QString out_dir;
585  QString out_pattern;
587  // export to a subdir with the name "<filename>.dir"
588  out_dir = fi.absolutePath() + QDir::separator() + base + _(".dir");
589  out_pattern = _("track-") + OUTFILE_PATTERN;
590  } else {
591  // use the same directory as the *.k3b file
592  out_dir = fi.absolutePath();
593  out_pattern = base + _("-track-") + OUTFILE_PATTERN;
594  }
595  qDebug("out_dir = '%s'", DBG(out_dir));
596  qDebug("out_pattern = '%s'", DBG(out_pattern));
597 
598  // determine the selection settings
599  sample_index_t selection_left = 0;
600  sample_index_t selection_right = 0;
601  QList<unsigned int> tracks;
602  selection(&tracks, &selection_left, &selection_right, false);
603 
604  // check: only mono or stereo files are supported
605  if ((tracks.count() != 1) && (tracks.count() != 2)) {
606  qWarning("sorry, K3b can not handle %u tracks", tracks.count());
608  "Only mono and stereo files can be used for an audio CD. "
609  "You can either deselect some channels or export the file "
610  "in a different file format that supports mono and stereo "
611  "only (for example FLAC) and then try again."
612  ));
613  return -EINVAL;
614  }
615 
616  bool selected_something = (selection_left != selection_right);
617  bool selected_all = ( (selection_left == 0) &&
618  ((selection_right + 1) >= signalLength()) );
619  bool enable_selection_only = selected_something && !selected_all;
620  bool selection_only = enable_selection_only && m_selection_only;
621  if (!selection_only) {
622  selection_left = 0;
623  selection_right = signalLength() - 1;
624  }
625 
626  // create a list of blocks to save, but not yet the output file names
627  scanBlocksToSave(base, selection_left, selection_right);
628  unsigned int count = m_block_info.count();
629  if (!count)
630  return -EINVAL;
631 
632  // find the start index of the file numbering
633  unsigned int first = 1;
635  // use new files, find out the highest existing index
636  QString pat = out_pattern;
637  pat.replace(OUTFILE_PATTERN, _("*"));
638  pat += OUTFILE_SUFFIX;
639 
640  QDir dir(out_dir, pat);
641  QStringList files;
642  files = dir.entryList();
643 
644  for (unsigned int i = first; i < (first + count); ++i) {
645  QString name = createFileName(out_pattern, i);
646  QRegExp rx(_("^(") + name + _(")$"), Qt::CaseInsensitive);
647  QStringList matches = files.filter(rx);
648  if (matches.count() > 0) first = i + 1;
649  }
650  qDebug("found first usable index -> %d", first);
651  } else {
652  // overwrite mode, always start at 1
653  }
654 
655  // create the complete file names
656  for (unsigned int i = 0; i < count; ++i) {
657  m_block_info[i].m_filename = out_dir + QDir::separator() +
658  createFileName(out_pattern, first + i);
659  }
660 
661  result = saveBlocks(selection_only, out_dir, out_pattern);
662  if (result != 0)
663  return result; // aborted or failed -> do not create a k3b file
664 
665  result = saveK3BFile(k3b_filename);
666  if (result != 0)
667  return result; // aborted or failed -> do not ask about starting k3b
668 
670  "A K3b project file has been created and audio files have "
671  "been exported.\n"
672  "Should I start K3b and open the audio CD project now?"
673  )) == KMessageBox::Yes) {
674  // call k3b and pass the project file name (must be full path)
675  QStringList args;
676  args << k3b_filename;
677  if (!QProcess::startDetached(_("k3b"), args)) {
678  return -EIO;
679  }
680  }
681 
682  return result;
683 }
684 
685 //***************************************************************************
686 int Kwave::K3BExportPlugin::saveBlocks(bool selection_only,
687  const QString &out_dir,
688  const QString &out_pattern)
689 {
690  QString first_filename = Kwave::Parser::escapeForFileName(
691  QUrl::fromLocalFile(createFileName(out_pattern, 1)).toString());
692 
693  // remember the original file info remove all unsupported/ properties,
694  // to avoid that the saveblocks plugin complains...
695  const Kwave::FileInfo orig_file_info(signalManager().metaData());
696  Kwave::FileInfo file_info(orig_file_info);
697  QList<Kwave::FileProperty> unsupported_properties;
698  {
699  QString mimetype = Kwave::CodecManager::mimeTypeOf(m_url);
700  Kwave::Encoder *encoder = Kwave::CodecManager::encoder(mimetype);
701  if (encoder) {
702  unsupported_properties = encoder->unsupportedProperties(
703  file_info.properties().keys());
704  delete encoder;
705  }
706  if (!unsupported_properties.isEmpty()) {
707  foreach (const Kwave::FileProperty &p, unsupported_properties) {
708  file_info.set(p, QVariant());
709  }
710  }
711  }
712 
713  // make sure that the file uses 16 bits/sample only
714  file_info.setBits(16);
715 
717 
718  // call the saveblocks plugin and let it do the main work of exporting
719  // the *.wav files with all the tracks...
720 
721  QStringList params;
722  params << out_dir + QDir::separator() + first_filename;
723  params << Kwave::Parser::escape(out_pattern);
724  params << ((m_overwrite_policy == USE_NEW_FILE_NAMES) ? _("0") : _("1"));
725  params << (selection_only ? _("1") : _("0"));
726  int result = manager().executePlugin(_("saveblocks"), &params);
727 
728  // restore the original file info
729  signalManager().metaData().replace(Kwave::MetaDataList(orig_file_info));
730 
731  return result;
732 }
733 
734 //***************************************************************************
735 int Kwave::K3BExportPlugin::saveK3BFile(const QString &k3b_filename)
736 {
737  // create the K3B file
738  KZip zip(k3b_filename);
739 
740  bool ok = zip.open(QIODevice::WriteOnly);
741  if (!ok) return -EIO;
742 
743  // write the mime type
744  QByteArray app_type(K3B_PROJECT_MIME_TYPE);
745  zip.setCompression(KZip::NoCompression);
746  zip.setExtraField(KZip::NoExtraField);
747  zip.writeFile(_("mimetype"), app_type);
748 
749  // export file global data
750  QByteArray xml;
751  QBuffer out(&xml);
752  out.open(QIODevice::WriteOnly);
753 
754  // save the data in the document
755  QDomDocument xmlDoc(_("k3b_audio_project"));
756 
757  xmlDoc.appendChild(xmlDoc.createProcessingInstruction(
758  _("xml"), _("version=\"1.0\" encoding=\"UTF-8\"")
759  ));
760  QDomElement docElem = xmlDoc.createElement(_("k3b_audio_project"));
761  xmlDoc.appendChild(docElem);
762  saveDocumentData(&docElem);
763  QTextStream xmlStream(&out);
764  xmlDoc.save(xmlStream, 0);
765 
766  out.close();
767 
768  zip.setCompression(KZip::NoCompression);
769  zip.setExtraField(KZip::NoExtraField);
770  zip.writeFile(_("maindata.xml"), xml.data());
771  zip.close();
772 
773  return 0;
774 }
775 
776 //***************************************************************************
778 {
779  // list of all known detection patterns
780  QStringList patterns;
781  patterns << _("[%title] ([%artist])");
782  patterns << _("[%title], [%artist]");
783  patterns << _("[%artist]: [%title]");
784  patterns << _("[%artist] - [%title]");
785  return patterns;
786 }
787 
788 //***************************************************************************
789 #include "K3BExportPlugin.moc"
790 //***************************************************************************
791 //***************************************************************************
int saveK3BFile(const QString &k3b_filename)
#define GET_INF(inf)
void emitCommand(const QString &command)
Definition: Plugin.cpp:510
K3BExportPlugin(QObject *parent, const QVariantList &args)
#define OUTFILE_DIGITS
overwrite_policy_t m_overwrite_policy
Definition: App.h:33
#define K3B_FILE_SUFFIX
QWidget * parentWidget() const
Definition: Plugin.cpp:450
Kwave::MetaDataList & metaData()
export_location_t m_export_location
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
Kwave::SignalManager & signalManager()
Definition: Plugin.cpp:444
static int sorry(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:85
virtual QString name() const
Definition: Plugin.cpp:196
virtual sample_index_t pos() const
Definition: Label.cpp:56
static int questionYesNo(QWidget *widget, QString message, QString caption=QString(), const QString buttonYes=QString(), const QString buttonNo=QString(), const QString &dontAskAgainName=QString())
Definition: MessageBox.cpp:63
quint64 sample_index_t
Definition: Sample.h:28
QString createFileName(const QString &pattern, unsigned int index)
static QString mimeTypeOf(const QUrl &url)
Kwave::PluginManager & manager() const
Definition: Plugin.cpp:437
void set(FileProperty key, const QVariant &value)
Definition: FileInfo.cpp:363
QListIterator< Kwave::Label > LabelListIterator
Definition: LabelList.h:76
virtual int start(QStringList &params) Q_DECL_OVERRIDE
int executePlugin(const QString &name, QStringList *params)
static QString unescape(const QString &text)
Definition: Parser.cpp:314
static QString escapeForFileName(const QString &text)
Definition: Parser.cpp:295
virtual QList< Kwave::FileProperty > unsupportedProperties(const QList< Kwave::FileProperty > &properties_to_check)
Definition: Encoder.cpp:27
const QMap< FileProperty, QVariant > properties() const
Definition: FileInfo.cpp:389
void saveDocumentData(QDomElement *docElem)
virtual bool isNull() const
Definition: MetaData.cpp:69
virtual QString name() const
Definition: Label.cpp:74
int interpreteParameters(QStringList &params)
void saveGeneralDocumentData(QDomElement *part)
virtual void replace(const MetaDataList &list)
virtual void load(QStringList &params) Q_DECL_OVERRIDE
virtual sample_index_t signalLength()
Definition: Plugin.cpp:462
QString signalName()
Definition: Plugin.cpp:456
static QStringList knownPatterns()
void setBits(unsigned int bits)
Definition: FileInfo.cpp:439
#define OUTFILE_SUFFIX
static Kwave::Encoder * encoder(const QString &mimetype_name)
#define KWAVE_PLUGIN(name, class)
Definition: Plugin.h:54
#define _(m)
Definition: memcpy.c:66
#define DBG(qs)
Definition: String.h:55
void scanBlocksToSave(const QString &base, sample_index_t selection_left, sample_index_t selection_right)
static QString escape(const QString &text)
Definition: Parser.cpp:277
FileProperty
Definition: FileInfo.h:45
virtual QString description() const
Definition: Plugin.cpp:202
virtual QStringList * setup(QStringList &params) Q_DECL_OVERRIDE
bool detectBlockMetaData(const QString &text, const QString &pattern, BlockInfo &block)
#define K3B_PROJECT_MIME_TYPE
#define OUTFILE_PATTERN
QVector< BlockInfo > m_block_info
virtual ~K3BExportPlugin() Q_DECL_OVERRIDE
virtual sample_index_t selection(QList< unsigned int > *tracks=Q_NULLPTR, sample_index_t *left=Q_NULLPTR, sample_index_t *right=Q_NULLPTR, bool expand_if_empty=false)
Definition: Plugin.cpp:480
int saveBlocks(bool selection_only, const QString &out_dir, const QString &out_pattern)