qt/LedOK/wProgramManager/pagelistitem.cpp

513 lines
18 KiB
C++
Raw Normal View History

2022-08-25 18:37:24 +08:00
#include "pagelistitem.h"
#include "cfg.h"
#include "tools.h"
#include "wProgramManager/wplanlist.h"
#include "base/lodateselector.h"
#include "wProgramManager/ebase.h"
#include "wProgramManager/etext.h"
#include "wProgramManager/ephoto.h"
#include "wProgramManager/evideo.h"
#include "wProgramManager/eaudio.h"
#include "wProgramManager/egif.h"
#include "wProgramManager/edclock.h"
#include "wProgramManager/eaclock.h"
#include "wProgramManager/eenviron.h"
#include "wProgramManager/eweb.h"
#include "wProgramManager/etimer.h"
#include "wProgramManager/emultiwin.h"
#include "globaldefine.h"
#include <QMessageBox>
#include <QJsonArray>
#include <QDir>
#include <QBoxLayout>
#include <QLineEdit>
#include <QDateEdit>
class PageScene : public QGraphicsScene {
public:
PageScene(qreal x, qreal y, qreal width, qreal height, QObject *parent = nullptr) : QGraphicsScene(x, y, width, height, parent) {};
void drawBackground(QPainter *painter, const QRectF &rect) {
QGraphicsScene::drawBackground(painter, rect);
painter->fillRect(sceneRect(), Qt::black);
}
};
PageListItem::PageListItem(const QJsonObject &attr, const QString &pageDir) : mAttr(attr), mPageDir(pageDir) {
setSizeHint(QSize(0,80));
mScene = new PageScene(0, 0, gProgWidth, gProgHeight, this);
auto elements = mAttr["elements"].toArray();
foreach(auto ele, elements) {
QString type = ele["elementType"].toString();
EBase *element = nullptr;
if(type=="Text") element = new EText(ele.toObject());
else if(type=="Photo") element = EPhoto::create(ele.toObject(), this);
else if(type=="Gif") element = EGif::create(ele.toObject(), this);
else if(type=="Movie") element = EVideo::create(ele.toObject(), this);
else if(type=="Audio") element = EAudio::create(ele.toObject(), this);
else if(type=="DClock") element = new eDClock(ele.toObject());
else if(type=="AClock") element = new eAClock(ele.toObject());
else if(type=="Temp") element = new EEnviron(ele.toObject());
else if(type=="Web") element = new EWeb(ele.toObject());
else if(type=="Timer") element = new ETimer(ele.toObject());
else if(type=="Window") element = new EMultiWin(ele.toObject(), this);
if(element!=nullptr) mScene->addItem(element);
}
}
//更新页属性参数到page.json
void PageListItem::updateJson() {
if(mAttrWgt==0) return; //没有点开该页面进行编辑
QJsonArray elements;
auto items = mScene->items();
foreach(auto item, items) {
auto element = static_cast<EBase*>(item);
if(element->mMultiWin == nullptr) elements.append(element->attrJson());
}
mAttr.insert("elements", elements);
QJsonArray audios;
auto cnt = mAudiosList->count();
for(int i=0; i<cnt; i++) {
auto info = mAudiosList->item(i)->data(Qt::UserRole).value<AudioInfo>();
audios.append(QJsonObject{
{"dir", info.dir},
{"name", info.name},
{"dur", info.dur},
{"vol", info.vol}
});
}
mAttr.insert("audios", audios);
}
bool PageListItem::saveFiles() {
mPageDir = gProgDir + "/" + mAttr["name"].toString();
QDir pageQDir(mPageDir);
if(! pageQDir.exists() && ! pageQDir.mkpath(".")) return false;
QJsonArray elements;
auto items = mScene->items();
foreach(auto item, items) {
auto element = static_cast<EBase*>(item);
if(element->mMultiWin == nullptr && element->save(mPageDir)) elements.append(element->attrJson());
}
mAttr.insert("elements", elements);
if(mAttrWgt!=0) {
QJsonArray audios;
auto cnt = mAudiosList->count();
for(int i=0; i<cnt; i++) {
auto info = mAudiosList->item(i)->data(Qt::UserRole).value<AudioInfo>();
QString oldFile = info.dir + PAGEDEL_SUFFIX + "/" + info.name;
if(QFileInfo::exists(oldFile)) ;
else if(QFileInfo::exists(oldFile = info.dir + "/" + info.name)) ;
else continue;
QFile::copy(oldFile, mPageDir + "/" + info.name);
info.dir = mPageDir;
audios.append(QJsonObject{
{"dir", info.dir},
{"name", info.name},
{"dur", info.dur},
{"vol", info.vol}
});
}
mAttr.insert("audios", audios);
}
QFile file(mPageDir + "/page.json");
if(! file.open(QIODevice::WriteOnly)) {
QMessageBox::critical(gMainWin, "Write Error", mPageDir + "/page.json "+file.errorString());
return false;
}
file.write(QJsonDocument(mAttr).toJson());
file.close();
return true;
}
QWidget *PageListItem::itemWgt() {
auto wgtPage = new QWidget();
auto hBox = new QHBoxLayout(wgtPage);
mGraView = new QGraphicsView();
mGraView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mGraView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mGraView->setEnabled(false);
mGraView->setFrameShape(QFrame::NoFrame);
mGraView->setFixedSize(120, 60);
mGraView->setStyleSheet("QGraphicsView{background-color:transparent;}");
mGraView->setScene(mScene);
qreal scale = qMin(mGraView->width() / mScene->width(), mGraView->height() / mScene->height());
mGraView->scale(scale, scale);
hBox->addWidget(mGraView);
fdPlayTimes = new QLabel(QString::number(mAttr["repeat"].toInt()));
hBox->addWidget(fdPlayTimes);
hBox->addWidget(new QLabel(tr("times")));
hBox->addStretch();
return wgtPage;
}
QWidget *PageListItem::attrWgt() {
if(mAttrWgt!=0) return mAttrWgt;
mAttrWgt = new QWidget();
mAttrWgt->setStyleSheet(R"rrr(
QPushButton {
padding-left: 4px;
padding-right: 4px;
padding-top: 2px;
padding-bottom: 2px;
border-radius: 4px;
}
QPushButton:hover {
background-color: #dddddd;
}
QPushButton#bnAddPlan {
image: url(:/res/ProgramManager/EditProgram/AddPlan.png);
width: 24;
height: 24;
}
QPushButton#bnClearPlan {
image: url(:/res/ProgramManager/EditProgram/Clean.png);
width: 24;
height: 24;
}
QPushButton#bnDel {
image: url(:/res/ProgramManager/EditProgram/Delete.png);
width: 18;
height: 18;
}
QPushButton#bnAddPlan:pressed,
QPushButton#bnClearPlan:pressed,
QPushButton#bnDel:pressed {
margin-top: 1px;
margin-left: 1px;
margin-bottom: -1px;
margin-right: -1px;
}
QPushButton[ssName="weeklySelector"] {
border: 1px solid #6A838F;
width: 24;
height: 24;
}
QPushButton[ssName="weeklySelector"]:checked {
background-color: #0099cc;
}
)rrr");
auto vBox = new QVBoxLayout(mAttrWgt);
vBox->setContentsMargins(6, 0, 6, 0);
vBox->setSpacing(4);
auto hBox = new QHBoxLayout();
auto lb1 = new QLabel(tr("Page name"));
lb1->setMinimumWidth(80);
hBox->addWidget(lb1);
auto fdPageName = new QLineEdit(mAttr["name"].toString());
connect(fdPageName, &QLineEdit::textEdited, this, [this, fdPageName](const QString &text) {
bool isDupli = false;
auto listWgt = listWidget();
if(nullptr != listWgt) {
int n = listWgt->count();
for(int i=0; i<n; i++) {
auto item = static_cast<PageListItem*>(listWgt->item(i));
if(text == item->mAttr["name"].toString()) {
isDupli = true;
break;
}
}
}
if(isDupli) {
QString newName = tr("New") + QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz");
mAttr["name"] = newName;
fdPageName->setText(newName);
} else mAttr["name"] = text;
});
hBox->addWidget(fdPageName);
vBox->addLayout(hBox);
hBox = new QHBoxLayout();
lb1 = new QLabel(tr("Play times"));
lb1->setMinimumWidth(80);
hBox->addWidget(lb1);
auto fdPlayTimes = new QSpinBox();
fdPlayTimes->setRange(1, 9999);
fdPlayTimes->setValue(mAttr["repeat"].toInt());
connect(fdPlayTimes, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
mAttr["repeat"] = value;
this->fdPlayTimes->setText(QString::number(value));
});
hBox->addWidget(fdPlayTimes);
hBox->addStretch();
vBox->addLayout(hBox);
auto line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
vBox->addWidget(line);
hBox = new QHBoxLayout();
auto lb = new QLabel();
lb->setPixmap(QPixmap(":/res/ProgramManager/EditProgram/Audio.png").scaledToHeight(24, Qt::SmoothTransformation));
hBox->addWidget(lb);
hBox->addWidget(new QLabel(tr("Audios")));
hBox->addStretch();
hBox->addWidget(new QLabel(tr("Total Dur")));
auto fdTtlDur = new QLabel("0");
hBox->addWidget(fdTtlDur);
hBox->addWidget(new QLabel(tr("s")));
hBox->addStretch();
auto btnAdd = new QPushButton();
btnAdd->setIcon(QIcon(":/res/ProgramManager/EditProgram/Add.png"));
btnAdd->setProperty("style","multiTool");
mAudiosList = new QListWidget();
connect(btnAdd, &QPushButton::clicked, this, [this, fdTtlDur] {
2022-09-13 23:16:36 +08:00
auto files = QFileDialog::getOpenFileNames(gMainWin, tr("Select File"), gFileHome, EAudio::filters());
2022-08-25 18:37:24 +08:00
int durs = fdTtlDur->text().toInt();
for(int i=0; i<files.count(); i++) {
int64_t dur;
QString err = Tools::audioInfo(files[i].toUtf8(), &dur);
if(! err.isEmpty()) {
QMessageBox::critical(gMainWin, "Audio Error", err+"\n"+files[i]);
continue;
}
QFileInfo fInfo(files[i]);
AudioInfo info{fInfo.absolutePath(), fInfo.fileName(), (int)(dur/1000000)};
auto item = new QListWidgetItem(QIcon(":/res/ProgramManager/EditProgram/Audio.png"), info.name);
item->setData(Qt::UserRole, QVariant::fromValue(info));
mAudiosList->addItem(item);
if(i == files.count()-1) {
mAudiosList->setCurrentItem(item);
2022-09-13 23:16:36 +08:00
gFileHome = fInfo.absolutePath();
2022-08-25 18:37:24 +08:00
}
durs += info.dur;
mAudiosList->addItem(item);
}
fdTtlDur->setText(QString::number(durs));
});
hBox->addWidget(btnAdd);
auto btnDel = new QPushButton();
btnDel->setIcon(QIcon(":/res/ProgramManager/EditProgram/Delete.png"));
btnDel->setProperty("style","multiTool");
connect(btnDel, &QPushButton::clicked, this, [this, fdTtlDur] {
auto row = mAudiosList->currentRow();
if(row < 0) return;
int durs = fdTtlDur->text().toInt();
auto item = mAudiosList->takeItem(row);
auto info = static_cast<AudioInfo>(item->data(Qt::UserRole).value<AudioInfo>());
durs -= info.dur;
delete item;
fdTtlDur->setText(QString::number(durs));
});
hBox->addWidget(btnDel);
auto btnGoUp = new QPushButton();
btnGoUp->setIcon(QIcon(":/res/ProgramManager/EditProgram/GoUp.png"));
btnGoUp->setProperty("style","multiTool");
connect(btnGoUp, &QPushButton::clicked, this, [this] {
int row = mAudiosList->currentRow();
if(row < 1) return;
mAudiosList->insertItem(row-1, mAudiosList->takeItem(row));
mAudiosList->setCurrentRow(row-1);
});
hBox->addWidget(btnGoUp);
auto btnGoDown = new QPushButton();
btnGoDown->setIcon(QIcon(":/res/ProgramManager/EditProgram/GoDown.png"));
btnGoDown->setProperty("style","multiTool");
connect(btnGoDown, &QPushButton::clicked, this, [this] {
int row = mAudiosList->currentRow();
if(row < 0 || row > mAudiosList->count() - 2) return;
mAudiosList->insertItem(row+1, mAudiosList->takeItem(row));
mAudiosList->setCurrentRow(row+1);
});
hBox->addWidget(btnGoDown);
vBox->addLayout(hBox);
mAudiosList->setMinimumHeight(120);
mAudiosList->setIconSize(QSize(20, 20));
vBox->addWidget(mAudiosList, 1);
auto audios = mAttr["audios"].toArray();
int durs = 0;
foreach(auto audio, audios) {
AudioInfo info{audio["dir"].toString(), audio["name"].toString(), audio["dur"].toInt(), audio["vol"].toInt()};
if(info.dir.isEmpty() || info.name.isEmpty() || info.dur==0) continue;
auto item = new QListWidgetItem(QIcon(":/res/ProgramManager/EditProgram/Audio.png"), info.name);
item->setData(Qt::UserRole, QVariant::fromValue(info));
durs += info.dur;
mAudiosList->addItem(item);
}
fdTtlDur->setText(QString::number(durs));
auto wgtAudioInfo = new QWidget();
wgtAudioInfo->hide();
hBox = new QHBoxLayout(wgtAudioInfo);
hBox->setContentsMargins(0,0,0,0);
hBox->setSpacing(2);
hBox->addWidget(new QLabel(tr("Duration")));
hBox->addSpacing(4);
auto fdAudioDur = new QLabel("0");
hBox->addWidget(fdAudioDur);
hBox->addWidget(new QLabel(tr("s")));
hBox->addStretch();
hBox->addWidget(new QLabel(tr("Vol")));
auto fdVol = new QSlider(Qt::Horizontal);
fdVol->setMaximum(100);
fdVol->setMinimumWidth(120);
hBox->addWidget(fdVol);
auto fdAudioVol = new QLabel("0");
fdAudioVol->setAlignment(Qt::AlignRight);
fdAudioVol->setFixedWidth(38);
hBox->addWidget(fdAudioVol);
vBox->addWidget(wgtAudioInfo);
connect(fdVol, &QSlider::valueChanged, this, [this, fdAudioVol](int value) {
fdAudioVol->setText(QString::number(value)+"%");
auto item = mAudiosList->currentItem();
if(item==nullptr) return;
auto info = static_cast<AudioInfo>(item->data(Qt::UserRole).value<AudioInfo>());
info.vol = value;
item->setData(Qt::UserRole, QVariant::fromValue(info));
});
connect(mAudiosList, &QListWidget::currentItemChanged, this, [fdAudioDur, wgtAudioInfo, fdVol, fdAudioVol](QListWidgetItem *current, QListWidgetItem *) {
if(current==nullptr) {
wgtAudioInfo->hide();
return;
}
wgtAudioInfo->show();
auto info = static_cast<AudioInfo>(current->data(Qt::UserRole).value<AudioInfo>());
fdAudioDur->setText(QString::number(info.dur));
fdVol->setValue(info.vol);
fdAudioVol->setText(QString::number(info.vol)+"%");
});
line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
vBox->addWidget(line);
QJsonValue validDate = mAttr["validDate"];
auto wValidDate = new QCheckBox(tr("Valid Date"));
bool isDateValid = validDate["isValid"].toBool();
wValidDate->setChecked(isDateValid);
vBox->addWidget(wValidDate);
hBox = new QHBoxLayout();
auto fdStart = new QDateEdit();
fdStart->setDisplayFormat("yyyy-MM-dd");
fdStart->setEnabled(isDateValid);
fdStart->setDate(QDate::fromString(validDate["start"].toString(), "yyyy-MM-dd"));
hBox->addWidget(fdStart);
auto bnDateStart = new LoDateSelector();
bnDateStart->setEnabled(isDateValid);
connect(bnDateStart, &LoDateSelector::sDateSelected, fdStart, &QDateEdit::setDate);
hBox->addWidget(bnDateStart);
hBox->addWidget(new QLabel(""));
auto fdEnd = new QDateEdit();
fdEnd->setDisplayFormat("yyyy-MM-dd");
fdEnd->setEnabled(isDateValid);
fdEnd->setDate(QDate::fromString(validDate["end"].toString(), "yyyy-MM-dd"));
connect(fdStart, &QDateEdit::dateChanged, this, [this, wValidDate, fdStart, fdEnd](const QDate &date) {
auto end = fdEnd->date();
if(! date.isValid() || date > end) {
QMessageBox::warning(gMainWin, tr("Warning"), tr("Start Time can't be later than End Time"));
fdStart->setDate(end);
}
mAttr["validDate"] = QJsonObject{
{"isValid", wValidDate->isChecked()},
{"start", fdStart->date().toString("yyyy-MM-dd")},
{"end", end.toString("yyyy-MM-dd")}
};
});
connect(fdEnd, &QDateEdit::dateChanged, this, [this, wValidDate, fdStart, fdEnd](const QDate &date) {
QDate start = fdStart->date();
if(! date.isValid() || start > date) {
QMessageBox::warning(gMainWin, tr("Warning"), tr("End Time can't be earlier than Start Time"));
fdEnd->setDate(start);
}
mAttr["validDate"] = QJsonObject{
{"isValid", wValidDate->isChecked()},
{"start", start.toString("yyyy-MM-dd")},
{"end", fdEnd->date().toString("yyyy-MM-dd")}
};
});
hBox->addWidget(fdEnd);
auto bnDateEnd = new LoDateSelector();
bnDateEnd->setEnabled(isDateValid);
connect(bnDateEnd, &LoDateSelector::sDateSelected, fdEnd, &QDateEdit::setDate);
hBox->addWidget(bnDateEnd);
hBox->addStretch();
connect(wValidDate, &QCheckBox::toggled, this, [this, fdStart, fdEnd, bnDateStart, bnDateEnd](bool checked) {
fdStart->setEnabled(checked);
fdEnd->setEnabled(checked);
bnDateStart->setEnabled(checked);
bnDateEnd->setEnabled(checked);
mAttr["validDate"] = QJsonObject{
{"isValid", checked},
{"start", fdStart->date().toString("yyyy-MM-dd")},
{"end", fdEnd->date().toString("yyyy-MM-dd")}
};
});
vBox->addLayout(hBox);
line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
vBox->addWidget(line);
hBox = new QHBoxLayout();
hBox->setSpacing(12);
hBox->addWidget(new QLabel(tr("Plan")));
hBox->addStretch();
auto bnAddPlan = new QPushButton();
bnAddPlan->setObjectName("bnAddPlan");
hBox->addWidget(bnAddPlan);
auto bnClearPlan = new QPushButton();
bnClearPlan->setObjectName("bnClearPlan");
hBox->addWidget(bnClearPlan);
vBox->addLayout(hBox);
auto wPlans = new wPlanList();
wPlans->setStyleSheet(R"rrr(
QListWidget::item {
height: 100;
border-top: 1px solid #6A838F;
margin-right: 9px;
})rrr");
wPlans->onRestorePlan(mAttr["plans"].toArray());
connect(bnAddPlan, &QPushButton::clicked, wPlans, &wPlanList::onAddPlan);
connect(bnClearPlan, &QPushButton::clicked, wPlans, &wPlanList::clear);
connect(wPlans, &QListWidget::itemChanged, this, [this, wPlans] {
mAttr["plans"] = wPlans->plansJson();
});
vBox->addWidget(wPlans, 2);
return mAttrWgt;
}