Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add a guide grid to the internal web-server.

This is a WORK IN PROGRESS, not a final finished product. Please do
NOT open tickets for it yet.

What does NOT work (yet)?
 * The 'One-Click-Record' menu isn't hooked.
 * There is no Recording Rule Editor.
 * There are no button to move back/forwards through the guide.

Basically you can view the guide, browse through it by date or time but not much else.

It has been designed with modern browsers in mind. It utilises some
CSS3 and DOM features that may not work with browsers more than 6
months old. This is intentional, it is not a bug but I may be bribed
to change my mind.

The styling is provisional, the finished article may either look very
similar or entirely different.

Firefox, Opera, Opera Mobile, Opera Mobile Classic (Android) and
Chromium were tested. Internet Explorer and Chrome were not tested but
since we're following the standards here they should of course work too.

There is a known issue with Opera Mobile (both versions) and the
record menu throwing everthing out of wack.
  • Loading branch information...
commit 6444664f1e10297b15817dfdca94b05999df2177 1 parent c0c5299
@stuartm stuartm authored
View
33 mythtv/html/css/category_colors.css
@@ -0,0 +1,33 @@
+.guideGrid .category_Action { background-color: #906020; }
+.guideGrid .category_Adult { background-color: #702020; }
+.guideGrid .category_Animals { background-color: #609060; }
+.guideGrid .category_Art_Music { background-color: #801060; }
+.guideGrid .category_Business { background-color: #703010; }
+.guideGrid .category_Children { background-color: #B00010; }
+.guideGrid .category_Comedy { background-color: #006080; }
+.guideGrid .category_Crime_Mystery { background-color: #105050; }
+.guideGrid .category_Documentary { background-color: #504020; }
+.guideGrid .category_Drama { background-color: #400060; }
+.guideGrid .category_Educational { background-color: #606060; }
+.guideGrid .category_Food { background-color: #208040; }
+.guideGrid .category_Game { background-color: #701010; }
+.guideGrid .category_Health_Medical { background-color: #806060; }
+.guideGrid .category_History { background-color: #807020; }
+.guideGrid .category_HowTo { background-color: #A0A000; }
+.guideGrid .category_Horror { background-color: #101040; }
+.guideGrid .category_Misc { background-color: #403060; }
+.guideGrid .category_Film, .guideGrid .category_Movie { background-color: #809090; }
+.guideGrid .category_News { background-color: #606040; }
+.guideGrid .category_Reality { background-color: #304040; }
+.guideGrid .category_Romance { background-color: #A02050; }
+.guideGrid .category_Science_Nature { background-color: #008050; }
+.guideGrid .category_SciFi_Fantasy { background-color: #606090; }
+.guideGrid .category_Shopping { background-color: #103010; }
+.guideGrid .category_Soaps { background-color: #508080; }
+.guideGrid .category_Spiritual { background-color: #804080; }
+.guideGrid .category_Sports { background-color: #005030; }
+.guideGrid .category_Talk { background-color: #203040; }
+.guideGrid .category_Travel { background-color: #2060B0; }
+.guideGrid .category_War { background-color: #B06050; }
+.guideGrid .category_Western { background-color: #806040; }
+.guideGrid .category_Unknown { background-color: #303030; }
View
241 mythtv/html/css/guide.css
@@ -0,0 +1,241 @@
+#content
+{
+ padding: 10px;
+}
+
+.pageTitle
+{
+ float:left;
+}
+
+.navigateBox
+{
+ float: right;
+ margin: 5px 5px 10px 5px;
+ background-color: #333333;
+ border-radius: 8px;
+ padding: 10px;
+ font-weight: bold;
+}
+
+.guideGrid
+{
+ width: 100%;
+ clear: both;
+ /*overflow: visible;*/
+}
+
+.guideGrid div
+{
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ overflow: hidden;
+}
+
+.guideGrid .timeBar
+{
+ clear:both;
+ width: 100%;
+ margin: 5px 0px 5px 0px;
+ font-size: 1.1em;
+ font-weight: bold;
+}
+
+.guideGrid .timeBarDate
+{
+ float: left;
+ background-color: #333333;
+ border-radius: 10px;
+ font-size: 0.8em;
+ width: 10%;
+ height: 100%;
+ text-align: center;
+ padding: 8px 4px 8px 4px;
+}
+
+.guideGrid .timeBarTimes
+{
+ float: left;
+ width: 90%;
+ height: 100%;
+}
+
+.guideGrid .timeBarTime
+{
+ background-color: #333333;
+ border-radius: 10px;
+ padding: 5px 4px 5px 4px;
+ height: 100%;
+}
+
+.guideGrid .channelRow
+{
+ clear: both;
+ width: 100%;
+ height: 80px;
+ margin: 2px;
+ overflow: visible;
+}
+
+.guideGrid .channelBox
+{
+ float: left;
+ width: 10%;
+ height: 100%;
+ text-align: center;
+ vertical-align: middle;
+ background-color: #333333;
+ color: #FFFFFF;
+ border-radius: 10px;
+}
+
+.guideGrid .channelIcon
+{
+ margin: 5px 5px 1px 5px;
+}
+
+.guideGrid .channelText
+{
+ font-weight: bold;
+}
+
+.guideGrid .programBox
+{
+ float: left;
+ height: 100%;
+}
+
+.guideGrid .programBoxInner
+{
+ margin:0px 1px 0px 1px;
+ height: 100%;
+ background-color: #666666;
+ border-radius: 10px;
+}
+
+.guideGrid .programStartsOffScreen
+{
+ border-top-left-radius: 0px;
+ border-bottom-left-radius: 0px;
+}
+
+.guideGrid .programEndsOffScreen
+{
+ border-top-right-radius: 0px;
+ border-bottom-right-radius: 0px;
+}
+
+.guideGrid .programHeader
+{
+ padding: 6px 8px 6px 8px;
+ color: #FFFFFF;
+ font-size: 1.1em;
+ width: 100%;
+ height: 30px;
+ font-weight: bold;
+ background-color: #444444;
+ border-radius: inherit;
+ border-bottom-left-radius: 0px;
+ border-bottom-right-radius: 0px;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ z-index: 5;
+ position:relative;
+}
+
+.guideGrid .programBody
+{
+ padding: 5px 5px 5px 5px;
+ color: #DDDDDD;
+ height: 45px;
+ z-index:5;
+ font-size: 0.8em;
+}
+
+.guideGrid .programDescription
+{
+ position:relative;
+ z-index:5; /* We want this to appear above the black veil */
+}
+
+.guideGrid .programSubtitle
+{
+ position:relative;
+ font-weight: bold;
+ font-size: 0.8em;
+ margin-right:5px;
+ z-index:5; /* We want this to appear above the black veil */
+}
+
+.guideGrid .programArrow
+{
+ font-size: 1.1em;
+ font-weight: bold;
+}
+
+.guideGrid .programWillRecord
+{
+ background-color:#37912F;
+}
+
+.guideGrid .programRecording
+{
+ background-color:#00CC00;
+}
+
+.guideGrid .programOtherShowing
+{
+ border:2px #37912F dashed;
+}
+
+.guideGrid .programSelected
+{
+ border:2px #045FB4 solid;
+}
+
+.guideGrid .relentlessMarchOfTime
+{
+ background-color: rgba(51, 51, 78, 0.7);
+ border-radius: 10px;
+ z-index: 1;
+ height: 80px;
+ margin-left:2px;
+}
+
+#recMenu
+{
+ background-color: rgba(51, 51, 51, 0.85);
+ border: 2px #045FB4 solid;
+ box-shadow: 6px 6px 4px #222222;
+ display: none;
+ z-index: 99;
+ position: absolute;
+ padding: 5px;
+}
+
+#recMenu .button
+{
+ background-color:#444444;
+ border:1px #FFFFFF solid;
+ color: #FFFFFF;
+ margin: 5px
+ font-weight: bold;
+ font-size: 1.1em;
+ padding: 5px;
+ vertical-align: middle;
+ text-align: center;
+ white-space: nowrap;
+ border-radius: 8px;
+}
+
+#programDetails
+{
+ background-color: rgba(51, 51, 51, 0.85);
+ border: 2px #045FB4 solid;
+ box-shadow: 6px 6px 4px #222222;
+ width: 30%;
+ display: none;
+ z-index: 50;
+ position: absolute;
+ padding: 10px;
+}
View
2  mythtv/html/html.pro
@@ -11,7 +11,7 @@ win32-msvc*:QMAKE_COPY_DIR =
html.path = $${PREFIX}/share/mythtv/html/
html.files = index.html overview.html menu.qsp
-html.files += css css/images images js misc setup samples
+html.files += css css/images images js misc setup samples tv
html.files += 3rdParty xslt
INSTALLS += html
View
1  mythtv/html/index.html
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html>
<head>
+<meta charset="UTF-8">
<title>
MythTV mythbackend Internal Web Server
</title>
View
158 mythtv/html/js/guide.js
@@ -0,0 +1,158 @@
+
+function isValidObject(variable)
+{
+ return ((typeof variable === 'object') && (variable != null));
+}
+
+function toggleVisibility(layer, show)
+{
+ // We can override the toggle behaviour with the show arg
+ if (typeof show === 'boolean')
+ {
+ layer.style.display = show ? "block" : "none";
+ }
+ else
+ layer.style.display = (layer.style.display != "block") ? "block" : "none";
+}
+
+function checkVisibility(layer)
+{
+ return (layer.style.display == "block");
+}
+
+function moveToPosition(layer, customer)
+{
+ // getBoundingClientRect() excludes the offset due to scrolling, the
+ // values return are relative to the currently displayed area
+ var customerLeft = customer.getBoundingClientRect().left;
+ var customerTop = customer.getBoundingClientRect().top;
+ var customerBottom = customer.getBoundingClientRect().bottom;
+ var layerWidth = layer.clientWidth;
+ var layerHeight = layer.clientHeight;
+ var pageTop = 0;
+
+ // If our layer is inside an absolute DIV then we need to compensate for
+ // that parent DIVs position
+ var parentXOffset = layer.parentNode.getBoundingClientRect().left;
+ var parentYOffset = layer.parentNode.getBoundingClientRect().top;
+
+ var pageBottom = window.innerHeight; //document.body.clientHeight;
+ var pageWidth = document.body.clientWidth; //window.innerHeight;
+
+ //alert("Page Bottom: " + pageBottom + " Parent Bottom: " + customerBottom + " Layer Height: " + layerHeight);
+
+ if ((customerLeft + layerWidth + 10 - parentXOffset) < pageWidth)
+ {
+ layer.style.left = (customerLeft + 10 - parentXOffset) + "px";
+ }
+ else
+ layer.style.left = (pageWidth - layerWidth - 5 - parentXOffset) + "px";
+
+ if ((customerBottom + layerHeight - parentYOffset) < pageBottom + window.pageYOffset)
+ {
+ layer.style.top = (customerBottom - parentYOffset) + "px";
+ }
+ else
+ layer.style.top = (customerTop - layerHeight - parentYOffset) + "px";
+}
+
+function toggleClass(element, className)
+{
+ class_array = element.className.split(" ");
+
+ if (class_array.length > 0 &&
+ class_array[class_array.length - 1] == className)
+ {
+ class_array.pop();
+ }
+ else
+ {
+ class_array.push(className);
+ }
+
+ element.className = class_array.join(" ");
+}
+
+var timer;
+function startDetailTimer(parent)
+{
+ var parentID = parent.id;
+ timer = setTimeout(function(){showDetail(parentID)}, 1500);
+}
+
+function showDetail(parentID)
+{
+ clearTimeout(timer);
+
+ var menu = document.getElementById('recMenu');
+ if (checkVisibility(menu))
+ return;
+
+ var parent = document.getElementById(parentID);
+ var content = document.getElementById(parentID + '_detail');
+ var layer = document.getElementById('programDetails');
+
+ layer.innerHTML = content.innerHTML;
+ toggleVisibility(layer, true);
+ moveToPosition(layer, parent);
+}
+
+function hideDetail(parent)
+{
+ clearTimeout(timer);
+
+ var parentID = parent.id;
+ var layer = document.getElementById('programDetails');
+
+ if (!isValidObject(layer))
+ return;
+
+ toggleVisibility(layer, false);
+}
+
+var selectedElement;
+var chanID = "";
+var startTime = "";
+function showRecMenu(parent)
+{
+ hideDetail(parent);
+ var menu = document.getElementById('recMenu');
+ // Reset visibility
+ if (checkVisibility(menu))
+ {
+ toggleVisibility(menu);
+
+ // Reset any currently selected program
+ if (isValidObject(selectedElement))
+ toggleClass(selectedElement, "programSelected");
+ }
+
+ if (selectedElement === parent)
+ {
+ selectedElement = null;
+ return;
+ }
+
+ var parentID = parent.id;
+ var values = parentID.split("_", 2);
+ chanID = values[0];
+ startTime = values[1];
+
+ // Toggle the "programSelected" class on the program div, this gives the
+ // user visual feedback on which one the menu relates to
+ selectedElement = parent;
+ toggleClass(selectedElement, "programSelected");
+
+ // Display the menu
+ toggleVisibility(menu);
+
+ // Move the menu position to the vicinity of the click event
+ // (may change this to immediately be above/below the selected program div
+ // instead)
+ moveToPosition(menu, parent);
+}
+
+function recordProgram(chanID, startTime, type)
+{
+
+}
View
5 mythtv/html/menu.qsp
@@ -3,6 +3,11 @@
</div>
<div id="menu">
<ul class="menu collapsible">
+ <li><a href='#'><i18n>TV</i18n></a>
+ <ul class="acitem collapsible">
+ <li><a class='menuitem' href='#' onClick="javascript:loadContent('/tv/guide.qsp')"><%=qsTr("Program Guide")%></a></li>
+ </ul>
+</li>
<!--
<li><a href='#'><i18n>Setup</i18n></a>
<ul class="acitem collapsible">
View
263 mythtv/html/tv/guide.qsp
@@ -0,0 +1,263 @@
+<%
+ var args = arguments[1];
+ function toCapitalCase(str)
+ {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+ }
+
+ function isValidObject(variable)
+ {
+ return ((typeof variable === "object")
+ && typeof variable !== "undefined"
+ && (variable != null));
+ }
+
+ var timeBarInterval = 30; // Display time markers every X minutes
+ var guideRange = 2; // Show X hours from the start time
+
+ var myth = new Myth();
+ var guide = new Guide();
+
+ var now = new Date();
+ var guideStartTime;
+
+ // Use the StartTime argument if it was defined
+ if (typeof args.StartTime !== "undefined")
+ {
+ //guideStartTime = new Date();
+ guideStartTime = myth.ParseISODateString(args.StartTime);
+ }
+
+ // If the StartTime wasn't valid or wasn't defined then use the current time
+ if (!isValidObject(guideStartTime))
+ guideStartTime = new Date(now);
+
+ // Round down to the nearest half hour
+ guideStartTime.setMinutes(guideStartTime.getMinutes() >= 30 ? 30 : 0);
+
+ // Remove any stray seconds that would break date comparisons later
+ guideStartTime.setSeconds(0);
+ guideStartTime.setMilliseconds(0);
+
+ var guideEndTime = new Date(guideStartTime);
+ guideEndTime.setHours(guideStartTime.getHours() + guideRange);
+ // Hack because GetProgramGuide will include programs with a starttime matching our endtime
+ guideEndTime.setSeconds(guideEndTime.getSeconds() - 1);
+ var guidePeriod = new Date(guideEndTime - guideStartTime);
+
+ // Actually fetch the guide data
+ var guideResult = guide.GetProgramGuide(guideStartTime, guideEndTime, 0, 0, true);
+ var channelList = guideResult.Channels;
+
+ // Indicator of time in past
+ var darkVeilWidth = 0;
+ if ((now - guideStartTime) > 0)
+ {
+ darkVeilWidth = Math.round(((now - guideStartTime)/guidePeriod) * 100);
+ if (darkVeilWidth > 100)
+ darkVeilWidth = 100;
+ }
+%>
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title><%=qsTr("Program Guide")%> - <%=myth.GetFormatDate(guideStartTime)%>,
+ <%=myth.GetFormatTime(guideStartTime)%> - <%=myth.GetFormatTime(guideEndTime)%></title>
+<link rel="stylesheet" type="text/css" href="/css/site.css">
+<link rel="stylesheet" type="text/css" href="/css/guide.css">
+<link rel="stylesheet" type="text/css" href="/css/category_colors.css">
+<script type="text/javascript" src="/js/util.qjs"></script>
+<script type="text/javascript" src="/js/guide.js"></script>
+</head>
+<body>
+
+<h2 class="pageTitle" id="title"><%=qsTr("Program Guide")%></h2>
+
+<!-- Popup Recording Menu -->
+<div id="recMenu">
+ <div class="button" onClick="recordProgram(chanID, startTime, 'Single Record')">
+ Record this showing
+ </div>
+ <div class="button" onClick="recordProgram(chanID, startTime, 'Record All')">
+ Record all showings
+ </div>
+ <div class="button" onClick="recordProgram(chanID, startTime, 'Record One')">
+ Record one showing
+ </div>
+ <div class="button" onClick="recordProgram(chanID, startTime, 'Record All (Channel)')">
+ Record all showings (this channel)
+ </div>
+ <div class="button" onClick="loadContent('/tv/schedule.qsp')">
+ Edit recording rule
+ </div>
+</div>
+
+<!-- Popup Program Details Box -->
+<div id="programDetails" class="programExDetail">
+</div>
+
+<!-- Navigation by day or time -->
+<div class="navigateBox">
+
+ <label for="guideStartDate"><%=qsTr("Date")%>:</label>
+ <select id="guideStartDate" onChange="loadContent('/tv/guide.qsp?StartTime=' + this.options[this.options.selectedIndex].value);">
+<%
+ var startDay = new Date(guideStartTime);
+ startDay.setDate(now.getDate() - 14); // We keep old guide date for 14 days
+ for (var dateIdx = 0; dateIdx < 28; dateIdx++)
+ {
+ var selected = (startDay.getDate() == guideStartTime.getDate()) ? "selected" : "";
+
+%>
+ <option label="<%=myth.GetFormatDate(startDay)%>" <%=selected%> value="<%=startDay.toISOString()%>"><%=myth.GetFormatDate(startDay)%></option>
+<%
+ startDay.setDate(startDay.getDate() + 1);
+ }
+%>
+ </select>
+
+ <label for="guideStartTime"><%=qsTr("Time")%>:</label>
+ <select id="guideStartTime" onChange="loadContent('/tv/guide.qsp?StartTime=' + this.options[this.options.selectedIndex].value);">
+<%
+ var startTime = new Date(guideStartTime);
+ startTime.setHours(0);
+ startTime.setMinutes(0);
+ for (var hourIdx = 0; hourIdx < 48; hourIdx++)
+ {
+ var selected = ((startTime.getHours() == guideStartTime.getHours()) &&
+ (startTime.getMinutes() == guideStartTime.getMinutes())) ? "selected" : "";
+%>
+ <option label="<%=myth.GetFormatTime(startTime)%>" value="<%=startTime.toISOString()%>" <%=selected%>><%=myth.GetFormatTime(startTime)%></option>
+<%
+ startTime.setMinutes(startTime.getMinutes() + 30);
+ }
+%>
+ </select>
+
+</div>
+
+<div class="guideGrid">
+
+ <div class="timeBar">
+ <div class="timeBarDate">
+ <%=myth.GetFormatDate(guideStartTime, true)%>
+ </div>
+ <div class="timeBarTimes">
+<%
+ var numTimePeriods = (guideRange * 60) / timeBarInterval;
+ var width = (100 / numTimePeriods);
+ for (var timeIdx=0; timeIdx < numTimePeriods; timeIdx++)
+ {
+ var displayTime = new Date(guideStartTime);
+ displayTime.setMinutes(displayTime.getMinutes() + (timeIdx * timeBarInterval));
+%>
+ <div style="width:<%=width%>%;float:left;height:100%;padding-left:2px;">
+ <div class="timeBarTime">
+ <%=myth.GetFormatTime(displayTime)%>
+ <span style="float:right;">&rsaquo;</span>
+ </div>
+ </div>
+<%
+ }
+%>
+ </div>
+ </div>
+
+<%
+ for (var chanIdx=0; chanIdx < channelList.length; chanIdx++)
+ {
+ var channel = channelList[chanIdx];
+ if (!channel.Visible)
+ continue;
+ var programList = channel.Programs;
+%>
+
+ <div class="channelRow">
+ <div class="channelBox">
+ <img class="channelIcon" alt="<%=channel.ChannelName%> Icon" src="/Guide/GetChannelIcon?ChanId=<%=channel.ChanId%>&amp;Height=50" />
+ <div class="channelText"><%=channel.ChannelName%></div>
+ </div>
+ <div style="float:left;width:90%;height:100%;position:relative;overflow:visible;">
+
+ <div class="relentlessMarchOfTime" style="position:absolute;width:<%=darkVeilWidth%>%;">&nbsp;</div>
+<%
+ var programNum = 0;
+ var cumulativeWidth = 0;
+ for (var progIdx=0; progIdx < programList.length; progIdx++)
+ {
+ var program = programList[progIdx];
+ if (program.EndTime <= guideStartTime)
+ continue;
+ if (program.StartTime >= (guideEndTime))
+ continue;
+ var altClass = "";
+ if (program.StartTime < guideStartTime)
+ altClass = "programStartsOffScreen";
+ else if (program.EndTime > guideEndTime)
+ altClass = "programEndsOffScreen";
+
+ programNum++;
+ var windowStart = (program.StartTime > guideStartTime ? program.StartTime : guideStartTime);
+ var windowEnd = (program.EndTime > guideEndTime ? guideEndTime : program.EndTime);
+ var windowLength = (windowEnd - windowStart);
+ var width = Math.round(((windowLength / guidePeriod) * 100));
+ cumulativeWidth += width;
+
+ // Due to rounding issues we can end up a percentage point or two over
+ // this just trims the last width to prevent that happening.
+ if (progIdx == (programList.length - 1))
+ {
+ width = (cumulativeWidth < 100) ? width + (100 - cumulativeWidth) : width;
+ width = (cumulativeWidth > 100) ? width - (cumulativeWidth - 100) : width;
+ }
+ var category = toCapitalCase(program.Category.replace(/ /g, ''))
+ var status = "";
+ switch (program.Recording.Status)
+ {
+ case -1:
+ status = "programWillRecord";
+ break;
+ case -2:
+ status = "programRecording";
+ break;
+ case 4: case 8: case 13:
+ status = "programOtherShowing";
+ break;
+ }
+
+ var showArrow = (program.EndTime > windowEnd) ? "block" : "none";
+
+ // Used as a unique identifier and also to access the chanid
+ // and starttime for the AJAX scheduling stuff
+ var programIdentifier = channel.ChanId + "_" + program.StartTime.toISOString();
+%>
+ <div class="programBox" style="width:<%=width%>%;" title="<%=program.Title%>">
+ <div class="programBoxInner category_<%=category%> <%=altClass%>" id="<%=programIdentifier%>" onMouseOver="startDetailTimer(this);" onMouseOut="hideDetail(this);" onClick="showRecMenu(this);">
+ <div class="programHeader <%=status%>"><%=program.Title%> <!-- <div style="display:<%=showArrow%>;" class="programArrow">&rsaquo;</div> --></div>
+ <div class="programBody">
+ <span class="programSubtitle"><%=program.SubTitle%></span>
+ <span class="programDescription"><%=program.Description%></span>
+ </div>
+ </div>
+ </div>
+ <div style="display: none" id="<%=programIdentifier%>_detail">
+ <label for="progStartTime">Duration: </label><span id="progStartTime"><%=myth.GetFormatTime(program.StartTime)%> - <%=myth.GetFormatTime(program.EndTime)%></span><br />
+ <label for="progCategory">Category: </label><span id="progCategory"><%=program.Category%></span><br />
+ <label for="progSeason">Season: </label><span id="progSeason"><%=program.Season%></span><br />
+ <label for="progEpisode">Episode: </label><span id="progEpisode"><%=program.Episode%></span>
+ </div>
+<%
+ }
+%>
+ </div>
+ </div>
+<%
+ }
+%>
+
+</div>
+
+</body>
+</html>
View
12 mythtv/html/tv/schedule.qsp
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>Schedule Editor</title>
+<link rel="stylesheet" type="text/css" href="/css/site.css">
+</head>
+<body>
+<h2>Schedule Editor</h2>
+<p>Sorry Folks, this has yet to be written. Please check back soon.</p>
+</body>
+</html>
View
5 mythtv/libs/libmythservicecontracts/services/mythServices.h
@@ -89,6 +89,11 @@ class SERVICE_PUBLIC MythServices : public Service //, public QScriptable ???
virtual DTC::TimeZoneInfo* GetTimeZone ( ) = 0;
+ virtual QString GetFormatDate ( const QDateTime Date,
+ bool ShortDate ) = 0;
+ virtual QString GetFormatTime ( const QDateTime Time ) = 0;
+ virtual QDateTime ParseISODateString ( const QString &DateTime ) = 0;
+
virtual DTC::LogMessageList* GetLogs ( const QString &HostName,
const QString &Application,
int PID,
View
42 mythtv/programs/mythbackend/services/myth.cpp
@@ -381,6 +381,46 @@ DTC::TimeZoneInfo *Myth::GetTimeZone( )
//
/////////////////////////////////////////////////////////////////////////////
+QString Myth::GetFormatDate(const QDateTime Date, bool ShortDate)
+{
+ QString dateFormat;
+ if (ShortDate)
+ dateFormat = gCoreContext->GetSetting("ShortDateFormat", "ddd d");
+ else
+ dateFormat = GetMythDB()->GetSetting("DateFormat", "ddd d MMMM");
+
+ return gCoreContext->GetQLocale().toString(Date, dateFormat);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+/////////////////////////////////////////////////////////////////////////////
+
+QString Myth::GetFormatTime(const QDateTime Time)
+{
+ QString timeFormat = GetMythDB()->GetSetting("TimeFormat", "hh:mm");
+
+ return gCoreContext->GetQLocale().toString(Time, timeFormat);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+/////////////////////////////////////////////////////////////////////////////
+
+QDateTime Myth::ParseISODateString(const QString& DateTimeString)
+{
+ QDateTime dateTime = QDateTime().fromString(DateTimeString, Qt::ISODate);
+
+ if (!dateTime.isValid())
+ throw( "Unable to parse DateTimeString" );
+
+ return dateTime;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+/////////////////////////////////////////////////////////////////////////////
+
DTC::LogMessageList *Myth::GetLogs( const QString &HostName,
const QString &Application,
int PID,
@@ -540,7 +580,7 @@ DTC::SettingList *Myth::GetSetting( const QString &sHostName,
// Key Supplied, lookup just its value.
// ------------------------------------------------------------------
- query.prepare("SELECT data, hostname from settings "
+ query.prepare("SELECT data, hostname FROM settings "
"WHERE value = :KEY AND "
"(hostname = :HOSTNAME OR hostname IS NULL) "
"ORDER BY hostname DESC;" );
View
21 mythtv/programs/mythbackend/services/myth.h
@@ -59,6 +59,11 @@ class Myth : public MythServices
DTC::TimeZoneInfo* GetTimeZone ( );
+ QString GetFormatDate ( const QDateTime Date,
+ bool ShortDate );
+ QString GetFormatTime ( const QDateTime Time );
+ QDateTime ParseISODateString ( const QString &DateTime );
+
DTC::LogMessageList* GetLogs ( const QString &HostName,
const QString &Application,
int PID,
@@ -187,6 +192,22 @@ class ScriptableMyth : public QObject
QObject* GetTimeZone() { return m_obj.GetTimeZone( ); }
+ QString GetFormatDate( const QDateTime Date,
+ bool ShortDate = false )
+ {
+ return m_obj.GetFormatDate( Date, ShortDate );
+ }
+
+ QString GetFormatTime( const QDateTime Time )
+ {
+ return m_obj.GetFormatTime( Time );
+ }
+
+ QDateTime ParseISODateString( const QString &DateTime )
+ {
+ return m_obj.ParseISODateString(DateTime);
+ }
+
QObject* GetLogs( const QString &HostName,
const QString &Application,
int PID,
Please sign in to comment.
Something went wrong with that request. Please try again.