• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / score / 31975605394

16 Aug 2026 10:10PM UTC coverage: 20.35%. First build
31975605394

Pull #2211

github

web-flow
Merge 1defa584c into bb5e533af
Pull Request #2211: project: collect, relink, trim and archive a project's files

1182 of 1996 new or added lines in 43 files covered. (59.22%)

43464 of 213584 relevant lines covered (20.35%)

5552.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/plugins/score-lib-process/Process/UnusedFilesDialog.cpp
1
#include <Process/UnusedFilesDialog.hpp>
2

3
#include <score/document/DocumentContext.hpp>
4

5
#include <QCheckBox>
6
#include <QComboBox>
7
#include <QDialogButtonBox>
8
#include <QFormLayout>
9
#include <QLabel>
10
#include <QLocale>
11
#include <QMessageBox>
12
#include <QPushButton>
13
#include <QVBoxLayout>
14

15
#include <algorithm>
16

17
namespace Process
18
{
19

NEW
20
UnusedFilesDialog::UnusedFilesDialog(const score::DocumentContext& ctx, QWidget* parent)
×
NEW
21
    : QDialog{parent}
×
NEW
22
    , m_ctx{ctx}
×
NEW
23
{
×
NEW
24
  setWindowTitle(tr("Unused files"));
×
NEW
25
  resize(900, 560);
×
26

NEW
27
  auto lay = new QVBoxLayout{this};
×
28

NEW
29
  m_summary = new QLabel{this};
×
NEW
30
  m_summary->setWordWrap(true);
×
NEW
31
  lay->addWidget(m_summary);
×
32

NEW
33
  m_warnings = new QLabel{this};
×
NEW
34
  m_warnings->setWordWrap(true);
×
NEW
35
  m_warnings->setTextFormat(Qt::RichText);
×
NEW
36
  lay->addWidget(m_warnings);
×
37

NEW
38
  auto form = new QFormLayout;
×
NEW
39
  lay->addLayout(form);
×
40

NEW
41
  m_disposal = new QComboBox{this};
×
NEW
42
  m_disposal->addItem(
×
NEW
43
      tr("Move them to the Unused folder"), int(UnusedDisposal::MoveAside));
×
NEW
44
  m_disposal->addItem(tr("Delete them"), int(UnusedDisposal::Delete));
×
NEW
45
  m_disposal->setToolTip(
×
NEW
46
      tr("Moving keeps them in the project, out of the way and out of archives, "
×
47
         "so a mistake costs a drag back. Deleting does not."));
NEW
48
  form->addRow(tr("What to do"), m_disposal);
×
49

NEW
50
  m_everywhere = new QCheckBox{
×
NEW
51
      tr("Look through the whole project folder, not just Audio/, Video/, ..."),
×
52
      this};
NEW
53
  m_everywhere->setToolTip(
×
NEW
54
      tr("Off by default. score put the files in those folders and knows what "
×
55
         "they were for; the rest of a project folder can hold renders, notes "
56
         "and other people's work."));
NEW
57
  form->addRow(m_everywhere);
×
58

NEW
59
  m_files = new FileReportView{this};
×
NEW
60
  m_files->setCheckable(true);
×
NEW
61
  lay->addWidget(m_files, 1);
×
62

NEW
63
  auto buttons
×
NEW
64
      = new QDialogButtonBox{QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this};
×
NEW
65
  m_ok = buttons->button(QDialogButtonBox::Ok);
×
NEW
66
  lay->addWidget(buttons);
×
67

NEW
68
  connect(buttons, &QDialogButtonBox::accepted, this, &UnusedFilesDialog::run);
×
NEW
69
  connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
×
NEW
70
  connect(m_everywhere, &QCheckBox::toggled, this, [this] { rescan(); });
×
NEW
71
  connect(m_disposal, &QComboBox::currentIndexChanged, this, [this] { rescan(); });
×
72

NEW
73
  rescan();
×
NEW
74
}
×
75

NEW
76
UnusedFilesDialog::~UnusedFilesDialog() = default;
×
77

NEW
78
UnusedFilesOptions UnusedFilesDialog::options() const noexcept
×
79
{
NEW
80
  return {
×
NEW
81
      .onlyCollectedFolders = !m_everywhere->isChecked(),
×
NEW
82
      .disposal = UnusedDisposal(m_disposal->currentData().toInt())};
×
83
}
84

NEW
85
void UnusedFilesDialog::rescan()
×
86
{
NEW
87
  m_scan = analyzeUnusedFiles(m_ctx, options());
×
NEW
88
  m_files->setReport(m_scan);
×
89

NEW
90
  const bool deleting = options().disposal == UnusedDisposal::Delete;
×
NEW
91
  m_ok->setText(deleting ? tr("Delete") : tr("Move aside"));
×
NEW
92
  m_ok->setEnabled(!m_scan.empty());
×
93

NEW
94
  qint64 total = 0;
×
NEW
95
  for(const auto& e : m_scan.entries)
×
NEW
96
    total += e.size;
×
97

NEW
98
  const QString scope = m_everywhere->isChecked()
×
NEW
99
                            ? tr("the whole project folder")
×
NEW
100
                            : tr("the Audio/, Video/, Images/... folders");
×
101

NEW
102
  if(m_scan.empty())
×
103
  {
NEW
104
    m_summary->setText(
×
NEW
105
        tr("<b>%1</b><br/>Nothing unused was found in %2.")
×
NEW
106
            .arg(m_scan.projectFolder)
×
NEW
107
            .arg(scope));
×
NEW
108
  }
×
109
  else
110
  {
NEW
111
    m_summary->setText(
×
NEW
112
        tr("<b>%1</b><br/>%2 file(s) in %3, %4, that nothing in this project "
×
113
           "points at. Untick anything you want to keep.")
NEW
114
            .arg(m_scan.projectFolder)
×
NEW
115
            .arg(m_scan.entries.size())
×
NEW
116
            .arg(scope)
×
NEW
117
            .arg(QLocale{}.formattedDataSize(total)));
×
118
  }
119

NEW
120
  const auto warnings = unusedFilesWarnings(m_ctx, m_scan);
×
NEW
121
  if(warnings.isEmpty())
×
122
  {
NEW
123
    m_warnings->clear();
×
NEW
124
    m_warnings->hide();
×
NEW
125
  }
×
126
  else
127
  {
NEW
128
    m_warnings->setText(
×
NEW
129
        tr("<b>Before you do:</b><ul><li>%1</li></ul>")
×
NEW
130
            .arg(warnings.join(QStringLiteral("</li><li>"))));
×
NEW
131
    m_warnings->show();
×
132
  }
NEW
133
}
×
134

NEW
135
void UnusedFilesDialog::run()
×
136
{
137
  // Only what is ticked, resolved back to the files the scan found.
NEW
138
  const auto ticked = m_files->checkedPaths();
×
NEW
139
  std::vector<QString> paths;
×
NEW
140
  for(const auto& stored : ticked)
×
NEW
141
    for(const auto& e : m_scan.entries)
×
NEW
142
      if(e.storedPath == stored)
×
NEW
143
        paths.push_back(e.sourcePath);
×
144

NEW
145
  if(paths.empty())
×
146
  {
NEW
147
    reject();
×
NEW
148
    return;
×
149
  }
150

NEW
151
  const auto opts = options();
×
NEW
152
  if(opts.disposal == UnusedDisposal::Delete)
×
153
  {
NEW
154
    qint64 total = 0;
×
NEW
155
    for(const auto& e : m_scan.entries)
×
NEW
156
      if(std::find(paths.begin(), paths.end(), e.sourcePath) != paths.end())
×
NEW
157
        total += e.size;
×
158

NEW
159
    const auto res = QMessageBox::warning(
×
NEW
160
        this, tr("Delete these files?"),
×
NEW
161
        tr("%1 file(s), %2, will be deleted from %3.\n\n"
×
162
           "This cannot be undone -- score's undo does not restore files.\n\n"
163
           "Continue?")
NEW
164
            .arg(paths.size())
×
NEW
165
            .arg(QLocale{}.formattedDataSize(total))
×
NEW
166
            .arg(m_scan.projectFolder),
×
NEW
167
        QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
×
NEW
168
    if(res != QMessageBox::Yes)
×
NEW
169
      return;
×
NEW
170
  }
×
171

NEW
172
  m_result = removeUnusedFiles(m_ctx, paths, opts);
×
173

NEW
174
  if(const int failed = m_result.count(FileAction::Failed)
×
NEW
175
                        + m_result.count(FileAction::Skipped);
×
NEW
176
     failed > 0)
×
177
  {
NEW
178
    QString detail;
×
NEW
179
    for(const auto& e : m_result.entries)
×
NEW
180
      if(!e.note.isEmpty())
×
NEW
181
        detail += e.storedPath + ": " + e.note + '\n';
×
182

NEW
183
    QMessageBox::warning(
×
NEW
184
        this, tr("Some files were left alone"),
×
NEW
185
        tr("%1 file(s) were not removed:\n\n%2").arg(failed).arg(detail));
×
NEW
186
  }
×
187

NEW
188
  accept();
×
NEW
189
}
×
190
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc