qt/LedOK/progpanel.cpp
2023-10-23 14:58:29 +08:00

383 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "progpanel.h"
#include "globaldefine.h"
#include "gutil/qgui.h"
#include "cfg.h"
#include "player/playwin.h"
#include "program/progeditorwin.h"
#include "program/copydirthread.h"
#include <QApplication>
#include <QMessageBox>
#include <QStandardPaths>
#include <QProgressBar>
#include <QFileDialog>
#include <QLineEdit>
ProgPanel::ProgPanel(QWidget *parent) : QWidget(parent) {
setAttribute(Qt::WA_DeleteOnClose);
setAutoFillBackground(true);
QPalette pal;
pal.setBrush(QPalette::Window, QColor(0xeeeeee));
setPalette(pal);
auto vBox = new QVBoxLayout(this);
vBox->setContentsMargins(0, 0, 0, 0);
vBox->setSpacing(0);
auto hBox = new QHBoxLayout();
hBox->setContentsMargins(6,6,6,6);
hBox->setSpacing(6);
vBox->addLayout(hBox);
bnNew = new QPushButton(tr("New"));
bnNew->setFixedSize(88, 38);
bnNew->setProperty("ssType", "progManageTool");
hBox->addWidget(bnNew);
connect(bnNew, &QPushButton::clicked, this, [this] {
ProgCreateDlg dlg("", 512, 256, "", "", this);
if(dlg.exec() != QDialog::Accepted) return;
if(checkIfNameRepeated(dlg.fdName->text())) return;
QList<int> widths;
int max = 0;
auto width = dlg.fdWidth->value();
if(dlg.fdIsUltraLong->isChecked()) {
auto splitWidths = dlg.fdSplitWidths->text().split(" ", Qt::SkipEmptyParts);
int ttl = 0;
for(auto &splitWidth : splitWidths) {
int val = splitWidth.toInt();
if(val==0) continue;
if(max < val) max = val;
widths.append(val);
ttl += val;
if(ttl>=width) break;
}
if(max) {
while(ttl < width) {
widths.append(max);
ttl += max;
}
if(ttl > width) widths.last() -= ttl - width;
}
}
auto item = new ProgItem(mProgsDir, dlg.fdName->text(), width, dlg.fdHeight->value(), dlg.fdRemark->toPlainText(), widths, max, mProgTree);
item->save();//保存pro.json
if(mProgTree->fdCheckAll->checkState()==Qt::Checked) {
mProgTree->fdCheckAll->blockSignals(true);
mProgTree->fdCheckAll->setCheckState(Qt::PartiallyChecked);
mProgTree->fdCheckAll->blockSignals(false);
}
auto editor = new ProgEditorWin(item, this);
editor->show();
});
bnEdit = new QPushButton(tr("Edit"));
bnEdit->setFixedSize(QSize(88, 38));
bnEdit->setProperty("ssType", "progManageTool");
bnEdit->setEnabled(false);
hBox->addWidget(bnEdit);
connect(bnEdit, SIGNAL(clicked(bool)), this, SLOT(onEditClicked(bool)));
bnDelete = new QPushButton(tr("Delete"));
bnDelete->setFixedSize(QSize(88, 38));
bnDelete->setProperty("ssType", "progManageTool");
bnDelete->setEnabled(false);
hBox->addWidget(bnDelete);
connect(bnDelete, SIGNAL(clicked(bool)), this, SLOT(onDeleteClicked(bool)));
bnImport = new QPushButton(tr("Import"));
bnImport->setFixedSize(88, 38);
bnImport->setProperty("ssType", "progManageTool");
hBox->addWidget(bnImport);
connect(bnImport, &QPushButton::clicked, this, [this] {
auto dir = QFileDialog::getExistingDirectory(this, tr("Choose Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
if(dir.isEmpty()) return;
QString progsDir = programsDir();
if(dir.contains(progsDir, Qt::CaseInsensitive)) {
QMessageBox::warning(this, tr("Tip"), tr("The imported directory is already in the working directory, so there is no need to import it again!"));
return;
}
QStringList progDirs;
if(QFileInfo::exists(dir + "/pro.json")) progDirs.append(dir);
else {
QStringList subdirNames = QDir(dir).entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
foreach(QString subdirName, subdirNames) {
auto subdir = dir + "/" + subdirName;
if(! QFileInfo::exists(subdir + "/pro.json")) continue;
if(QFileInfo::exists(progsDir + "/" + subdirName)) {
auto res = QMessageBox::information(this, tr("Tip Info"), subdirName + tr(":solution(s) already exist.are you sure you want to overwrite the existing solution(s)?"), QMessageBox::Yes, QMessageBox::No);
if(res == QMessageBox::No) continue;
}
progDirs.append(subdir);
}
if(progDirs.isEmpty()) return;
}
ProgPortDlg dlg(this, tr("Import"));
dlg.table->setRowCount(progDirs.count());
for(int i=0; i<progDirs.count(); i++) {
dlg.table->setItem(i, 0, new QTableWidgetItem(QFileInfo(progDirs[i]).fileName()));
dlg.table->setCellWidget(i, 1, new QProgressBar);
}
connect(dlg.bnOK, &QPushButton::clicked, this, [=, &dlg] {
for(int i=0; i<progDirs.count(); i++) ((QProgressBar*)dlg.table->cellWidget(i, 1))->setMaximum(dirFileSize(progDirs[i]));
auto thread = new CopyDirThread();
thread->dirSrcs = progDirs;
thread->dirDst = progsDir;
connect(thread, &CopyDirThread::sigProgress, &dlg, [&dlg](int i, int value) {
((QProgressBar*)dlg.table->cellWidget(i, 1))->setValue(value);
});
thread->start();
});
dlg.exec();
mProgTree->clear();
QStringList progNames = QDir(mProgsDir).entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
foreach(QString pro_name, progNames) {
QFile jFile(mProgsDir + "/" + pro_name + "/pro.json");
if(! jFile.exists()) continue;
if(! jFile.open(QIODevice::ReadOnly)) continue;
auto data = jFile.readAll();
jFile.close();
m_pwPorgramItemList.append(new ProgItem(mProgsDir, QJsonDocument::fromJson(data).object(), mProgTree));
}
});
bnExport = new QPushButton(tr("Export"));
bnExport->setFixedSize(QSize(88, 38));
bnExport->setEnabled(false);
bnExport->setProperty("ssType", "progManageTool");
hBox->addWidget(bnExport);
connect(bnExport, &QPushButton::clicked, this, [=] {
int cnt = mProgTree->topLevelItemCount();
QStringList progNames;
for(int i=0; i<cnt; i++) if(mProgTree->item(i)->checkState("check") == Qt::Checked) progNames.append(((ProgItem*) mProgTree->topLevelItem(i))->mName);
if(progNames.isEmpty()) return;
ProgPortDlg dlg(this, tr("Export"));
dlg.table->setRowCount(progNames.count());
for(int i=0; i<progNames.count(); i++) {
dlg.table->setItem(i, 0, new QTableWidgetItem(progNames[i]));
dlg.table->setCellWidget(i, 1, new QProgressBar);
}
connect(dlg.bnOK, &QPushButton::clicked, this, [=, &dlg] {
QString dirDst = QFileDialog::getExistingDirectory(this, tr("Choose Directory"), "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
if(dirDst.isEmpty()) return;
auto progsDir = programsDir();
auto thread = new CopyDirThread();
for(int i=0; i<progNames.count(); i++) {
auto dir = progsDir+"/"+progNames[i];
((QProgressBar*)dlg.table->cellWidget(i, 1))->setMaximum(dirFileSize(dir));
thread->dirSrcs.append(dir);
}
thread->dirDst = dirDst;
connect(thread, &CopyDirThread::sigProgress, &dlg, [&dlg](int i, int value) {
((QProgressBar*)dlg.table->cellWidget(i, 1))->setValue(value);
});
thread->start();
});
dlg.exec();
});
bnSend = new QPushButton(tr("Send"));
bnSend->setFixedSize(QSize(88, 38));
bnSend->setProperty("ssType", "progManageTool");
bnSend->setEnabled(false);
bnSend->hide();
hBox->addWidget(bnSend);
btnPlay = new QPushButton(tr("Play")+"/"+tr("Stop"));
btnPlay->setFixedSize(QSize(88, 38));
btnPlay->setProperty("ssType", "progManageTool");
hBox->addWidget(btnPlay);
connect(btnPlay, &QPushButton::clicked, this, [this] {
if(PlayWin::self) PlayWin::self->close();
else {
int cnt = mProgTree->topLevelItemCount();
for(int i=0; i<cnt; i++) if(mProgTree->item(i)->checkState("check") == Qt::Checked) {
auto item = (ProgItem*) mProgTree->topLevelItem(i);
auto dir = mProgsDir+"/"+item->mName+"_tmp";
QFile file(dir+"/program");
if(! file.open(QIODevice::ReadOnly | QIODevice::Text)) return;
auto value = file.readAll();
file.close();
QString jsErr;
auto prog = JFrom(value, &jsErr);
if(! jsErr.isEmpty()) return;
if(item->mSplitWidths.isEmpty()) PlayWin::self = PlayWin::newIns(item->mWidth, item->mHeight, dir, prog);
else PlayWin::self = PlayWin::newIns(item->mMaxWidth, item->mHeight * item->mSplitWidths.size(), dir, prog);
break;
}
}
});
hBox->addStretch();
auto fdSearch = new QLineEdit;
fdSearch->setFixedWidth(200);
auto search = new QAction;
search->setIcon(QIcon(":/res/program/bnSearch.png"));
fdSearch->addAction(search, QLineEdit::LeadingPosition);
fdSearch->setClearButtonEnabled(true);
fdSearch->setStyleSheet("border: 2px solid #aaa;");
connect(fdSearch, &QLineEdit::textChanged, this, [this](const QString &text) {
auto cnt = mProgTree->topLevelItemCount();
for(int i=0; i<cnt; i++) {
auto item = mProgTree->item(i);
item->setHidden(! (text.isEmpty() || item->text("name").contains(text) || item->text("resolution").contains(text)));
}
});
hBox->addWidget(fdSearch);
auto table = new LoQTreeWidget;
table->addCol("#", "", 20);
table->addCol("check", "", 36).margin(6);
table->addCol("name", "", 300, QHeaderView::Stretch);
table->addCol("resolution", "", 150, QHeaderView::Stretch);
table->addCol("size", "", 100, QHeaderView::Stretch);
table->addCol("lasttime", "", 180);
table->addCol("usb", "", 80);
table->addCol("send", "", 80);
table->setDefs()->setHeaderAlignC();
table->addFd();
table->minRowHeight = 36;
table->setSelectionMode(QAbstractItemView::NoSelection);
table->setSortingEnabled(true);
connect(table, &LoQTreeWidget::selChanged, this, [=] {
auto en = table->fdCheckAll->checkState()!=Qt::Unchecked;
bnEdit->setEnabled(en);
bnDelete->setEnabled(en);
bnExport->setEnabled(en);
bnSend->setEnabled(en);
});
vBox->addWidget(mProgTree = table);
QString doc_path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
if(!doc_path.isEmpty()) {
QString app_path = doc_path + "/" + QApplication::applicationName();
mProgsDir = app_path + "/NPrograms";
if(!QFileInfo::exists(mProgsDir)) QDir(app_path).mkdir("NPrograms");
}
//查找根路径下的项目文件夹查找文件夹下的节目pro.json信息包括节目名称大小像素备注等信息
if(!mProgsDir.isEmpty()) {
QDir root_dir(mProgsDir);
QStringList pro_list = root_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
foreach(QString pro_name, pro_list) {
QDir pro_dir(mProgsDir + "/" + pro_name);
if(pro_dir.exists("pro.json")) {
QFile fPro(pro_dir.path() + "/pro.json");
fPro.open(QIODevice::ReadOnly);
QJsonDocument pro = QJsonDocument::fromJson(fPro.readAll());
fPro.close();
m_pwPorgramItemList.append(new ProgItem(mProgsDir, pro.object(), mProgTree));
}
}
}
QSettings settings;
if(settings.value("ProgramListSortOrder").toInt()==0) mProgTree->sortByColumn(settings.value("ProgramListSortColumn").toInt(),Qt::SortOrder::AscendingOrder);
else mProgTree->sortByColumn(settings.value("ProgramListSortColumn").toInt(),Qt::SortOrder::DescendingOrder);
transUi();
}
void ProgPanel::changeEvent(QEvent *event) {
QWidget::changeEvent(event);
if(event->type() == QEvent::LanguageChange) transUi();
}
void ProgPanel::transUi() {
mProgTree->headerItem()->setText("name"**mProgTree, tr("Name"));
mProgTree->headerItem()->setText("resolution"**mProgTree, tr("Resolution"));
mProgTree->headerItem()->setText("size"**mProgTree, tr("File Size"));
mProgTree->headerItem()->setText("lasttime"**mProgTree, tr("Last Modify"));
mProgTree->headerItem()->setText("usb"**mProgTree, tr("USB Update"));
mProgTree->headerItem()->setText("send"**mProgTree, tr("Publish"));
bnNew->setText(tr("New"));
bnEdit->setText(tr("Edit"));
bnDelete->setText(tr("Delete"));
bnImport->setText(tr("Import"));
bnExport->setText(tr("Export"));
bnSend->setText(tr("Send"));
btnPlay->setText(tr("Play")+"/"+tr("Stop"));
}
void ProgPanel::onEditClicked(bool){
int cnt = mProgTree->topLevelItemCount();
for(int i=0; i<cnt; i++) {
if(mProgTree->item(i)->checkState("check") == Qt::Checked) {
auto item = static_cast<ProgItem*>(mProgTree->topLevelItem(i));
auto editor = new ProgEditorWin(item, this);
editor->show();
break;
}
}
}
bool ProgPanel::checkIfNameRepeated(const QString &name, QTreeWidgetItem *skip){
int cnt = mProgTree->topLevelItemCount();
for(int i=0; i<cnt; i++) {
auto item = static_cast<ProgItem*>(mProgTree->topLevelItem(i));
if(item == skip) continue;
if(name == item->mName) {
QMessageBox::warning(this, tr("Warning"), tr("Program name conflicted"));
return true;
}
}
return false;
}
void ProgPanel::onCreateNewProgramOnOpenEditProgramWidget(QString name, QSize res, QString remarks, QList<int> &splitWidths, int max)
{
if(checkIfNameRepeated(name)) return;
auto item = new ProgItem(mProgsDir, name, res.width(), res.height(), remarks, splitWidths, max, mProgTree);
item->save();//保存pro.json
if(mProgTree->fdCheckAll->checkState()==Qt::Checked) {
mProgTree->fdCheckAll->blockSignals(true);
mProgTree->fdCheckAll->setCheckState(Qt::PartiallyChecked);
mProgTree->fdCheckAll->blockSignals(false);
}
auto editor = new ProgEditorWin(item, this);
editor->show();
}
void ProgPanel::onDeleteClicked(bool){
auto res = QMessageBox::information(this, tr("Tip Info"), tr("You will delete the selected solution(s),are you sure?"), QMessageBox::Ok, QMessageBox::Cancel);
if(res == QMessageBox::Ok) {
for(int i=0; i<mProgTree->topLevelItemCount(); i++) if(mProgTree->item(i)->checkState("check") == Qt::Checked) {
auto item = (ProgItem*) mProgTree->topLevelItem(i--);
item->del();
delete item;
}
mProgTree->fdCheckAll->blockSignals(true);
mProgTree->fdCheckAll->setCheckState(Qt::Unchecked);
mProgTree->fdCheckAll->blockSignals(false);
emit mProgTree->selChanged();
}
}
ProgPortDlg::ProgPortDlg(QWidget *parent, QString title) : QDialog(parent) {
#ifdef Q_OS_WIN
setWindowFlag(Qt::WindowContextHelpButtonHint, 0);
#endif
resize(600, 400);
setWindowTitle(title);
auto vBox = new VBox(this);
vBox->setContentsMargins(0, 0, 0, 6);
table = new QTableWidget(0, 2);
table->setSelectionMode(QTableWidget::NoSelection);
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
table->setAlternatingRowColors(true);
table->horizontalHeader()->setBackgroundRole(QPalette::Window);
table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
table->horizontalHeader()->resizeSection(1, 200);
table->setHorizontalHeaderLabels({tr("Solution Name"), tr("Progress")});
vBox->addWidget(table);
auto hBox = new HBox(vBox);
hBox->addStretch();
bnOK = new QPushButton(title);
hBox->addWidget(bnOK);
auto bnDone = new QPushButton(tr("Done"));
connect(bnDone, &QPushButton::clicked, this, &QDialog::accept);
hBox->addWidget(bnDone);
}