Added database settings view
This commit is contained in:
@@ -24,6 +24,7 @@ lms_approot_DATA = \
|
|||||||
approot/playlist.xml \
|
approot/playlist.xml \
|
||||||
approot/releases.xml \
|
approot/releases.xml \
|
||||||
approot/release.xml \
|
approot/release.xml \
|
||||||
|
approot/settings.xml \
|
||||||
approot/templates.xml \
|
approot/templates.xml \
|
||||||
approot/tracks.xml
|
approot/tracks.xml
|
||||||
|
|
||||||
|
|||||||
@@ -17,4 +17,19 @@
|
|||||||
<message id="msg-filter-value">Value</message>
|
<message id="msg-filter-value">Value</message>
|
||||||
|
|
||||||
<message id="msg-show-more">Show more</message>
|
<message id="msg-show-more">Show more</message>
|
||||||
|
|
||||||
|
<message id="msg-settings">Settings</message>
|
||||||
|
<message id="msg-settings-database">Database</message>
|
||||||
|
<message id="msg-settings-media-directory">Media root directory</message>
|
||||||
|
<message id="msg-settings-update-period">Update period</message>
|
||||||
|
<message id="msg-settings-update-start-time">Update start time</message>
|
||||||
|
<message id="msg-update-period-never">Never</message>
|
||||||
|
<message id="msg-update-period-daily">Daily</message>
|
||||||
|
<message id="msg-update-period-weekly">Weekly</message>
|
||||||
|
<message id="msg-update-period-monthly">Monthly</message>
|
||||||
|
<message id="msg-error-not-a-directory">Not a directory</message>
|
||||||
|
<message id="msg-btn-apply">Apply</message>
|
||||||
|
<message id="msg-btn-discard">Discard</message>
|
||||||
|
|
||||||
|
|
||||||
</messages>
|
</messages>
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<messages xmlns:if="Wt.WTemplate.conditions">
|
||||||
|
<!--FORMS message blocks-->
|
||||||
|
|
||||||
|
<message id="template-settings-database">
|
||||||
|
<legend>${tr:msg-settings-database}</legend>
|
||||||
|
<div class="form-horizontal">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="${id:media-directory}">
|
||||||
|
${tr:msg-settings-media-directory}
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-5">
|
||||||
|
${media-directory}
|
||||||
|
</div>
|
||||||
|
<div class="help-block col-sm-5">
|
||||||
|
${media-directory-info}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="${id:update-period}">
|
||||||
|
${tr:msg-settings-update-period}
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-5">
|
||||||
|
${update-period}
|
||||||
|
</div>
|
||||||
|
<div class="help-block col-sm-5">
|
||||||
|
${update-period-info}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="${id:update-start-time}">
|
||||||
|
${tr:msg-settings-update-start-time}
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-5">
|
||||||
|
${update-start-time}
|
||||||
|
</div>
|
||||||
|
<div class="help-block col-sm-5">
|
||||||
|
${update-start-time-info}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
${apply-btn class="btn-primary"} ${discard-btn}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</message>
|
||||||
|
|
||||||
|
</messages>
|
||||||
@@ -39,6 +39,7 @@ lms_SOURCES = \
|
|||||||
$(srcdir)/ui/resource/AvConvTranscodeStreamResource.cpp \
|
$(srcdir)/ui/resource/AvConvTranscodeStreamResource.cpp \
|
||||||
$(srcdir)/ui/resource/ImageResource.cpp \
|
$(srcdir)/ui/resource/ImageResource.cpp \
|
||||||
$(srcdir)/ui/resource/TranscodeResource.cpp \
|
$(srcdir)/ui/resource/TranscodeResource.cpp \
|
||||||
|
$(srcdir)/ui/settings/DatabaseView.cpp \
|
||||||
$(srcdir)/utils/Config.cpp \
|
$(srcdir)/utils/Config.cpp \
|
||||||
$(srcdir)/utils/Logger.cpp \
|
$(srcdir)/utils/Logger.cpp \
|
||||||
$(srcdir)/utils/Path.cpp \
|
$(srcdir)/utils/Path.cpp \
|
||||||
|
|||||||
@@ -127,10 +127,6 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
Scanner::MediaScanner scanner(*connectionPool);
|
Scanner::MediaScanner scanner(*connectionPool);
|
||||||
|
|
||||||
// Instanciate the updater's event handler. Order is important
|
|
||||||
// dbUpdater.registerEventHandler(std::make_shared<Database::FeatureExtractor>());
|
|
||||||
// dbUpdater.registerEventHandler(std::make_shared<Database::HighLevelCluster>());
|
|
||||||
|
|
||||||
// bind entry point
|
// bind entry point
|
||||||
server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create,
|
server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create,
|
||||||
_1, boost::ref(*connectionPool)));
|
_1, boost::ref(*connectionPool)));
|
||||||
|
|||||||
@@ -107,6 +107,28 @@ namespace Scanner {
|
|||||||
|
|
||||||
using namespace Database;
|
using namespace Database;
|
||||||
|
|
||||||
|
UpdatePeriod
|
||||||
|
getUpdatePeriod(Wt::Dbo::Session& session)
|
||||||
|
{
|
||||||
|
return static_cast<UpdatePeriod>(Setting::getInt(session, "update_period", static_cast<int>(UpdatePeriod::Never)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setUpdatePeriod(Wt::Dbo::Session& session, UpdatePeriod updatePeriod)
|
||||||
|
{
|
||||||
|
Setting::setInt(session, "update_period", static_cast<int>(updatePeriod));
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::posix_time::time_duration getUpdateStartTime(Wt::Dbo::Session& session)
|
||||||
|
{
|
||||||
|
return Setting::getDuration(session, "update_start_time");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUpdateStartTime(Wt::Dbo::Session& session, boost::posix_time::time_duration startTime)
|
||||||
|
{
|
||||||
|
Setting::setDuration(session, "update_start_time", startTime);
|
||||||
|
}
|
||||||
|
|
||||||
MediaScanner::MediaScanner(Wt::Dbo::SqlConnectionPool& connectionPool)
|
MediaScanner::MediaScanner(Wt::Dbo::SqlConnectionPool& connectionPool)
|
||||||
: _running(false),
|
: _running(false),
|
||||||
_scheduleTimer(_ioService),
|
_scheduleTimer(_ioService),
|
||||||
@@ -159,31 +181,35 @@ MediaScanner::processNextJob(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
|
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
|
||||||
boost::posix_time::time_duration startTime = Setting::getDuration(_db.getSession(), "update_start_time");
|
boost::posix_time::time_duration startTime = getUpdateStartTime(_db.getSession());
|
||||||
|
|
||||||
boost::gregorian::date nextScanDate;
|
boost::gregorian::date nextScanDate;
|
||||||
|
|
||||||
std::string updatePeriod = Setting::getString(_db.getSession(), "update_period", "never");
|
switch ( getUpdatePeriod(_db.getSession()) )
|
||||||
if (updatePeriod == "daily")
|
|
||||||
{
|
{
|
||||||
|
case UpdatePeriod::Daily:
|
||||||
if (now.time_of_day() < startTime)
|
if (now.time_of_day() < startTime)
|
||||||
nextScanDate = now.date();
|
nextScanDate = now.date();
|
||||||
else
|
else
|
||||||
nextScanDate = getNextDay(now.date());
|
nextScanDate = getNextDay(now.date());
|
||||||
}
|
break;
|
||||||
else if (updatePeriod == "weekly")
|
|
||||||
{
|
case UpdatePeriod::Weekly:
|
||||||
if (now.time_of_day() < startTime && now.date().day_of_week() == 1)
|
if (now.time_of_day() < startTime && now.date().day_of_week() == 1)
|
||||||
nextScanDate = now.date();
|
nextScanDate = now.date();
|
||||||
else
|
else
|
||||||
nextScanDate = getNextMonday(now.date());
|
nextScanDate = getNextMonday(now.date());
|
||||||
}
|
break;
|
||||||
else if (updatePeriod == "monthly")
|
|
||||||
{
|
case UpdatePeriod::Monthly:
|
||||||
if (now.time_of_day() < startTime && now.date().day() == 1)
|
if (now.time_of_day() < startTime && now.date().day() == 1)
|
||||||
nextScanDate = now.date();
|
nextScanDate = now.date();
|
||||||
else
|
else
|
||||||
nextScanDate = getNextFirstOfMonth(now.date());
|
nextScanDate = getNextFirstOfMonth(now.date());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UpdatePeriod::Never:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nextScanDate.is_special())
|
if (!nextScanDate.is_special())
|
||||||
|
|||||||
@@ -30,6 +30,18 @@
|
|||||||
|
|
||||||
namespace Scanner {
|
namespace Scanner {
|
||||||
|
|
||||||
|
enum class UpdatePeriod {
|
||||||
|
Never = 0,
|
||||||
|
Daily,
|
||||||
|
Weekly,
|
||||||
|
Monthly
|
||||||
|
};
|
||||||
|
|
||||||
|
UpdatePeriod getUpdatePeriod(Wt::Dbo::Session& session);
|
||||||
|
void setUpdatePeriod(Wt::Dbo::Session& session, UpdatePeriod updatePeriod);
|
||||||
|
|
||||||
|
boost::posix_time::time_duration getUpdateStartTime(Wt::Dbo::Session& session);
|
||||||
|
void setUpdateStartTime(Wt::Dbo::Session& session, boost::posix_time::time_duration);
|
||||||
|
|
||||||
class MediaScanner
|
class MediaScanner
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <Wt/WNavigationBar>
|
#include <Wt/WNavigationBar>
|
||||||
#include <Wt/WStackedWidget>
|
#include <Wt/WStackedWidget>
|
||||||
#include <Wt/WMenu>
|
#include <Wt/WMenu>
|
||||||
|
#include <Wt/WPopupMenu>
|
||||||
#include <Wt/WText>
|
#include <Wt/WText>
|
||||||
|
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
@@ -34,6 +35,8 @@
|
|||||||
#include "MediaPlayer.hpp"
|
#include "MediaPlayer.hpp"
|
||||||
#include "PlaylistView.hpp"
|
#include "PlaylistView.hpp"
|
||||||
|
|
||||||
|
#include "settings/DatabaseView.hpp"
|
||||||
|
|
||||||
#include "LmsApplication.hpp"
|
#include "LmsApplication.hpp"
|
||||||
|
|
||||||
namespace skeletons {
|
namespace skeletons {
|
||||||
@@ -86,6 +89,7 @@ LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnecti
|
|||||||
messageResourceBundle().use(appRoot() + "playlist");
|
messageResourceBundle().use(appRoot() + "playlist");
|
||||||
messageResourceBundle().use(appRoot() + "release");
|
messageResourceBundle().use(appRoot() + "release");
|
||||||
messageResourceBundle().use(appRoot() + "releases");
|
messageResourceBundle().use(appRoot() + "releases");
|
||||||
|
messageResourceBundle().use(appRoot() + "settings");
|
||||||
messageResourceBundle().use(appRoot() + "tracks");
|
messageResourceBundle().use(appRoot() + "tracks");
|
||||||
messageResourceBundle().use(appRoot() + "templates");
|
messageResourceBundle().use(appRoot() + "templates");
|
||||||
|
|
||||||
@@ -179,7 +183,7 @@ enum IdxRoot
|
|||||||
IdxHome = 0,
|
IdxHome = 0,
|
||||||
IdxExplore,
|
IdxExplore,
|
||||||
IdxPlaylist,
|
IdxPlaylist,
|
||||||
IdxSettings,
|
IdxSettingsDatabase,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -196,7 +200,7 @@ handlePathChange(Wt::WStackedWidget* stack)
|
|||||||
{ "/release", IdxExplore },
|
{ "/release", IdxExplore },
|
||||||
{ "/tracks", IdxExplore },
|
{ "/tracks", IdxExplore },
|
||||||
{ "/playlist", IdxPlaylist },
|
{ "/playlist", IdxPlaylist },
|
||||||
{ "/settings", IdxSettings },
|
{ "/settings/database", IdxSettingsDatabase },
|
||||||
};
|
};
|
||||||
|
|
||||||
LMS_LOG(UI, DEBUG) << "Internal path changed to '" << wApp->internalPath() << "'";
|
LMS_LOG(UI, DEBUG) << "Internal path changed to '" << wApp->internalPath() << "'";
|
||||||
@@ -237,7 +241,6 @@ LmsApplication::handleAuthEvent(void)
|
|||||||
auto navbar = new Wt::WNavigationBar();
|
auto navbar = new Wt::WNavigationBar();
|
||||||
navbar->setTitle("LMS", Wt::WLink(Wt::WLink::InternalPath, "/home"));
|
navbar->setTitle("LMS", Wt::WLink(Wt::WLink::InternalPath, "/home"));
|
||||||
navbar->setResponsive(true);
|
navbar->setResponsive(true);
|
||||||
// navbar->setStyleClass("main-nav");
|
|
||||||
|
|
||||||
main->bindWidget("navbar-top", navbar);
|
main->bindWidget("navbar-top", navbar);
|
||||||
|
|
||||||
@@ -262,6 +265,18 @@ LmsApplication::handleAuthEvent(void)
|
|||||||
menuItem->setLink(Wt::WLink(Wt::WLink::InternalPath, "/playlist"));
|
menuItem->setLink(Wt::WLink(Wt::WLink::InternalPath, "/playlist"));
|
||||||
menuItem->setSelectable(false);
|
menuItem->setSelectable(false);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto menuItem = menu->insertItem(4, Wt::WString::tr("msg-settings"));
|
||||||
|
menuItem->setSelectable(false);
|
||||||
|
|
||||||
|
Wt::WPopupMenu *settings = new Wt::WPopupMenu();
|
||||||
|
auto dbSettings = settings->insertItem(0, Wt::WString::tr("msg-settings-database"));
|
||||||
|
dbSettings->setLink(Wt::WLink(Wt::WLink::InternalPath, "/settings/database"));
|
||||||
|
dbSettings->setSelectable(false);
|
||||||
|
|
||||||
|
menuItem->setMenu(settings);
|
||||||
|
}
|
||||||
|
|
||||||
navbar->addMenu(menu);
|
navbar->addMenu(menu);
|
||||||
|
|
||||||
// Contents
|
// Contents
|
||||||
@@ -275,7 +290,9 @@ LmsApplication::handleAuthEvent(void)
|
|||||||
|
|
||||||
auto playlist = new Playlist();
|
auto playlist = new Playlist();
|
||||||
mainStack->addWidget(playlist);
|
mainStack->addWidget(playlist);
|
||||||
mainStack->addWidget(new Wt::WText("SETTINGS"));
|
|
||||||
|
auto databaseSettings = new Settings::DatabaseView();
|
||||||
|
mainStack->addWidget(databaseSettings);
|
||||||
|
|
||||||
explore->tracksAdd.connect(std::bind([=] (std::vector<Database::Track::pointer> tracks)
|
explore->tracksAdd.connect(std::bind([=] (std::vector<Database::Track::pointer> tracks)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,13 +38,14 @@ DirectoryValidator::validate(const Wt::WString& input) const
|
|||||||
boost::filesystem::path p(input.toUTF8());
|
boost::filesystem::path p(input.toUTF8());
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
|
|
||||||
|
// TODO check rights
|
||||||
bool res = boost::filesystem::is_directory(p, ec);
|
bool res = boost::filesystem::is_directory(p, ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
return Wt::WValidator::Result(Wt::WValidator::Invalid, ec.message());
|
return Wt::WValidator::Result(Wt::WValidator::Invalid, ec.message()); // TODO translate common errors
|
||||||
else if (res)
|
else if (res)
|
||||||
return Wt::WValidator::Result(Wt::WValidator::Valid);
|
return Wt::WValidator::Result(Wt::WValidator::Valid);
|
||||||
else
|
else
|
||||||
return Wt::WValidator::Result(Wt::WValidator::Invalid, "Not a directory");
|
return Wt::WValidator::Result(Wt::WValidator::Invalid, Wt::WString::tr("msg-error-not-a-directory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Wt/WString>
|
||||||
|
#include <Wt/WPushButton>
|
||||||
|
#include <Wt/WComboBox>
|
||||||
|
#include <Wt/WMessageBox>
|
||||||
|
#include <Wt/WLineEdit>
|
||||||
|
|
||||||
|
#include <Wt/WFormModel>
|
||||||
|
#include <Wt/WStringListModel>
|
||||||
|
|
||||||
|
#include "common/DirectoryValidator.hpp"
|
||||||
|
#include "database/MediaDirectory.hpp"
|
||||||
|
#include "scanner/MediaScanner.hpp"
|
||||||
|
#include "utils/Logger.hpp"
|
||||||
|
|
||||||
|
#include "LmsApplication.hpp"
|
||||||
|
|
||||||
|
#include "DatabaseView.hpp"
|
||||||
|
|
||||||
|
namespace UserInterface {
|
||||||
|
namespace Settings {
|
||||||
|
|
||||||
|
using namespace Database;
|
||||||
|
|
||||||
|
class DatabaseModel : public Wt::WFormModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Associate each field with a unique string literal.
|
||||||
|
static const Field MediaDirectoryField;
|
||||||
|
static const Field UpdatePeriodField;
|
||||||
|
static const Field UpdateStartTimeField;
|
||||||
|
|
||||||
|
DatabaseModel(Wt::WObject *parent = 0)
|
||||||
|
: Wt::WFormModel(parent)
|
||||||
|
{
|
||||||
|
initializeModels();
|
||||||
|
|
||||||
|
addField(MediaDirectoryField);
|
||||||
|
addField(UpdatePeriodField);
|
||||||
|
addField(UpdateStartTimeField);
|
||||||
|
|
||||||
|
DirectoryValidator* dirValidator = new DirectoryValidator();
|
||||||
|
dirValidator->setMandatory(true);
|
||||||
|
setValidator(MediaDirectoryField, dirValidator);
|
||||||
|
|
||||||
|
setValidator(UpdatePeriodField, createMandatoryValidator());
|
||||||
|
setValidator(UpdateStartTimeField, createMandatoryValidator());
|
||||||
|
|
||||||
|
// populate the model with initial data
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
Wt::WAbstractItemModel *updatePeriodModel() { return _updatePeriodModel; }
|
||||||
|
Wt::WAbstractItemModel *updateStartTimeModel() { return _updateStartTimeModel; }
|
||||||
|
|
||||||
|
void loadData()
|
||||||
|
{
|
||||||
|
using namespace Database;
|
||||||
|
|
||||||
|
Wt::Dbo::Transaction transaction(DboSession());
|
||||||
|
|
||||||
|
std::vector<MediaDirectory::pointer> mediaDirectories = MediaDirectory::getAll(DboSession());
|
||||||
|
if (!mediaDirectories.empty())
|
||||||
|
setValue(MediaDirectoryField, mediaDirectories.front()->getPath().string());
|
||||||
|
|
||||||
|
auto periodRow = getUpdatePeriodModelRow( Scanner::getUpdatePeriod(DboSession()) );
|
||||||
|
if (periodRow)
|
||||||
|
setValue(UpdatePeriodField, updatePeriodString(*periodRow));
|
||||||
|
|
||||||
|
auto startTimeRow = getUpdateStartTimeModelRow( Scanner::getUpdateStartTime(DboSession()) );
|
||||||
|
if (startTimeRow)
|
||||||
|
setValue(UpdateStartTimeField, updateStartTimeString(*startTimeRow) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveData()
|
||||||
|
{
|
||||||
|
Wt::Dbo::Transaction transaction(DboSession());
|
||||||
|
|
||||||
|
MediaDirectory::eraseAll(DboSession());
|
||||||
|
MediaDirectory::create(DboSession(), boost::any_cast<Wt::WString>(value(MediaDirectoryField)).toUTF8());
|
||||||
|
|
||||||
|
auto updatePeriodRow = getUpdatePeriodModelRow( boost::any_cast<Wt::WString>(value(UpdatePeriodField)));
|
||||||
|
assert(updatePeriodRow);
|
||||||
|
Scanner::setUpdatePeriod(DboSession(), updatePeriod(*updatePeriodRow));
|
||||||
|
|
||||||
|
auto startTimeRow = getUpdateStartTimeModelRow( boost::any_cast<Wt::WString>(value(UpdateStartTimeField)));
|
||||||
|
assert(startTimeRow);
|
||||||
|
Scanner::setUpdateStartTime(DboSession(), updateStartTime(*startTimeRow));
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<int> getUpdatePeriodModelRow(Wt::WString value)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _updatePeriodModel->rowCount(); ++i)
|
||||||
|
{
|
||||||
|
if (updatePeriodString(i) == value)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<int> getUpdatePeriodModelRow(Scanner::UpdatePeriod period)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _updatePeriodModel->rowCount(); ++i)
|
||||||
|
{
|
||||||
|
if (updatePeriod(i) == period)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
Scanner::UpdatePeriod updatePeriod(int row)
|
||||||
|
{
|
||||||
|
return boost::any_cast<Scanner::UpdatePeriod>
|
||||||
|
(_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::UserRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
Wt::WString updatePeriodString(int row)
|
||||||
|
{
|
||||||
|
return boost::any_cast<Wt::WString>
|
||||||
|
(_updatePeriodModel->data(_updatePeriodModel->index(row, 0), Wt::DisplayRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boost::optional<int> getUpdateStartTimeModelRow(Wt::WString value)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _updateStartTimeModel->rowCount(); ++i)
|
||||||
|
{
|
||||||
|
if (updateStartTimeString(i) == value)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::optional<int> getUpdateStartTimeModelRow(boost::posix_time::time_duration startTime)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _updateStartTimeModel->rowCount(); ++i)
|
||||||
|
{
|
||||||
|
if (updateStartTime(i) == startTime)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::posix_time::time_duration updateStartTime(int row)
|
||||||
|
{
|
||||||
|
return boost::any_cast<boost::posix_time::time_duration>
|
||||||
|
(_updateStartTimeModel->data(_updateStartTimeModel->index(row, 0), Wt::UserRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
Wt::WString updateStartTimeString(int row)
|
||||||
|
{
|
||||||
|
return boost::any_cast<Wt::WString>
|
||||||
|
(_updateStartTimeModel->data(_updateStartTimeModel->index(row, 0), Wt::DisplayRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void initializeModels() {
|
||||||
|
|
||||||
|
_updatePeriodModel = new Wt::WStringListModel(this);
|
||||||
|
|
||||||
|
_updatePeriodModel->addString(Wt::WString::tr("msg-update-period-never"));
|
||||||
|
_updatePeriodModel->setData(0, 0, Scanner::UpdatePeriod::Never, Wt::UserRole);
|
||||||
|
|
||||||
|
_updatePeriodModel->addString(Wt::WString::tr("msg-update-period-daily"));
|
||||||
|
_updatePeriodModel->setData(1, 0, Scanner::UpdatePeriod::Daily, Wt::UserRole);
|
||||||
|
|
||||||
|
_updatePeriodModel->addString(Wt::WString::tr("msg-update-period-weekly"));
|
||||||
|
_updatePeriodModel->setData(2, 0, Scanner::UpdatePeriod::Weekly, Wt::UserRole);
|
||||||
|
|
||||||
|
_updatePeriodModel->addString(Wt::WString::tr("msg-update-period-monthly"));
|
||||||
|
_updatePeriodModel->setData(3, 0, Scanner::UpdatePeriod::Monthly, Wt::UserRole);
|
||||||
|
|
||||||
|
_updateStartTimeModel = new Wt::WStringListModel(this);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < 24; ++i)
|
||||||
|
{
|
||||||
|
boost::posix_time::time_duration dur = boost::posix_time::hours(i);
|
||||||
|
|
||||||
|
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%H:%M");
|
||||||
|
facet->time_duration_format("%H:%M");
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss.imbue(std::locale(oss.getloc(), facet));
|
||||||
|
|
||||||
|
oss << dur;
|
||||||
|
|
||||||
|
_updateStartTimeModel->addString( oss.str() );
|
||||||
|
_updateStartTimeModel->setData(i, 0, dur, Wt::UserRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Wt::WValidator *createMandatoryValidator()
|
||||||
|
{
|
||||||
|
Wt::WValidator* v = new Wt::WValidator();
|
||||||
|
v->setMandatory(true);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wt::WStringListModel* _updatePeriodModel;
|
||||||
|
Wt::WStringListModel* _updateStartTimeModel;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const Wt::WFormModel::Field DatabaseModel::MediaDirectoryField = "media-directory";
|
||||||
|
const Wt::WFormModel::Field DatabaseModel::UpdatePeriodField = "update-period";
|
||||||
|
const Wt::WFormModel::Field DatabaseModel::UpdateStartTimeField = "update-start-time";
|
||||||
|
|
||||||
|
|
||||||
|
DatabaseView::DatabaseView(Wt::WContainerWidget *parent)
|
||||||
|
: Wt::WTemplateFormView(parent)
|
||||||
|
{
|
||||||
|
_model = new DatabaseModel(this);
|
||||||
|
|
||||||
|
setTemplateText(tr("template-settings-database"));
|
||||||
|
addFunction("tr", &WTemplate::Functions::tr);
|
||||||
|
addFunction("id", &WTemplate::Functions::id);
|
||||||
|
|
||||||
|
// Media Directory
|
||||||
|
Wt::WLineEdit *mediaDirectoryEdit = new Wt::WLineEdit();
|
||||||
|
setFormWidget(DatabaseModel::MediaDirectoryField, mediaDirectoryEdit);
|
||||||
|
|
||||||
|
// Update Period
|
||||||
|
Wt::WComboBox *updatePeriodCB = new Wt::WComboBox();
|
||||||
|
setFormWidget(DatabaseModel::UpdatePeriodField, updatePeriodCB);
|
||||||
|
updatePeriodCB->setModel(_model->updatePeriodModel());
|
||||||
|
|
||||||
|
// Update Start Time
|
||||||
|
Wt::WComboBox *updateStartTimeCB = new Wt::WComboBox();
|
||||||
|
setFormWidget(DatabaseModel::UpdateStartTimeField, updateStartTimeCB);
|
||||||
|
updateStartTimeCB->setModel(_model->updateStartTimeModel());
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
|
||||||
|
Wt::WPushButton *saveBtn = new Wt::WPushButton(Wt::WString::tr("msg-btn-apply"));
|
||||||
|
bindWidget("apply-btn", saveBtn);
|
||||||
|
saveBtn->setStyleClass("btn-primary");
|
||||||
|
|
||||||
|
Wt::WPushButton *discardBtn = new Wt::WPushButton(Wt::WString::tr("msg-btn-discard"));
|
||||||
|
bindWidget("discard-btn", discardBtn);
|
||||||
|
|
||||||
|
saveBtn->clicked().connect(this, &DatabaseView::processSave);
|
||||||
|
discardBtn->clicked().connect(this, &DatabaseView::processDiscard);
|
||||||
|
|
||||||
|
updateView(_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DatabaseView::processDiscard()
|
||||||
|
{
|
||||||
|
_model->loadData();
|
||||||
|
_model->validate();
|
||||||
|
updateView(_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DatabaseView::processSave()
|
||||||
|
{
|
||||||
|
updateModel(_model);
|
||||||
|
|
||||||
|
if (_model->validate()) {
|
||||||
|
_model->saveData();
|
||||||
|
|
||||||
|
// _sigChanged.emit();
|
||||||
|
}
|
||||||
|
// Udate the view: Delete any validation message in the view, etc.
|
||||||
|
updateView(_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Settings
|
||||||
|
} // namespace UserInterface
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Emeric Poupon
|
||||||
|
*
|
||||||
|
* This file is part of LMS.
|
||||||
|
*
|
||||||
|
* LMS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* LMS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Wt/WContainerWidget>
|
||||||
|
#include <Wt/WTemplateFormView>
|
||||||
|
#include <Wt/WText>
|
||||||
|
#include <Wt/WSignal>
|
||||||
|
|
||||||
|
namespace UserInterface {
|
||||||
|
namespace Settings {
|
||||||
|
|
||||||
|
class DatabaseModel;
|
||||||
|
|
||||||
|
class DatabaseView : public Wt::WTemplateFormView
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DatabaseView(Wt::WContainerWidget *parent = 0);
|
||||||
|
|
||||||
|
Wt::Signal<void>& changed() { return _sigChanged; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Wt::Signal<void> _sigChanged;
|
||||||
|
|
||||||
|
void processSave();
|
||||||
|
void processDiscard();
|
||||||
|
void processImmediateScan();
|
||||||
|
|
||||||
|
Wt::WText *_applyInfo;
|
||||||
|
DatabaseModel *_model;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Settings
|
||||||
|
} // namespace UserInterface
|
||||||
|
|
||||||
Reference in New Issue
Block a user