Coding conventions

Layout of the source tree

Path

Contents

TahitiBase/

Portable base library: strings, logging, exceptions, reference counting, threads, XML / JSON / zip, disk utilities. No UI.

TahitiCore/

Document model, repositories (GigaBase), presentations, document types.

Tahiti/

The application and its ~40 feature modules (Tahiti with MainFrame, TahitiCommon, DocTree, MultiPageView, Ole2View, PdfView, MailView, HtmlView, PictureView, Scanning / ScanCore, BarCode, Damis / DamisCore, PdfExport, Update, …).

Communication/

DEP2 archive protocol, TCIOL transport, import / export tools.

Components/

Pluggable components (BasicExport, PhotoFilter, SapLink, ShellFiles).

AppPlugins/

Host-application integration: MsWord, MsExcel, MsOutlook, LotusNotes, WebExtension, ChromeExt.

Utils/

Standalone executables: TahitiServer, StiHandler, RunTpkg, Send2Damis.

ImageProcessing/

Image processing routines.

Externals/

Vendored third-party sources (FreeImage, libxml2, podofo, gigabase, cppunit, …).

Setup/, Scripts/

Installer (WiX) and build / release scripts.

TestData/

Fixtures for the test executables.

Tests use cppunit with mfcTestRunner, one test executable per layer: Tahiti/TahitiTest, TahitiBase/TahitiBaseTest, TahitiCore/TahitiCoreTest, Communication/tciolTest.

Errors, logging, ownership

  • Errors are accumulated, not thrown. The convention is a bool return plus a trailing TahitiException &tahitiException out-parameter. Add context with TAHITI_EXCEPTION("msg") (it references the local named tahitiException), TAHITI_EXCEPTION_OBJECT(obj, "msg") or TAHITI_EXCEPTION_LOCAL("msg"). For COM failures use TAHITI_COM_EXCEPTION(msg, pUnk, piid, hr) from TahitiBase/ComUtils.h.

  • Logging (TahitiBase/logger.h): _LOG_SYS_DEBUG(x), _LOG_SYS_INFO(x), _LOG_SYS(level, x) with _LOG_LEVEL_CRITICAL | MEDIUM | INFO | DEBUG. Pass a u8string or a U8StringBuilder. Never log secrets, see Handling of secrets in memory.

  • Reference counting (TahitiBase/ReferenceCounter.h): lcbase::Reference<T> is the smart pointer, lcbase::ReferencedImpl<T> the instantiable wrapper:

    lcbase::Reference<Foo> f(new lcbase::ReferencedImpl<Foo>());
    
  • COM uses CComPtr, _variant_t, _bstr_t and vtMissing for optional arguments.

Architecture

A TahitiDomain owns a TahitiDomainComponentManager. Features are TahitiDomainComponent instances registered under a name and resolved at runtime:

TahitiDomainComponent *pComponent =
    getDomain()->getComponentManager()->get(TU8(COMPONENT_DOCUMENTMANAGER_NAME));
DocumentManagerComponentBase *pDocMgr =
    dynamic_cast<DocumentManagerComponentBase *>(pComponent);

Cross-module access goes through pure-virtual interface headers (...I.h, ...Base.h), so modules depend on interfaces rather than on each other’s implementations. When a module needs to expose something new, extend its interface header; do not reach into the concrete class.

The main window is MainFrame : CMDSIFrameWnd (Tahiti/Tahiti/MainFrame.cpp). The ribbon is BCGControlBar Pro (CBCGPRibbonBar / CBCGPRibbonPanel / CBCGPRibbonButton).

Recipe: adding a UI command

  1. Resource id - add #define ID_MY_CMD <n> to Tahiti/TahitiCommon/resource.h.in (CMake copies it to resource.h). Add icon PNG entries with their own ids to Tahiti/Tahiti/res/Tahiti.rc2.

  2. Command class - subclass TahitiCommon::MenuCommandBase and TahitiCommon::CommandHandler; use Tahiti/Tahiti/ViewHistoryCmd.{h,cpp} as the template. Implement getMenuItemId(), getMenuItem(), onCommand(), onUpdateCommand().

  3. Register in MainFrame::registerViewCommands(). Either registerCommandHandler(ID_MY_CMD, cmd->getHandler()) binds the handler to a fixed resource id (ribbon and classic menu reference ID_MY_CMD), or registerViewCommand(cmd) binds it to the string id from the id manager and appends it to the dynamic view-command list. Pick one.

  4. String id (only for registerViewCommand) - add ids.push_back(TahitiIdManagerId(TU8("My.Command"), 0)); in Tahiti/Tahiti/MainApp.cpp (addPredefinedMainIds / addPredefinedViewIds / addPredefinedToolbarIds).

  5. Menus - ribbon button in the relevant Create*Panel() of MainFrame.cpp; classic menu entry in Tahiti/TahitiCommon/TahitiDocTemplate.cpp.

  6. Labels - add the key to Tahiti/locale/{cs,en}/<Bundle>.properties.

  7. Build - add the new files to the module’s CMakeLists.txt.

Localization

.properties bundles per module live under Tahiti/locale/<lang>/. Translations exist for cs and en; add every new key to both. Lookup macros (TahitiBase/localize.h, Tahiti/TahitiCommon/LocalizedStrings.h): _TR_UI_TU8("Key") (default bundle), _TRB_UI_TU8("Bundle", "Key") (explicit bundle), LS_TAHITICOMMON_UI("Key") (the TahitiCommon bundle). Since 7.7 the application language follows the system language unless the user overrides it in Options; a language is available when its locale subdirectory contains the Common bundle.

Style

  • Indentation is inconsistent by file age: older files use tabs, newer or rewritten ones use 4 spaces. Follow the file you are editing; do not reflow surrounding code.

  • Doxygen comments: /*! \brief ... */ or /** ... */.

  • Members are m_-prefixed with a type hint: m_str... string, m_b... bool, m_i... int, m_sp... smart / COM pointer. Parameters use p... pointer, i... int, str... string, b... bool.

  • Commit messages are written in Czech, usually #<ticket> - <description>; release commits contain only the version number.