ScannedFileItem *
ScannedFileItem::create(SourceFile const &scannedFile) {
  auto item = new ScannedFileItem{ scannedFile, QStringList{
      QFileInfo{scannedFile.m_fileName}.fileName(),
      to_qs(format_timecode(scannedFile.m_playlistDuration, 0)),
      to_qs(format_file_size(scannedFile.m_playlistSize)),
    }};

  item->setTextAlignment(1, Qt::AlignRight | Qt::AlignVCenter);
  item->setTextAlignment(2, Qt::AlignRight | Qt::AlignVCenter);

  return item;
}
void
SourceFileModel::setItemsFromSourceFile(QList<QStandardItem *> const &items,
                                        SourceFile *sourceFile)
  const {
  auto info = QFileInfo{sourceFile->m_fileName};

  items[0]->setText(info.fileName());
  items[1]->setText(sourceFile->isAdditionalPart() ? QY("(additional part)") : sourceFile->container());
  items[2]->setText(to_qs(format_file_size(sourceFile->isPlaylist() ? sourceFile->m_playlistSize : info.size())));
  items[3]->setText(info.path());

  items[0]->setData(reinterpret_cast<quint64>(sourceFile), Util::SourceFileRole);
  items[0]->setIcon(  sourceFile->isAdditionalPart() ? m_additionalPartIcon
                    : sourceFile->isAppended()       ? m_addedIcon
                    :                                  m_normalIcon);

  items[2]->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
}
QList<QStandardItem *>
SourceFileModel::createRow(SourceFile *sourceFile)
  const {
  auto items = QList<QStandardItem *>{};
  auto info  = QFileInfo{sourceFile->m_fileName};

  items << new QStandardItem{info.fileName()};
  items << new QStandardItem{sourceFile->isAdditionalPart() ? QY("(additional part)") : sourceFile->m_container};
  items << new QStandardItem{to_qs(format_file_size(sourceFile->isPlaylist() ? sourceFile->m_playlistSize : info.size()))};
  items << new QStandardItem{info.path()};

  items[0]->setData(reinterpret_cast<quint64>(sourceFile), Util::SourceFileRole);
  items[0]->setIcon(  sourceFile->isAdditionalPart() ? m_additionalPartIcon
                    : sourceFile->isAppended()       ? m_addedIcon
                    :                                  m_normalIcon);

  items[2]->setTextAlignment(Qt::AlignRight);

  return items;
}
void
SelectPlaylistDialog::onScannedFileSelected(QTreeWidgetItem *current,
                                            QTreeWidgetItem *) {
  auto selectedItem = static_cast<ScannedFileItem *>(current);
  if (!selectedItem)
    return;

  auto const &file = *selectedItem->m_file;

  ui->duration->setText(to_qs(format_timecode(file.m_playlistDuration, 0)));
  ui->size->setText(to_qs(format_file_size(file.m_playlistSize)));
  ui->numberOfChapters->setText(QString::number(file.m_playlistChapters));

  ui->tracks->setSortingEnabled(false);
  ui->playlistItems->setSortingEnabled(false);

  ui->tracks->clear();
  ui->playlistItems->clear();

  auto newItems = QList<QTreeWidgetItem *>{};
  for (auto const &track : file.m_tracks)
    newItems << TrackItem::create(*track);

  ui->tracks->insertTopLevelItems(0, newItems);

  newItems.clear();
  for (auto const &playlistFile : file.m_playlistFiles)
    newItems << createPlaylistItemItem(playlistFile);

  ui->playlistItems->insertTopLevelItems(0, newItems);

  ui->tracks->setSortingEnabled(true);
  ui->tracks->sortItems(ui->tracks->sortColumn(), Qt::AscendingOrder);

  ui->playlistItems->setSortingEnabled(true);
  ui->playlistItems->sortItems(ui->playlistItems->sortColumn(), Qt::AscendingOrder);

  Util::resizeViewColumnsToContents(ui->tracks);
  Util::resizeViewColumnsToContents(ui->playlistItems);
}
void
select_scanned_file_dlg::update_info() {
  wxListItem item;

  auto &playlist = *m_playlists[m_selected_playlist_idx];

  m_st_duration->SetLabel(wxU(format_timecode(playlist.duration, 0)));
  m_st_size->SetLabel(wxU(format_file_size(playlist.size)));
  m_st_chapters->SetLabel(wxU(boost::format("%1%") % playlist.chapters));

  m_lc_tracks->Hide();
  m_lc_tracks->DeleteAllItems();
  long idx = 0;
  for (auto &track : playlist.tracks) {
    auto id = m_lc_tracks->InsertItem(idx, track.type);
    m_lc_tracks->SetItem(id, 1, track.codec);
    m_lc_tracks->SetItem(id, 2, wxU(boost::format("%|1$ -15s|") % to_utf8(track.language)));
    ++idx;
  }

  m_lc_tracks->SetColumnWidth(0, wxLIST_AUTOSIZE);
  m_lc_tracks->SetColumnWidth(1, wxLIST_AUTOSIZE);
  m_lc_tracks->SetColumnWidth(2, wxLIST_AUTOSIZE);

  m_lc_tracks->Show();

  m_lc_items->Hide();
  m_lc_items->DeleteAllItems();
  idx = 0;
  for (auto &file : playlist.files) {
    auto id = m_lc_items->InsertItem(idx, wxFileName{file}.GetFullName());
    m_lc_items->SetItem(id, 1, wxFileName{file}.GetPath());
    ++idx;
  }

  m_lc_items->SetColumnWidth(0, wxLIST_AUTOSIZE);
  m_lc_items->SetColumnWidth(1, wxLIST_AUTOSIZE);

  m_lc_items->Show();
}
select_scanned_file_dlg::select_scanned_file_dlg(wxWindow *parent,
                                                 std::vector<playlist_file_cptr> const &playlists,
                                                 wxString const &orig_file_name)
  : wxDialog(parent, wxID_ANY, Z("Select file to add"), wxDefaultPosition, wxSize{1000, 650})
  , m_playlists{playlists}
  , m_selected_playlist_idx{0}
{
  // controls left column
	auto st_scanned_files = new wxStaticText(this, wxID_ANY, Z("Scanned files"));
	auto sl_left          = new wxStaticLine(this);
	m_lc_files            = new wxListCtrl(  this, ID_LC_PLAYLIST_FILE, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);

  // controls right column
	auto st_details        = new wxStaticText(this, wxID_ANY, Z("Details"));
	auto sl_right          = new wxStaticLine(this);
	auto st_duration       = new wxStaticText(this, wxID_ANY, Z("Duration:"));
	m_st_duration          = new wxStaticText(this, wxID_ANY, wxEmptyString);
	auto st_size           = new wxStaticText(this, wxID_ANY, Z("Size:"));
	m_st_size              = new wxStaticText(this, wxID_ANY, wxEmptyString);
	auto st_chapters       = new wxStaticText(this, wxID_ANY, Z("Number of chapters:"));
	m_st_chapters          = new wxStaticText(this, wxID_ANY, wxEmptyString);
	auto st_tracks         = new wxStaticText(this, wxID_ANY, Z("Tracks:"));
	m_lc_tracks            = new wxListCtrl(  this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);
	auto st_playlist_items = new wxStaticText(this, wxID_ANY, Z("Playlist items:"));
	m_lc_items             = new wxListCtrl(  this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);

  // button controls
	auto b_add    = new wxButton(this, wxID_OK,     Z("&Add"));
	auto b_cancel = new wxButton(this, wxID_CANCEL, Z("&Cancel"));
	b_add->SetDefault();

  // list controls
  wxListItem item;

  item.SetText(Z("File name"));
  m_lc_files->InsertColumn(0, item);
  item.SetText(Z("Duration"));
  m_lc_files->InsertColumn(1, item);
  item.SetText(Z("Size"));
  m_lc_files->InsertColumn(2, item);

  item.SetText(Z("Type"));
  m_lc_tracks->InsertColumn(0, item);
  item.SetText(Z("Codec"));
  m_lc_tracks->InsertColumn(1, item);
  item.SetText(Z("Language"));
  m_lc_tracks->InsertColumn(2, item);

  item.SetText(Z("File name"));
  m_lc_items->InsertColumn(0, item);
  item.SetText(Z("Directory"));
  m_lc_items->InsertColumn(1, item);

  // fill "files" with data
  m_lc_files->Hide();
  long idx = 0;
  for (auto &playlist : m_playlists) {
    auto id = m_lc_files->InsertItem(idx, wxFileName{playlist->file_name}.GetFullName());
    m_lc_files->SetItem(id, 1, wxU(format_timecode(playlist->duration, 0)));
    m_lc_files->SetItem(id, 2, wxU(format_file_size(playlist->size)));
    m_lc_files->SetItemData(id, idx);

    if (orig_file_name == playlist->file_name) {
      m_lc_files->SetItemState(id, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
      m_selected_playlist_idx = idx;
    }

    ++idx;
  }

  m_lc_files->SetColumnWidth(0, wxLIST_AUTOSIZE);
  m_lc_files->SetColumnWidth(1, wxLIST_AUTOSIZE);
  m_lc_files->SetColumnWidth(2, wxLIST_AUTOSIZE);

  m_lc_files->Show();

  // layout
	auto siz_left_column = new wxBoxSizer(wxVERTICAL);
	siz_left_column->Add(st_scanned_files, 0, wxALL,            5);
	siz_left_column->Add(sl_left,          0, wxALL | wxEXPAND, 5);
	siz_left_column->Add(m_lc_files,       1, wxALL | wxEXPAND, 5);

	auto siz_info = new wxGridSizer(3, 2, 0, 0);
	siz_info->Add(st_duration,   0, wxALL, 5);
	siz_info->Add(m_st_duration, 0, wxALL, 5);
	siz_info->Add(st_size,       0, wxALL, 5);
	siz_info->Add(m_st_size,     0, wxALL, 5);
	siz_info->Add(st_chapters,   0, wxALL, 5);
	siz_info->Add(m_st_chapters, 0, wxALL, 5);

	auto siz_right_column = new wxBoxSizer(wxVERTICAL);
	siz_right_column->Add(st_details,        0, wxALL,            5);
	siz_right_column->Add(sl_right,          0, wxEXPAND | wxALL, 5);
	siz_right_column->Add(siz_info,          0, wxEXPAND,         5);
	siz_right_column->Add(st_tracks,         0, wxALL,            5);
	siz_right_column->Add(m_lc_tracks,       1, wxALL | wxEXPAND, 5);
	siz_right_column->Add(st_playlist_items, 0, wxALL,            5);
	siz_right_column->Add(m_lc_items,        1, wxALL | wxEXPAND, 5);

	auto siz_columns = new wxBoxSizer(wxHORIZONTAL);
	siz_columns->Add(siz_left_column,  1, wxEXPAND, 5);
	siz_columns->Add(siz_right_column, 1, wxEXPAND, 5);

	auto siz_buttons = new wxBoxSizer(wxHORIZONTAL);
	siz_buttons->AddStretchSpacer();
	siz_buttons->Add(b_add,    0, wxALL, 5);
	siz_buttons->AddStretchSpacer();
	siz_buttons->Add(b_cancel, 0, wxALL, 5);
	siz_buttons->AddStretchSpacer();

	auto siz_all = new wxBoxSizer(wxVERTICAL);
	siz_all->Add(siz_columns, 1, wxEXPAND, 5);
	siz_all->Add(siz_buttons, 0, wxEXPAND, 5);

	SetSizer(siz_all);
	Layout();

	Centre(wxBOTH);

  update_info();
}
void
AttachmentModel::setRowData(QList<QStandardItem *> const &items,
                            Attachment const &attachment) {
  auto info = QFileInfo{attachment.m_fileName};
  auto size = QNY("%1 byte (%2)", "%1 bytes (%2)", info.size()).arg(info.size()).arg(Q(format_file_size(info.size())));

  items[NameColumn       ]->setText(attachment.m_name);
  items[MIMETypeColumn   ]->setText(attachment.m_MIMEType);
  items[DescriptionColumn]->setText(attachment.m_description);
  items[StyleColumn      ]->setText(attachment.m_style == Attachment::ToAllFiles ? QY("To all destination files") : QY("Only to the first destination file"));
  items[SourceFileColumn ]->setText(info.fileName());
  items[SourceDirColumn  ]->setText(QDir::toNativeSeparators(info.path()));
  items[SizeColumn       ]->setText(size);

  items[SizeColumn       ]->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
}
select_scanned_file_dlg::select_scanned_file_dlg(wxWindow *parent,
                                                 std::vector<playlist_file_cptr> const &playlists,
                                                 wxString const &orig_file_name)
  : wxDialog{parent, wxID_ANY, Z("Select file to add"), wxDefaultPosition, wxSize{1000, 650}, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX}
  , m_playlists{playlists}
  , m_selected_playlist_idx{0}
  , m_geometry_saver{this, "select_scanned_file_dlg"}
  , m_sorted_by_column{}
  , m_sorted_ascending{}
{
  // controls left column
	auto st_scanned_files = new wxStaticText(this, wxID_ANY, Z("Scanned files"));
	auto sl_left          = new wxStaticLine(this);
	m_lc_files            = new wxListCtrl(  this, ID_LC_PLAYLIST_FILE, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);

  // controls right column
	auto st_details        = new wxStaticText(this, wxID_ANY, Z("Details"));
	auto sl_right          = new wxStaticLine(this);
	auto st_duration       = new wxStaticText(this, wxID_ANY, Z("Duration:"));
	m_st_duration          = new wxStaticText(this, wxID_ANY, wxEmptyString);
	auto st_size           = new wxStaticText(this, wxID_ANY, Z("Size:"));
	m_st_size              = new wxStaticText(this, wxID_ANY, wxEmptyString);
	auto st_chapters       = new wxStaticText(this, wxID_ANY, Z("Number of chapters:"));
	m_st_chapters          = new wxStaticText(this, wxID_ANY, wxEmptyString);
	auto st_tracks         = new wxStaticText(this, wxID_ANY, Z("Tracks:"));
	m_lc_tracks            = new wxListCtrl(  this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);
	auto st_playlist_items = new wxStaticText(this, wxID_ANY, Z("Playlist items:"));
	m_lc_items             = new wxListCtrl(  this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);

  // button controls
	auto b_add    = new wxButton(this, wxID_OK,     Z("&Add"));
	auto b_cancel = new wxButton(this, wxID_CANCEL, Z("&Cancel"));
	b_add->SetDefault();

  // list controls
  m_lc_files->InsertColumn(0, Z("File name"));
  m_lc_files->InsertColumn(1, Z("Duration"), wxLIST_FORMAT_RIGHT);
  m_lc_files->InsertColumn(2, Z("Size"), wxLIST_FORMAT_RIGHT);

  m_lc_tracks->InsertColumn(0, Z("Type"));
  m_lc_tracks->InsertColumn(1, Z("Codec"));
  m_lc_tracks->InsertColumn(2, Z("Language"));

  m_lc_items->InsertColumn(0, Z("File name"));
  m_lc_items->InsertColumn(1, Z("Directory"));

  m_sort_arrows.Add(wx_get_png(sort_ascending));
  m_sort_arrows.Add(wx_get_png(sort_descending));
  m_lc_files->SetImageList(&m_sort_arrows, wxIMAGE_LIST_SMALL);

  // fill "files" with data
  m_lc_files->Hide();
  long idx = 0;
  for (auto &playlist : m_playlists) {
    auto id = m_lc_files->InsertItem(idx, wxFileName{playlist->file_name}.GetFullName());
    m_lc_files->SetItemData(id, idx);

    auto item = wxListItem{};
    item.SetId(id);
    item.SetColumn(1);
    item.SetText(wxU(format_timecode(playlist->duration, 0)));
    item.SetAlign(wxLIST_FORMAT_RIGHT);
    item.SetMask(wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT);
    m_lc_files->SetItem(item);

    item.SetColumn(2);
    item.SetText(wxU(format_file_size(playlist->size)));
    m_lc_files->SetItem(item);

    if (orig_file_name == playlist->file_name) {
      m_lc_files->SetItemState(id, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
      m_selected_playlist_idx = idx;
    }

    ++idx;
  }

  sort_by(0, true);

  m_lc_files->SetColumnWidth(0, wxLIST_AUTOSIZE);
  m_lc_files->SetColumnWidth(1, wxLIST_AUTOSIZE);
  m_lc_files->SetColumnWidth(2, wxLIST_AUTOSIZE);

  m_lc_files->Show();

  // layout
	auto siz_left_column = new wxBoxSizer(wxVERTICAL);
	siz_left_column->Add(st_scanned_files, 0, wxALL,            5);
	siz_left_column->Add(sl_left,          0, wxALL | wxEXPAND, 5);
	siz_left_column->Add(m_lc_files,       1, wxALL | wxEXPAND, 5);

	auto siz_info = new wxGridSizer(3, 2, 0, 0);
	siz_info->Add(st_duration,   0, wxALL, 5);
	siz_info->Add(m_st_duration, 0, wxALL, 5);
	siz_info->Add(st_size,       0, wxALL, 5);
	siz_info->Add(m_st_size,     0, wxALL, 5);
	siz_info->Add(st_chapters,   0, wxALL, 5);
	siz_info->Add(m_st_chapters, 0, wxALL, 5);

	auto siz_right_column = new wxBoxSizer(wxVERTICAL);
	siz_right_column->Add(st_details,        0, wxALL,            5);
	siz_right_column->Add(sl_right,          0, wxEXPAND | wxALL, 5);
	siz_right_column->Add(siz_info,          0, wxEXPAND,         5);
	siz_right_column->Add(st_tracks,         0, wxALL,            5);
	siz_right_column->Add(m_lc_tracks,       1, wxALL | wxEXPAND, 5);
	siz_right_column->Add(st_playlist_items, 0, wxALL,            5);
	siz_right_column->Add(m_lc_items,        1, wxALL | wxEXPAND, 5);

	auto siz_columns = new wxBoxSizer(wxHORIZONTAL);
	siz_columns->Add(siz_left_column,  1, wxEXPAND, 5);
	siz_columns->Add(siz_right_column, 1, wxEXPAND, 5);

	auto siz_buttons = new wxBoxSizer(wxHORIZONTAL);
	siz_buttons->AddStretchSpacer();
	siz_buttons->Add(b_add,    0, wxALL, 5);
	siz_buttons->AddStretchSpacer();
	siz_buttons->Add(b_cancel, 0, wxALL, 5);
	siz_buttons->AddStretchSpacer();

	auto siz_all = new wxBoxSizer(wxVERTICAL);
	siz_all->Add(siz_columns, 1, wxEXPAND, 5);
	siz_all->Add(siz_buttons, 0, wxEXPAND, 5);

	SetSizerAndFit(siz_all);
	Layout();

	Centre(wxBOTH);

  m_geometry_saver.set_default_size(1000, 650, true).restore();

  update_info();
}