Skip to content

Commit

Permalink
Add option to read tags from command's output.
Browse files Browse the repository at this point in the history
  • Loading branch information
0xb8 committed Nov 27, 2022
1 parent 2e4224a commit 8633b96
Show file tree
Hide file tree
Showing 9 changed files with 308 additions and 147 deletions.
2 changes: 2 additions & 0 deletions src/global_enums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ struct MetaTypeRegistrator
REGISTER_METATYPE_STREAM_OPERATORS(GlobalEnums::ViewMode)
REGISTER_METATYPE_STREAM_OPERATORS(GlobalEnums::SortQueueBy)
REGISTER_METATYPE_STREAM_OPERATORS(GlobalEnums::EditMode)
REGISTER_METATYPE_STREAM_OPERATORS(GlobalEnums::CommandOutputMode)
}
};
static const MetaTypeRegistrator _;
IMPLEMENT_ENUM_STREAM_OPERATORS(GlobalEnums::ViewMode)
IMPLEMENT_ENUM_STREAM_OPERATORS(GlobalEnums::SortQueueBy)
IMPLEMENT_ENUM_STREAM_OPERATORS(GlobalEnums::EditMode)
IMPLEMENT_ENUM_STREAM_OPERATORS(GlobalEnums::CommandOutputMode)


GlobalEnums::EditMode GlobalEnums::next_edit_mode(EditMode current)
Expand Down
16 changes: 16 additions & 0 deletions src/global_enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,24 @@ class GlobalEnums
*/
static EditMode next_edit_mode(EditMode current);


/*!
* \brief Specifies command output mode.
*/
enum class CommandOutputMode {
Ignore, ///< Command output is ignored, and the process is detached.
Replace, ///< Command output replaces current tags
Append, ///< Command output appended to current tags
Prepend ///< Command output prepended to current tags
};
Q_ENUM(CommandOutputMode);

GlobalEnums() = delete;
};
ENUM_STREAM_OPERATORS(GlobalEnums::ViewMode)
ENUM_STREAM_OPERATORS(GlobalEnums::SortQueueBy)
ENUM_STREAM_OPERATORS(GlobalEnums::EditMode)
ENUM_STREAM_OPERATORS(GlobalEnums::CommandOutputMode)


/// Alias for \ref GlobalEnums::ViewMode enumeration
Expand All @@ -95,4 +108,7 @@ using SortQueueBy = GlobalEnums::SortQueueBy;
/// Alias for \ref GlobalEnums::EditMode enumeration
using EditMode = GlobalEnums::EditMode;

/// Alias for \ref GlobalEnums::CommandOutputMode enumeration
using CommandOutputMode = GlobalEnums::CommandOutputMode;

#endif // GLOBAL_ENUMS_H
11 changes: 11 additions & 0 deletions src/settings_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "ui_settings.h"
#include "util/misc.h"
#include "util/project_info.h"
#include "global_enums.h"
#include "util/command_placeholders.h"
#include <QApplication>
#include <QDataWidgetMapper>
Expand Down Expand Up @@ -307,6 +308,7 @@ void SettingsDialog::reset()
m_dmpr->setModel(m_cmdl);
m_dmpr->addMapping(ui->cmdExecutableEdit, 2);
m_dmpr->addMapping(ui->cmdArgsEdit, 3);
m_dmpr->addMapping(ui->cmdOutputMode, 4, "currentIndex");
m_dmpr->toFirst();

auto fmd = new HideColumnsFilter(m_cmdl);
Expand All @@ -332,6 +334,8 @@ void SettingsDialog::reset()
}
disable_widgets(disabled);
});

ui->cmdView->selectRow(0);
}

void SettingsDialog::resetModel()
Expand Down Expand Up @@ -371,6 +375,11 @@ void SettingsDialog::resetModel()
path.removeFirst();
m_cmdl->setItem(i, 3, new QStandardItem(join_args(path)));
}

auto mode = st.value(SETT_COMMAND_MODE).value<CommandOutputMode>();
auto item = new QStandardItem();
item->setData(static_cast<int>(mode), Qt::DisplayRole);
m_cmdl->setItem(i, 4, item);
}
st.endArray();
}
Expand Down Expand Up @@ -442,10 +451,12 @@ void SettingsDialog::apply()
auto exec_path = m_cmdl->data(m_cmdl->index(i,2)).toString();
auto args = parse_arguments(m_cmdl->data(m_cmdl->index(i,3)).toString());
args.prepend(exec_path);
auto mode = m_cmdl->data(m_cmdl->index(i, 4)).toInt();

settings.setValue(SETT_COMMAND_NAME, name);
settings.setValue(SETT_COMMAND_HOTKEY, hotkey);
settings.setValue(SETT_COMMAND_CMD, args);
settings.setValue(SETT_COMMAND_MODE, QVariant::fromValue(static_cast<CommandOutputMode>(mode)));
}
settings.endArray();
emit updated();
Expand Down
121 changes: 64 additions & 57 deletions src/tagger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,69 @@ QString Tagger::text() const
return m_input.text();
}

void Tagger::addTags(QString tags, int *tag_count)
{
TagEditState state;
auto options = TagParser::FixOptions::from_settings();
options.sort = true;

// Autofix imageboard tags before comparing and assigning
util::replace_special(tags);
auto fixed_tags_list = m_input.tag_parser().fixTags(state, tags, options);
tags = util::join(fixed_tags_list);
if (tag_count) {
*tag_count = fixed_tags_list.size();
}

util::replace_special(tags);
auto current_tags = m_input.tags();

if (current_tags != tags) {

if (!util::is_hex_string(current_tags)) {

auto current_list = m_input.tags_list();
// sort current tags in case they were being edited and unsorted.
// imageboard tags are already sorted.
current_list.sort();

QString added_tags_str, removed_tags_str;
getTagDifference(current_list, fixed_tags_list, added_tags_str, removed_tags_str, true);

// Ask user what to do with tags
QMessageBox mbox(QMessageBox::Question,
tr("Fetched tags mismatch"),
tr("<p>Imageboard tags do not match current tags:"
"<p style=\"margin-left: 1em; line-height: 130%;\">"
"<code>%1</code></p></p>"
"%2%3"
"<p>Please choose what to do:</p>").arg(tags)
.arg(added_tags_str)
.arg(removed_tags_str),
QMessageBox::Save|QMessageBox::SaveAll);

mbox.addButton(QMessageBox::Cancel);
mbox.setButtonText(QMessageBox::Save, tr("Use only imageboard tags"));
mbox.setButtonText(QMessageBox::SaveAll, tr("Merge tags"));

int res = mbox.exec();

if (res == QMessageBox::Save) {
m_input.setTags(tags);
}
if (res == QMessageBox::SaveAll) {
current_tags.append(' ');
current_tags.append(tags);
m_input.setTags(current_tags);
}
} else {
// if there was only hash filename to begin with,
// just use the imageboard tags without asking
setText(tags);
}
}
}

void Tagger::resetText()
{
setText(QFileInfo(m_file_queue.current()).completeBaseName());
Expand Down Expand Up @@ -334,63 +397,7 @@ void Tagger::tagsFetched(QString file, QString tags)

// Current file might have already changed since reply came
if (currentFile() == file) {
TagEditState state;
auto options = TagParser::FixOptions::from_settings();
options.sort = true;

// Autofix imageboard tags before comparing and assigning
util::replace_special(tags);
auto fixed_tags_list = m_input.tag_parser().fixTags(state, tags, options);
tags = util::join(fixed_tags_list);
processed_tags_count = fixed_tags_list.size();

util::replace_special(tags);
auto current_tags = m_input.tags();

if (current_tags != tags) {

if (!util::is_hex_string(current_tags)) {

auto current_list = m_input.tags_list();
// sort current tags in case they were being edited and unsorted.
// imageboard tags are already sorted.
current_list.sort();

QString added_tags_str, removed_tags_str;
getTagDifference(current_list, fixed_tags_list, added_tags_str, removed_tags_str, true);

// Ask user what to do with tags
QMessageBox mbox(QMessageBox::Question,
tr("Fetched tags mismatch"),
tr("<p>Imageboard tags do not match current tags:"
"<p style=\"margin-left: 1em; line-height: 130%;\">"
"<code>%1</code></p></p>"
"%2%3"
"<p>Please choose what to do:</p>").arg(tags)
.arg(added_tags_str)
.arg(removed_tags_str),
QMessageBox::Save|QMessageBox::SaveAll);

mbox.addButton(QMessageBox::Cancel);
mbox.setButtonText(QMessageBox::Save, tr("Use only imageboard tags"));
mbox.setButtonText(QMessageBox::SaveAll, tr("Merge tags"));

int res = mbox.exec();

if (res == QMessageBox::Save) {
m_input.setTags(tags);
}
if (res == QMessageBox::SaveAll) {
current_tags.append(' ');
current_tags.append(tags);
m_input.setTags(current_tags);
}
} else {
// if there was only hash filename to begin with,
// just use the imageboard tags without asking
setText(tags);
}
}
addTags(tags, &processed_tags_count);
}

TaggerStatistics::instance().tagsFetched(overall_tags_count, processed_tags_count);
Expand Down
3 changes: 3 additions & 0 deletions src/tagger.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ class Tagger : public QWidget
/// Current tag input text.
QString text() const;

/// Ask user to add tags (maybe replacing current tags?)
void addTags(QString tags, int* tag_count=nullptr);

/// Undo tag input changes and set original tags.
void resetText();

Expand Down
100 changes: 92 additions & 8 deletions src/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,17 @@ void Window::showFileHashingProgress(QString file, int value)
statusBar()->showMessage(tr("Calculating file hash... %1% complete").arg(value));
}

void Window::showCommandExecutionProgress(QString command_name)
{
#ifdef Q_OS_WIN32
auto progress = m_win_taskbar_button.progress();
progress->setVisible(true);
progress->setMaximum(0);
progress->setValue(0);
#endif
statusBar()->showMessage(tr("Running %1...").arg(command_name));
}

void Window::hideUploadProgress()
{
#ifdef Q_OS_WIN32
Expand Down Expand Up @@ -974,6 +985,7 @@ void Window::createCommands()
auto name = settings.value(SETT_COMMAND_NAME).toString();
auto cmd = settings.value(SETT_COMMAND_CMD).toStringList();
auto hkey = settings.value(SETT_COMMAND_HOTKEY).toString();
auto mode = settings.value(SETT_COMMAND_MODE).value<CommandOutputMode>();

if(name == CMD_SEPARATOR) {
menu_commands.addSeparator();
Expand All @@ -998,7 +1010,7 @@ void Window::createCommands()
action->setShortcut(hkey);
}

connect(action, &QAction::triggered, this, [this,name,binary,cmd]()
connect(action, &QAction::triggered, this, [this,name,binary,cmd,mode]()
{
auto cmd_tmp = cmd; // NOTE: separate copy is needed instead of mutable lambda
auto to_native = [](const auto& path)
Expand Down Expand Up @@ -1026,13 +1038,85 @@ void Window::createCommands()
to_native(remove_ext(m_tagger.currentFileName())));

}
auto success = QProcess::startDetached(binary, cmd_tmp, m_tagger.currentDir());
pdbg << "QProcess::startDetached(" << binary << "," << cmd_tmp << ") =>" << success;
if(!success) {
QMessageBox::critical(this,
tr("Failed to start command"),
tr("<p>Failed to launch command <b>%1</b>:</p><p>Could not start <code>%2</code>.</p>")
.arg(name, binary));
if (mode == CommandOutputMode::Ignore) {
bool success = QProcess::startDetached(binary, cmd_tmp, m_tagger.currentDir());
pdbg << "QProcess::startDetached(" << binary << "," << cmd_tmp << ") =>" << success;
if(!success) {
QMessageBox::critical(this,
tr("Failed to start command"),
tr("<p>Failed to launch command <b>%1</b>:</p><p>Could not start <code>%2</code>.</p>")
.arg(name, binary));
}
} else {

auto proc = new QProcess{this};
proc->setProgram(binary);
proc->setArguments(cmd_tmp);
proc->setWorkingDirectory(m_tagger.currentDir());

showCommandExecutionProgress(name);

connect(&m_tagger,
&Tagger::fileOpened,
proc,
[this, proc](const QString&)
{
if (proc->state() != QProcess::NotRunning) {
disconnect(proc, nullptr, this, nullptr);
proc->terminate();
}
});

connect(proc,
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this,
[this, name, binary, mode](int exit_code, QProcess::ExitStatus exit_status)
{
Q_UNUSED(exit_code);

if (exit_status != QProcess::NormalExit) {
QMessageBox::critical(this,
tr("Failed to start command"),
tr("<p>Failed to launch command <b>%1</b>:</p><p>Could not start <code>%2</code>.</p>")
.arg(name, binary));


hideUploadProgress();
return;
}

auto proc = qobject_cast<QProcess*>(sender());
Q_ASSERT(proc);

auto tags_data = proc->readAllStandardOutput();

QTextStream in{tags_data};
in.setCodec("UTF-8");

auto tags = in.readAll().replace('\n', ' ').trimmed();
if (!tags.isEmpty()) {
auto current_tags = m_tagger.text();

switch(mode) {
case CommandOutputMode::Replace:
m_tagger.addTags(tags);
break;
case CommandOutputMode::Append:
m_tagger.setText(current_tags + " " + tags);
break;
case CommandOutputMode::Prepend:
m_tagger.setText(tags + " " + current_tags);
break;
default:
break;
}
}
hideUploadProgress();
proc->deleteLater();
}, Qt::QueuedConnection);

proc->start(QProcess::ReadOnly);

}
});
menu_commands.setEnabled(true);
Expand Down
3 changes: 3 additions & 0 deletions src/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public slots:
/// Display file hashing progress.
void showFileHashingProgress(QString file, int value);

/// Display command execution progress.
void showCommandExecutionProgress(QString command_name);

/// Hide current upload progress
void hideUploadProgress();

Expand Down
Loading

0 comments on commit 8633b96

Please sign in to comment.