mirror of
				https://github.com/ElvishArtisan/rivendell.git
				synced 2025-10-30 17:23:53 +01:00 
			
		
		
		
	* Cleaned up deprecation warnings for 'QString::sprintf()'. Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
		
			
				
	
	
		
			433 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			433 lines
		
	
	
		
			15 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.
 | |
| 
 | |
| 
 | |
| 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 master 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 'master' branch. 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.
 | |
| 
 | |
| 
 | |
| 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
 |