mirror of
https://github.com/ElvishArtisan/rivendell.git
synced 2025-05-18 14:14:59 +02:00
* Added a 'RDTimeArray' class for optimization and debugging. Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
458 lines
16 KiB
Plaintext
458 lines
16 KiB
Plaintext
This is the CODINGSTYLE file for the Rivendell package.
|
|
|
|
OVERVIEW:
|
|
This file, CODINGSTYLE, describes the coding style guidelines for writing
|
|
new code, how to submit patches to be incorporated into the official
|
|
Rivendell Git repository, and other code related information. General info
|
|
on the Rivendell project can be found at the http://www.rivendellaudio.org/
|
|
web page and also in the 'README' and 'INSTALL' files.
|
|
|
|
The code style used for Rivendell is a somewhat idiosyncratic mixture of
|
|
the style generally used for Qt C++ programs combined with the classic UNIX
|
|
C style. Some of the specifics include:
|
|
|
|
|
|
LINE LENGTH:
|
|
Should not be longer than 78 characters unless doing so would severely
|
|
compromise the readability of the code. Where it is necessary to break a
|
|
line, it should be done at a point that preserves maximum clarity and ease
|
|
of reading.
|
|
|
|
Good:
|
|
*report+=QString(" ")+
|
|
logLine(i)->startTime(RDLogLine::Logged).toString("hh:mm:ss")+
|
|
QString::asprintf(" - cart %06d [",logLine(i)->cartNumber())+
|
|
q->value(1).toString()+"] "+QObject::tr("is not playable")+"\n";
|
|
|
|
Bad:
|
|
*report+=QString(" ")+logLine(i)->startTime(RDLogLine::Logged).toString("hh:mm:ss")+QString::asprintf(" - cart %06d [",logLine(i)->cartNumber())+q->value(1).toString()+"] "+QObject::tr("is not playable")+"\n";
|
|
|
|
|
|
INDENTATION:
|
|
Should be two spaces per level. This helps to keep the line length down.
|
|
|
|
Good:
|
|
if(to_line<0) {
|
|
to_line=size();
|
|
for(int i=from_line;i<size();i++) {
|
|
if(logLine(i)->timeType()==RDLogLine::Hard) {
|
|
to_line=i;
|
|
i=size();
|
|
if(sched_time!=NULL) {
|
|
*sched_time=logLine(i)->startTime(RDLogLine::Logged);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Bad:
|
|
if(to_line<0) {
|
|
to_line=size();
|
|
for(int i=from_line;i<size();i++) {
|
|
if(logLine(i)->timeType()==RDLogLine::Hard) {
|
|
to_line=i;
|
|
i=size();
|
|
if(sched_time!=NULL) {
|
|
*sched_time=logLine(i)->startTime(RDLogLine::Logged);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CURLY BRACES:
|
|
Conditional statements (such as 'if' and 'for') should *always* use curly
|
|
braces, even where the affected block is but one line long. The opening
|
|
brace should be on the same line as the conditional and the closing one on
|
|
a line by itself. This style greatly facilitates debugging, allowing a
|
|
single line to be provisionally commented out or additional lines to be
|
|
provisionally added without making the enclosing conditional syntactically
|
|
invalid.
|
|
|
|
Good:
|
|
if(i==12) {
|
|
printf("i is equal to twelve!\n");
|
|
}
|
|
|
|
Bad:
|
|
if(i==12)
|
|
printf("i is equal to twelve!\n");
|
|
|
|
|
|
PADDING WHITESPACE:
|
|
Wherever possible, there should be no whitespace between constants/variables
|
|
and operators. This helps to keep the line length down.
|
|
|
|
Good:
|
|
for(int i=from_line;i<size();i++) {
|
|
if(logLine(i)->timeType()==RDLogLine::Hard) {
|
|
to_line=i;
|
|
}
|
|
}
|
|
|
|
Bad:
|
|
for(int i = from_line; i < size(); i++) {
|
|
if(logLine(i)->timeType() == RDLogLine::Hard) {
|
|
to_line = i;
|
|
}
|
|
}
|
|
|
|
|
|
CLASS NAMES:
|
|
Should have the initial letter of each word capitalized, e.g. 'ThisIsMyClass'.
|
|
If the class is part of the librd convenience library (in 'lib/'), the name
|
|
should be prefaced with the uppercase letters 'RD', e.g. 'RDThisIsMyClass'.
|
|
|
|
|
|
METHOD NAMES:
|
|
Public method names as well as signal and slot method names should follow
|
|
the general style used by Qt. A special convention for Rivendell is to
|
|
reserve names beginning with an uppercase letter for private methods only.
|
|
|
|
Good:
|
|
class RDLogPlay
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
RDLogPlay(int id,RDEventPlayer *player,QObject *parent=0);
|
|
QString serviceName() const;
|
|
void setServiceName(const QString &svcname);
|
|
|
|
private slots:
|
|
void transTimerData();
|
|
void graceTimerData();
|
|
|
|
signals:
|
|
void renamed();
|
|
void reloaded();
|
|
void transportChanged();
|
|
|
|
private:
|
|
bool StartEvent(int line,RDLogLine::TransType trans_type,int trans_length,
|
|
RDLogLine::StartSource src,int mport=-1,int duck_length=0);
|
|
bool StartAudioEvent(int line);
|
|
};
|
|
|
|
Bad:
|
|
class RDLogPlay
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
RDLogPlay(int id,RDEventPlayer *player,QObject *parent=0);
|
|
QString servicename() const;
|
|
void set_service_name(const QString &svcname);
|
|
|
|
private slots:
|
|
void TransTimerData();
|
|
void grace_timer_data();
|
|
|
|
signals:
|
|
void RENAMED();
|
|
void Reloaded();
|
|
void transport_changed();
|
|
|
|
private:
|
|
bool startEvent(int line,RDLogLine::TransType trans_type,int trans_length,
|
|
RDLogLine::StartSource src,int mport=-1,int duck_length=0);
|
|
bool startAudioEvent(int line);
|
|
};
|
|
|
|
|
|
VARIABLE NAMES:
|
|
*All* variables should be lowercase only, with uppercase being reserved for
|
|
class and method names. Words should be separated by underscores.
|
|
|
|
Good:
|
|
int log_position_number=1;
|
|
|
|
Bad:
|
|
int logPositionNumnber=1;
|
|
|
|
Class variables should be prefaced with a short base name that is common to
|
|
all, followed by an underscore. For example, the class 'MyClass' might use
|
|
'myclass_', as in 'myclass_foo1', 'myclass_foo2', etc. Local variables
|
|
(including function parameter names) should be kept short, preferably a
|
|
single word.
|
|
|
|
|
|
NULL POINTERS
|
|
Null pointers should always be represented by using the 'NULL' keyword,
|
|
rather than 0.
|
|
|
|
Good:
|
|
int *foo=NULL;
|
|
if(foo==NULL) {
|
|
printf("The foo variable is null!\n");
|
|
}
|
|
|
|
Bad:
|
|
int *foo=0;
|
|
if(foo==0) {
|
|
printf("The foo variable is null!\n");
|
|
}
|
|
|
|
|
|
SQL STATEMENTS:
|
|
When embedding SQL statements in code, the following guidelines should be
|
|
followed:
|
|
|
|
1) All identifier fields should be enclosed in backticks (ASCII 0x2C)
|
|
characters (NOT to be confused with apostrophes, see below).
|
|
|
|
Good:
|
|
sql="select `FIELD1`,`FIELD2` from `MY_TABLE` where `ID`=2";
|
|
|
|
Bad:
|
|
Good:
|
|
sql="select FIELD1,FIELD2 from MY_TABLE where ID=2";
|
|
|
|
|
|
2) All string literals should be delimited with the apostrophe character,
|
|
*not* quotes. The previous use of quotes is a MySQL-ism that is now strongly
|
|
discouraged.
|
|
|
|
Good:
|
|
sql="select `FIELD1` from `MY_TABLE` where `FIELD2`='foobar'";
|
|
|
|
Bad:
|
|
sql="select `FIELD1` from `MY_TABLE` where `FIELD2`="foobar";
|
|
|
|
|
|
3) All identifiers are uppercase-only, while SQL operators
|
|
should be all lowercase. This helps improve readability.
|
|
|
|
Good:
|
|
sql="select `FIELD1`,`FIELD2` from `MY_TABLE` where `ID`=2";
|
|
|
|
Bad:
|
|
sql="SELECT `FIELD1`,`FIELD2` FROM `MY_TABLE` WHERE `ID`=2";
|
|
|
|
|
|
4) Long or complex SQL statements should be broken into multiple lines in
|
|
a manner to enhance the readability of both C++ and SQL. For 'select'
|
|
queries that return more than two fields per row, each field should be
|
|
commented with its ordinal number to assist in determining the
|
|
appropriate value to give to 'RDSqlQuery::value()' for referencing
|
|
the fields.
|
|
|
|
Good:
|
|
sql=QString("select ")+
|
|
"`CART`.`TITLE`,"+ // 00
|
|
"`CART`.`ARTIST`,"+ // 01
|
|
"`CART`.`PUBLISHER`,"+ // 02
|
|
"`CART`.`COMPOSER`,"+ // 03
|
|
"`CART`.`USAGE_CODE`,"+ // 04
|
|
"`CUTS`.`ISRC`,"+ // 05
|
|
"`CART`.`ALBUM`,"+ // 06
|
|
"`CART`.`LABEL`,"+ // 07
|
|
"`CUTS`.`ISCI`,"+ // 08
|
|
"`CART`.`CONDUCTOR`,"+ // 09
|
|
"`CART`.`USER_DEFINED`,"+ // 10
|
|
"`CART`.`SONG_ID`,"+ // 11
|
|
"`CUTS`.`DESCRIPTION`,"+ // 12
|
|
"`CUTS`.`OUTCUE` "+ // 13
|
|
"from `CART` left join `CUTS` "+
|
|
"on `CART`.`NUMBER`=`CUTS`.`CART_NUMBER` where "+
|
|
"`CUTS`.`CUT_NAME`='"+RDEscapeString(button->cutName())+"'";
|
|
|
|
Bad:
|
|
sql="select `CART`.`TITLE`,`CART`.`ARTIST`,`CART`.`PUBLISHER`,`CART`.`COMPOSER`,`CART`.`USAGE_CODE`,`CUTS.ISRC`,`CART.ALBUM`,`CART.LABEL`,`CUTS`.`ISCI`,`CART`.`CONDUCTOR`,`CART`.`USER_DEFINED`,`CART`.`SONG_ID`,`CUTS`.`DESCRIPTION`,`CUTS.OUTCUE` from `CART` left join `CUTS` on `CART`.`NUMBER`=`CUTS`.`CART_NUMBER` where `CUTS`.`CUT_NAME`='"+RDEscapeString(button->cutName())+"'";
|
|
|
|
|
|
SCHEMA CHANGES:
|
|
Changes that alter the schema of the database must include:
|
|
|
|
A) Incrementation of the 'RD_VERSION_DATABASE' value in 'lib/dbversion.h'.
|
|
|
|
B) Code that implements the schema change, in the
|
|
'utils/rddbmgr/updateschema.cpp' file.
|
|
|
|
C) Code that implements an exact, perfect reversal of the schema change,
|
|
in the 'utils/rddbmgr/revertschema.cpp' file.
|
|
|
|
D) Updating of the schema map in the 'MainObject::InitializeSchemaMap()'
|
|
method in the 'utils/rddbmgr/schemamap.cpp' file. (See the comment at
|
|
the top of the method definition for details).
|
|
|
|
E) Update the table documentation appropriately in 'docs/tables/'.
|
|
|
|
F) [VERY IMPORTANT] - Document the changes to the schema in your
|
|
'ChangeLog' entry, including the new value of 'RD_VERSION_DATABASE'.
|
|
|
|
|
|
FONT MANGEMENT:
|
|
All fonts used in Rivendell are managed by the RDFontEngine class, which
|
|
provides them on the basis of abstract "roles" so as to provide consistency
|
|
across the entire set of modules. See the file 'docs/apis/fonts.pdf' for
|
|
a detailed description of this sub-system, including screenshot examples.
|
|
|
|
|
|
WRITING TO THE SYSLOG:
|
|
Rivendell makes extensive use of the syslog(3) system found on all
|
|
POSIX-compliant systems. Sending messages to the syslog should almost
|
|
always be done by means of the following method in 'RDApplication':
|
|
|
|
void RDApplication::syslog(int priority,const char *format,...)
|
|
|
|
The exception to the above is when the application context does not
|
|
include a global RDApplication object --e.g. in caed(8). For those
|
|
cases, the following static RDApplication method should be used:
|
|
|
|
void RDApplication::syslog(RDConfig *c,int priority,const char *format,...)
|
|
|
|
For a discussion of the parameters of these methods, see the syslog(3) man
|
|
page. The 'priority' parameter should be one of the following values:
|
|
|
|
LOG_ERR - Indicates that a fatal error has occurred; 'fatal' meaning
|
|
that the program is unable to continue and will now exit.
|
|
|
|
LOG_WARNING - Indicates that a non-fatal error has occured; meaning
|
|
that the program will continue to operate, but with
|
|
possibly significant operational degradation. This would be
|
|
appropriate for things like failure to connect to an
|
|
external switcher or other device.
|
|
|
|
LOG_INFO - Information useful for tracking operational state --e.g.
|
|
a cart play-out has begun, a new Rivendell log has been
|
|
loaded, etc.
|
|
|
|
LOG_DEBUG - Information useful for tracking or verifying Rivendell
|
|
software internal state. These messages will not normally
|
|
be seen by users, but can be made visible to allow for
|
|
program debugging.
|
|
|
|
NOTE: A 'facility' value should *not* be included in the 'priority'
|
|
argument. The appropriate 'facility' value, as determined by the
|
|
'SyslogFacility=' directive in rd.conf(5), will be added automatically.
|
|
|
|
|
|
DATE/TIME FORMATS:
|
|
The formats of date/time values presented in the Rivendell's GUI modules
|
|
are user-specifiable in RDAdmin->SystemSettings. Thus, when handling such,
|
|
the following facilities are available:
|
|
|
|
Value Inputs. The following classes are available:
|
|
|
|
RDDateTimeEdit - Subclass of QDateTimeEdit
|
|
RDDateEdit - Subclass of QDateEdit
|
|
RDTimeEdit - Subclass of QTimeEdit.
|
|
|
|
While the underlying Qt 'setDisplayFormat()' method remains available
|
|
in these subclasses, *it should never be used*, as the underlying display
|
|
formats are automatically derived and applied. In addition, these classes
|
|
have a number of additional methods for handling Rivendell-specific
|
|
situations (times to tenths-of-second precision, read-only states, etc).
|
|
See the specific headers in 'lib/' for details.
|
|
|
|
Value Outputs. The following methods are available for easily rendering
|
|
properly formatted date/time strings in GUI module contexts:
|
|
|
|
RDCoreApplication::timeString(const QTime &time,
|
|
const QString &padding="") const;
|
|
RDCoreApplication::tenthsTimeString(const QTime &time,
|
|
const QString &padding="") const;
|
|
RDCoreApplication::shortDateString(const QDate &date) const;
|
|
RDCoreApplication::longDateString(const Date &date) const;
|
|
|
|
The methods above that involve time all include support for optionally
|
|
specifying times with tenth-second precision. At present, the only place in
|
|
Rivendell where this facility is used is when specifying the 'Start Time' and
|
|
'Grace Time' parameters in Rivendell logs. All other contexts should present
|
|
times to single-second precision.
|
|
|
|
These methods can be easily accessed in GUI module contexts via the global
|
|
'rda' pointer, as illustrated in the following code snippet:
|
|
|
|
*** snip snip ***
|
|
#include <rdapplication.h>
|
|
[..]
|
|
QDate my_date(2021,8,13); // 13 August 2021
|
|
QString my_string=rda->shortDateString(my_date);
|
|
*** snip snip ***
|
|
|
|
N.B. - These date/time formats are for use when interacting with users in
|
|
a GUI context. They should *not* be used in other contexts, including
|
|
(but not necessarily limited to):
|
|
1) SQL Statements. Standard SQL date-time formats apply, and should
|
|
be hard-coded appropriately.
|
|
2) Command-line Utilities. In the interest of providing stable interfaces
|
|
for scripting purposes, date/time values in Rivendell command-line
|
|
tools generally use ISO8601-compliant formats. Where this varies
|
|
(due to application requirements), it should be documented in the
|
|
appropriate manpage.
|
|
3) Standardized APIs. Data interfaces for external systems (JSON, XML,
|
|
etc) should continue to use the formats appropriate for those
|
|
contexts.
|
|
4) Syslog Messages. Any date/time references sent to syslog(3) should
|
|
use ISO8601-compliant formats.
|
|
|
|
|
|
CONTRIBUTING CHANGES:
|
|
The primary code repository for Rivendell resides at GitHub, and can be
|
|
found at:
|
|
|
|
https://github.com/ElvishArtisan/rivendell
|
|
|
|
Changes should be submitted in the form of a pull request [PR] against
|
|
the default branch ('v4' as of this writing). Information about drafting and
|
|
submitting PRs can be found at:
|
|
|
|
https://help.github.com/en/articles/about-pull-requests
|
|
|
|
|
|
PULL REQUEST CHECKLIST:
|
|
Before submitting a pull request, the following guidelines should be
|
|
completed:
|
|
|
|
1) The code should compile without errors or warnings [the '-Werrors' switch
|
|
for gcc(1) is your friend here!].
|
|
|
|
2) Add an entry to the 'ChangeLog' file at the base of the Rivendell source
|
|
code tree, describing your changes. The format of the ChangeLog file has
|
|
the most recent changes at the bottom of the file. Entries start with a
|
|
date stamp and have a format like:
|
|
|
|
YYYY-MM-DD NAME <EMAIL>
|
|
* Description of change
|
|
|
|
For example:
|
|
2007-02-23 John Coder <coder@example.com>
|
|
* Modified the code in 'lib/rdimport_audio.cpp' to use the
|
|
'RDCart::setMetadata()' and 'RDCut::setMetadata()' methods.
|
|
|
|
3) If your changes add, remove or change the behavior of one or more
|
|
configuration entries in rd.conf(5), update the default configuration
|
|
file ('conf/rd.conf-sample') accordingly. Similiarly, for PyPAD scripts,
|
|
be sure to update the corresponding '<plugin-name>-exemplar' files.
|
|
|
|
4) If your changes alter any user-visible aspect (UI or behavior), update
|
|
the user documentation appropriately. The documentation is written
|
|
in DocBook 5 markup, and can be found at the following locations in
|
|
the source tree:
|
|
|
|
Operations Guide - 'docs/opsguide/'
|
|
|
|
Manual pages - 'docs/manpages/'
|
|
|
|
Internal and public APIs - 'docs/apis/'.
|
|
|
|
5) If you wish your work to be mentioned in the 'Credits' list displayed in
|
|
rdadmin(1), add or modify the appropriate entry in the 'AUTHORS' file.
|
|
Entries should be sorted by surname, then christian name of the author.
|
|
|
|
|
|
DEBUGGING/OPTIMIZATION AIDS:
|
|
The following classes exist for aiding the debugging and optimization
|
|
process:
|
|
|
|
RDTimeArray. Record a series of code points with microsecond precision
|
|
and then render the results to a QString. See 'lib/rdtimearray.h'.
|
|
|
|
|
|
QUESTIONS:
|
|
Questions about coding style, or indeed any aspect of Rivendell development,
|
|
are welcomed on the Rivendell-prog mailing list. Subscription information
|
|
and list archives are available at:
|
|
|
|
http://caspian.paravelsystems.com/mailman/listinfo/rivendell-prog
|