mirror of
https://github.com/RetroPie/EmulationStation.git
synced 2024-06-12 17:37:24 -04:00
Changes to maintain and persist <folder/> information in a gamelist:
1. folder elements are loaded when present in a gamelist and if they match the filesystem representation 2. missing optional folder elements are rendered empty in theme (and not "unknown") 3. As before non-existing folder elements are generated by ES, with mandatory elements <path/> and <name/>, but with this PR, whenever metadata is edited for this folder object (FileData class) it is persisted 4. Editiing metadata on existing <folder/> gets persisted too 5. UI metadata edit: layout fix that renders entered metadata not centered when returning from editing 6. UI metadata edit: format tooltip for date format in release date field
This commit is contained in:
parent
01de7618d0
commit
a113b22ca7
|
@ -12,11 +12,12 @@
|
|||
|
||||
FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType type)
|
||||
{
|
||||
// first, verify that path is within the system's root folder
|
||||
FileData* root = system->getRootFolder();
|
||||
bool contains = false;
|
||||
std::string relative = Utils::FileSystem::removeCommonPath(path, root->getPath(), contains, true);
|
||||
const std::string systemPath = root->getPath();
|
||||
|
||||
// first, verify that path is within the system's root folder
|
||||
std::string relative = Utils::FileSystem::removeCommonPath(path, systemPath, contains, true);
|
||||
if(!contains)
|
||||
{
|
||||
LOG(LogError) << "File path \"" << path << "\" is outside system path \"" << system->getStartPath() << "\"";
|
||||
|
@ -24,17 +25,21 @@ FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType
|
|||
}
|
||||
|
||||
Utils::FileSystem::stringList pathList = Utils::FileSystem::getPathList(relative);
|
||||
|
||||
auto path_it = pathList.begin();
|
||||
FileData* treeNode = root;
|
||||
bool found = false;
|
||||
|
||||
// iterate over all subpaths below the provided path
|
||||
while(path_it != pathList.end())
|
||||
{
|
||||
const std::unordered_map<std::string, FileData*>& children = treeNode->getChildrenByFilename();
|
||||
|
||||
std::string key = *path_it;
|
||||
found = children.find(key) != children.cend();
|
||||
std::string pathSegment = *path_it;
|
||||
auto candidate = children.find(pathSegment);
|
||||
found = candidate != children.cend();
|
||||
if (found) {
|
||||
treeNode = children.at(key);
|
||||
treeNode = candidate->second;
|
||||
}
|
||||
|
||||
// this is the end
|
||||
|
@ -65,12 +70,16 @@ FileData* findOrCreateFile(SystemData* system, const std::string& path, FileType
|
|||
// if type is a folder it's gonna be empty, so don't bother
|
||||
if(type == FOLDER)
|
||||
{
|
||||
LOG(LogWarning) << "gameList: folder doesn't already exist, won't create";
|
||||
std::string absFolder = Utils::FileSystem::getAbsolutePath(pathSegment, systemPath);
|
||||
LOG(LogWarning) << "gameList: folder " << absFolder << " absent on fs, no FileData object created. Do remove leftover in gamelist.xml to remediate this warning.";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create missing folder
|
||||
FileData* folder = new FileData(FOLDER, Utils::FileSystem::getStem(treeNode->getPath()) + "/" + *path_it, system->getSystemEnvData(), system);
|
||||
// create folder filedata object
|
||||
std::string absPath = Utils::FileSystem::resolveRelativePath(treeNode->getPath() + "/" + pathSegment, systemPath, false, true);
|
||||
FileData* folder = new FileData(FOLDER, absPath, system->getSystemEnvData(), system);
|
||||
LOG(LogDebug) << "folder not found as FileData, adding: " << folder->getPath();
|
||||
|
||||
treeNode->addChild(folder);
|
||||
treeNode = folder;
|
||||
}
|
||||
|
@ -118,7 +127,8 @@ void parseGamelist(SystemData* system)
|
|||
FileType type = typeList[i];
|
||||
for(pugi::xml_node fileNode = root.child(tag); fileNode; fileNode = fileNode.next_sibling(tag))
|
||||
{
|
||||
const std::string path = Utils::FileSystem::resolveRelativePath(fileNode.child("path").text().get(), relativeTo, false, true);
|
||||
std::string path = fileNode.child("path").text().get();
|
||||
path = Utils::FileSystem::resolveRelativePath(path, relativeTo, false, true);
|
||||
|
||||
if(!trustGamelist && !Utils::FileSystem::exists(path))
|
||||
{
|
||||
|
@ -127,7 +137,7 @@ void parseGamelist(SystemData* system)
|
|||
}
|
||||
|
||||
// Check whether the file's extension is allowed in the system
|
||||
if (std::find(allowedExtensions.cbegin(), allowedExtensions.cend(), Utils::FileSystem::getExtension(path)) == allowedExtensions.cend())
|
||||
if (i == 0 /*game*/ && std::find(allowedExtensions.cbegin(), allowedExtensions.cend(), Utils::FileSystem::getExtension(path)) == allowedExtensions.cend())
|
||||
{
|
||||
LOG(LogDebug) << "file " << path << " found in gamelist, but has unregistered extension";
|
||||
continue;
|
||||
|
@ -142,7 +152,7 @@ void parseGamelist(SystemData* system)
|
|||
else if(!file->isArcadeAsset())
|
||||
{
|
||||
std::string defaultName = file->metadata.get("name");
|
||||
file->metadata = MetaDataList::createFromXML(GAME_METADATA, fileNode, relativeTo);
|
||||
file->metadata = MetaDataList::createFromXML(i == 0 ? GAME_METADATA : FOLDER_METADATA, fileNode, relativeTo);
|
||||
|
||||
//make sure name gets set if one didn't exist
|
||||
if(file->metadata.get("name").empty())
|
||||
|
@ -173,7 +183,8 @@ void addFileDataNode(pugi::xml_node& parent, const FileData* file, const char* t
|
|||
//there's something useful in there so we'll keep the node, add the path
|
||||
|
||||
// try and make the path relative if we can so things still work if we change the rom folder location in the future
|
||||
newNode.prepend_child("path").text().set(Utils::FileSystem::createRelativePath(file->getPath(), system->getStartPath(), false, true).c_str());
|
||||
std::string relPath = Utils::FileSystem::createRelativePath(file->getPath(), system->getStartPath(), false, true);
|
||||
newNode.prepend_child("path").text().set(relPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,9 +235,8 @@ void updateGamelist(SystemData* system)
|
|||
{
|
||||
int numUpdated = 0;
|
||||
|
||||
//get only files, no folders
|
||||
std::vector<FileData*> files = rootFolder->getFilesRecursive(GAME | FOLDER);
|
||||
|
||||
|
||||
// Stage 1: iterate through all files in memory, checking for changes
|
||||
for(std::vector<FileData*>::const_iterator fit = files.cbegin(); fit != files.cend(); ++fit)
|
||||
{
|
||||
|
@ -234,13 +244,13 @@ void updateGamelist(SystemData* system)
|
|||
// do not touch if it wasn't changed anyway
|
||||
if (!(*fit)->metadata.wasChanged())
|
||||
continue;
|
||||
|
||||
|
||||
// adding item to changed list
|
||||
if ((*fit)->getType() == GAME)
|
||||
if ((*fit)->getType() == GAME)
|
||||
{
|
||||
changedGames.push_back((*fit));
|
||||
changedGames.push_back((*fit));
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
changedFolders.push_back((*fit));
|
||||
}
|
||||
|
@ -251,13 +261,13 @@ void updateGamelist(SystemData* system)
|
|||
const char* tagList[2] = { "game", "folder" };
|
||||
FileType typeList[2] = { GAME, FOLDER };
|
||||
std::vector<FileData*> changedList[2] = { changedGames, changedFolders };
|
||||
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
const char* tag = tagList[i];
|
||||
std::vector<FileData*> changes = changedList[i];
|
||||
|
||||
// if changed items of this type
|
||||
// check for changed items of this type
|
||||
if (changes.size() > 0) {
|
||||
// check if the item already exists in the XML
|
||||
// if it does, remove all corresponding items before adding
|
||||
|
@ -274,9 +284,10 @@ void updateGamelist(SystemData* system)
|
|||
continue;
|
||||
}
|
||||
|
||||
std::string xmlpath = pathNode.text().get();
|
||||
// apply the same transformation as in Gamelist::parseGamelist
|
||||
std::string xmlpath = Utils::FileSystem::resolveRelativePath(pathNode.text().get(), relativeTo, false, true);
|
||||
|
||||
xmlpath = Utils::FileSystem::resolveRelativePath(xmlpath, relativeTo, false, true);
|
||||
|
||||
for(std::vector<FileData*>::const_iterator cfit = changes.cbegin(); cfit != changes.cend(); ++cfit)
|
||||
{
|
||||
if(xmlpath == (*cfit)->getPath())
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "MetaData.h"
|
||||
|
||||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/TimeUtil.h"
|
||||
#include "Log.h"
|
||||
#include <pugixml.hpp>
|
||||
|
||||
|
@ -27,6 +28,12 @@ MetaDataDecl gameDecls[] = {
|
|||
};
|
||||
const std::vector<MetaDataDecl> gameMDD(gameDecls, gameDecls + sizeof(gameDecls) / sizeof(gameDecls[0]));
|
||||
|
||||
const inline std::string blankDate() {
|
||||
// blank date (1970-01-02) is used to render "" (see DateTimeComponent.cpp) for
|
||||
// folder metadata when no date is provided (=default case)
|
||||
return Utils::Time::timeToString(Utils::Time::BLANK_DATE, "%Y%m%d");
|
||||
}
|
||||
|
||||
MetaDataDecl folderDecls[] = {
|
||||
{"name", MD_STRING, "", false, "name", "enter game name"},
|
||||
{"sortname", MD_STRING, "", false, "sortname", "enter game sort name"},
|
||||
|
@ -35,12 +42,12 @@ MetaDataDecl folderDecls[] = {
|
|||
{"thumbnail", MD_PATH, "", false, "thumbnail", "enter path to thumbnail"},
|
||||
{"video", MD_PATH, "", false, "video", "enter path to video"},
|
||||
{"marquee", MD_PATH, "", false, "marquee", "enter path to marquee"},
|
||||
{"rating", MD_RATING, "0.000000", false, "rating", "enter rating"},
|
||||
{"releasedate", MD_DATE, "not-a-date-time", false, "release date", "enter release date"},
|
||||
{"developer", MD_STRING, "unknown", false, "developer", "enter game developer"},
|
||||
{"publisher", MD_STRING, "unknown", false, "publisher", "enter game publisher"},
|
||||
{"genre", MD_STRING, "unknown", false, "genre", "enter game genre"},
|
||||
{"players", MD_INT, "1", false, "players", "enter number of players"}
|
||||
{"rating", MD_RATING, "", false, "rating", "enter rating"},
|
||||
{"releasedate", MD_DATE, blankDate(), true, "release date", "enter release date"},
|
||||
{"developer", MD_STRING, "", false, "developer", "enter game developer"},
|
||||
{"publisher", MD_STRING, "", false, "publisher", "enter game publisher"},
|
||||
{"genre", MD_STRING, "", false, "genre", "enter game genre"},
|
||||
{"players", MD_INT, "", false, "players", "enter number of players"}
|
||||
};
|
||||
const std::vector<MetaDataDecl> folderMDD(folderDecls, folderDecls + sizeof(folderDecls) / sizeof(folderDecls[0]));
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ struct MetaDataDecl
|
|||
std::string key;
|
||||
MetaDataType type;
|
||||
std::string defaultValue;
|
||||
bool isStatistic; //if true, ignore scraper values for this metadata
|
||||
bool isStatistic; // if true: ignore in scraping and hide in metadata edits for this key
|
||||
std::string displayName; // displayed as this in editors
|
||||
std::string displayPrompt; // phrase displayed in editors when prompted to enter value (currently only for strings)
|
||||
};
|
||||
|
|
|
@ -121,7 +121,10 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
|
|||
if (UIModeController::getInstance()->isUIModeFull() && !mFromPlaceholder && !(mSystem->isCollection() && file->getType() == FOLDER))
|
||||
{
|
||||
row.elements.clear();
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
std::string lblTxt = std::string("EDIT THIS ");
|
||||
lblTxt += std::string((file->getType() == FOLDER ? "FOLDER" : "GAME"));
|
||||
lblTxt += std::string("'S METADATA");
|
||||
row.addElement(std::make_shared<TextComponent>(mWindow, lblTxt, Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||
row.addElement(makeArrow(mWindow), false);
|
||||
row.makeAcceptInputHandler(std::bind(&GuiGamelistOptions::openMetaDataEd, this));
|
||||
mMenu.addRow(row);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "components/ButtonComponent.h"
|
||||
#include "components/ComponentList.h"
|
||||
#include "components/DateTimeComponent.h"
|
||||
#include "components/DateTimeEditComponent.h"
|
||||
#include "components/MenuComponent.h"
|
||||
#include "components/RatingComponent.h"
|
||||
|
@ -37,8 +38,9 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector
|
|||
mHeaderGrid = std::make_shared<ComponentGrid>(mWindow, Vector2i(1, 5));
|
||||
|
||||
mTitle = std::make_shared<TextComponent>(mWindow, "EDIT METADATA", Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
||||
mSubtitle = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(Utils::FileSystem::getFileName(scraperParams.game->getPath())),
|
||||
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER);
|
||||
std::string tgt = md->getType() == GAME_METADATA ? "GAME" : "FOLDER";
|
||||
std::string subt = tgt + ": " + Utils::String::toUpper(Utils::FileSystem::getFileName(scraperParams.game->getPath()));
|
||||
mSubtitle = std::make_shared<TextComponent>(mWindow, subt, Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER);
|
||||
mHeaderGrid->setEntry(mTitle, Vector2i(0, 1), false, true);
|
||||
mHeaderGrid->setEntry(mSubtitle, Vector2i(0, 3), false, true);
|
||||
|
||||
|
@ -50,16 +52,20 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector
|
|||
// populate list
|
||||
for(auto iter = mdd.cbegin(); iter != mdd.cend(); iter++)
|
||||
{
|
||||
std::shared_ptr<GuiComponent> ed;
|
||||
|
||||
// don't add statistics
|
||||
if(iter->isStatistic)
|
||||
continue;
|
||||
|
||||
std::shared_ptr<GuiComponent> ed;
|
||||
|
||||
// create ed and add it (and any related components) to mMenu
|
||||
// ed's value will be set below
|
||||
ComponentListRow row;
|
||||
auto lbl = std::make_shared<TextComponent>(mWindow, Utils::String::toUpper(iter->displayName), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||
auto lblTxt = Utils::String::toUpper(iter->displayName);
|
||||
if (iter->type == MD_DATE) {
|
||||
lblTxt += " (" + DateTimeComponent::getDateformatTip() + ")";
|
||||
}
|
||||
auto lbl = std::make_shared<TextComponent>(mWindow, lblTxt, Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
||||
row.addElement(lbl, true); // label
|
||||
|
||||
switch(iter->type)
|
||||
|
@ -111,6 +117,8 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector
|
|||
{
|
||||
// MD_STRING
|
||||
ed = std::make_shared<TextComponent>(window, "", Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
||||
const float height = lbl->getSize().y() * 0.71f;
|
||||
ed->setSize(0, height);
|
||||
row.addElement(ed, true);
|
||||
|
||||
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
||||
|
@ -140,7 +148,7 @@ GuiMetaDataEd::GuiMetaDataEd(Window* window, MetaDataList* md, const std::vector
|
|||
|
||||
std::vector< std::shared_ptr<ButtonComponent> > buttons;
|
||||
|
||||
if(!scraperParams.system->hasPlatformId(PlatformIds::PLATFORM_IGNORE))
|
||||
if(md->getType() == GAME_METADATA && !scraperParams.system->hasPlatformId(PlatformIds::PLATFORM_IGNORE))
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SCRAPE", "scrape", std::bind(&GuiMetaDataEd::fetch, this)));
|
||||
|
||||
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SAVE", "save", [&] { save(); delete this; }));
|
||||
|
@ -185,11 +193,17 @@ void GuiMetaDataEd::save()
|
|||
// remove game from index
|
||||
mScraperParams.system->getIndex()->removeFromIndex(mScraperParams.game);
|
||||
|
||||
for(unsigned int i = 0; i < mEditors.size(); i++)
|
||||
assert(mMetaDataDecl.size() >= mEditors.size());
|
||||
// there may be less editfields than metadata entries as
|
||||
// statistic md fields are not shown to the user.
|
||||
// md statistic fields are not necessarily at the end of the md list
|
||||
int edIdx = 0;
|
||||
for(auto &mdd : mMetaDataDecl)
|
||||
{
|
||||
if(mMetaDataDecl.at(i).isStatistic)
|
||||
continue;
|
||||
mMetaData->set(mMetaDataDecl.at(i).key, mEditors.at(i)->getValue());
|
||||
if(!mdd.isStatistic) {
|
||||
mMetaData->set(mdd.key, mEditors.at(edIdx)->getValue());
|
||||
edIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
// enter game in index
|
||||
|
@ -212,29 +226,21 @@ void GuiMetaDataEd::fetch()
|
|||
|
||||
void GuiMetaDataEd::fetchDone(const ScraperSearchResult& result)
|
||||
{
|
||||
for(unsigned int i = 0; i < mEditors.size(); i++)
|
||||
assert(mMetaDataDecl.size() >= mEditors.size());
|
||||
int edIdx = 0;
|
||||
for(auto &mdd : mMetaDataDecl)
|
||||
{
|
||||
if(mMetaDataDecl.at(i).isStatistic)
|
||||
if(mdd.isStatistic)
|
||||
continue;
|
||||
|
||||
const std::string& key = mMetaDataDecl.at(i).key;
|
||||
mEditors.at(i)->setValue(result.mdl.get(key));
|
||||
mEditors.at(edIdx)->setValue(result.mdl.get(mdd.key));
|
||||
edIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiMetaDataEd::close(bool closeAllWindows)
|
||||
{
|
||||
// find out if the user made any changes
|
||||
bool dirty = false;
|
||||
for(unsigned int i = 0; i < mEditors.size(); i++)
|
||||
{
|
||||
const std::string& key = mMetaDataDecl.at(i).key;
|
||||
if(mMetaData->get(key) != mEditors.at(i)->getValue())
|
||||
{
|
||||
dirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool dirty = hasChanges();
|
||||
|
||||
std::function<void()> closeFunc;
|
||||
if(!closeAllWindows)
|
||||
|
@ -248,7 +254,6 @@ void GuiMetaDataEd::close(bool closeAllWindows)
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
if(dirty)
|
||||
{
|
||||
// changes were made, ask if the user wants to save them
|
||||
|
@ -262,6 +267,20 @@ void GuiMetaDataEd::close(bool closeAllWindows)
|
|||
}
|
||||
}
|
||||
|
||||
bool GuiMetaDataEd::hasChanges()
|
||||
{
|
||||
assert(mMetaDataDecl.size() >= mEditors.size());
|
||||
// find out if the user made any changes
|
||||
int edIdx = 0;
|
||||
for(auto &mdd : mMetaDataDecl)
|
||||
{
|
||||
if(!mdd.isStatistic && mMetaData->get(mdd.key) != mEditors.at(edIdx++)->getValue())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GuiMetaDataEd::input(InputConfig* config, Input input)
|
||||
{
|
||||
if(GuiComponent::input(config, input))
|
||||
|
|
|
@ -26,6 +26,7 @@ private:
|
|||
void fetch();
|
||||
void fetchDone(const ScraperSearchResult& result);
|
||||
void close(bool closeAllWindows);
|
||||
bool hasChanges();
|
||||
|
||||
NinePatchComponent mBackground;
|
||||
ComponentGrid mGrid;
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
#include "Log.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
DateTimeComponent::DateTimeComponent(Window* window) : TextComponent(window), mDisplayRelative(false)
|
||||
{
|
||||
setFormat("%m/%d/%Y");
|
||||
setFormat(getDateformat());
|
||||
}
|
||||
|
||||
DateTimeComponent::DateTimeComponent(Window* window, const std::string& text, const std::shared_ptr<Font>& font, unsigned int color, Alignment align,
|
||||
Vector3f pos, Vector2f size, unsigned int bgcolor) : TextComponent(window, text, font, color, align, pos, size, bgcolor), mDisplayRelative(false)
|
||||
{
|
||||
setFormat("%m/%d/%Y");
|
||||
setFormat(getDateformat());
|
||||
}
|
||||
|
||||
void DateTimeComponent::setValue(const std::string& val)
|
||||
|
@ -47,9 +49,13 @@ void DateTimeComponent::onTextChanged()
|
|||
|
||||
std::string DateTimeComponent::getDisplayString() const
|
||||
{
|
||||
if(std::difftime(mTime.getTime(), Utils::Time::BLANK_DATE) == 0.0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (mDisplayRelative) {
|
||||
//relative time
|
||||
if(mTime.getTime() == 0)
|
||||
if(mTime.getTime() == Utils::Time::NOT_A_DATE_TIME)
|
||||
return "never";
|
||||
|
||||
Utils::Time::DateTime now(Utils::Time::now());
|
||||
|
@ -69,7 +75,7 @@ std::string DateTimeComponent::getDisplayString() const
|
|||
return std::string(buf);
|
||||
}
|
||||
|
||||
if(mTime.getTime() == 0)
|
||||
if(mTime.getTime() == Utils::Time::NOT_A_DATE_TIME)
|
||||
return "unknown";
|
||||
|
||||
return Utils::Time::timeToString(mTime.getTime(), mFormat);
|
||||
|
|
|
@ -25,6 +25,9 @@ public:
|
|||
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme, const std::string& view, const std::string& element, unsigned int properties) override;
|
||||
|
||||
static std::string getDateformat() { return "%m/%d/%Y"; }
|
||||
static std::string getDateformatTip() { return "MM/DD/YYYY"; }
|
||||
|
||||
protected:
|
||||
void onTextChanged() override;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "components/DateTimeEditComponent.h"
|
||||
|
||||
#include "DateTimeComponent.h"
|
||||
#include "resources/Font.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
|
@ -196,17 +197,17 @@ std::string DateTimeEditComponent::getDisplayString(DisplayMode mode) const
|
|||
switch(mode)
|
||||
{
|
||||
case DISP_DATE:
|
||||
fmt = "%m/%d/%Y";
|
||||
fmt = DateTimeComponent::getDateformat();
|
||||
break;
|
||||
case DISP_DATE_TIME:
|
||||
if(mTime.getTime() == 0)
|
||||
if(mTime.getTime() == Utils::Time::NOT_A_DATE_TIME)
|
||||
return "unknown";
|
||||
fmt = "%m/%d/%Y %H:%M:%S";
|
||||
fmt = DateTimeComponent::getDateformat() + " %H:%M:%S";
|
||||
break;
|
||||
case DISP_RELATIVE_TO_NOW:
|
||||
{
|
||||
//relative time
|
||||
if(mTime.getTime() == 0)
|
||||
if(mTime.getTime() == Utils::Time::NOT_A_DATE_TIME)
|
||||
return "never";
|
||||
|
||||
Utils::Time::DateTime now(Utils::Time::now());
|
||||
|
|
|
@ -9,7 +9,13 @@ namespace Utils
|
|||
{
|
||||
namespace Time
|
||||
{
|
||||
static inline time_t blankDate() {
|
||||
// 1970-01-02
|
||||
tm timeStruct = { 0, 0, 0, 2, 0, 70, 0, 0, -1 };
|
||||
return mktime(&timeStruct);
|
||||
}
|
||||
static int NOT_A_DATE_TIME = 0;
|
||||
static time_t BLANK_DATE = blankDate();
|
||||
|
||||
class DateTime
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue