Development
This guide covers building paperman from source and working on the codebase.
Prerequisites
The quickest way to set up a build environment is:
make setup
This installs all Debian packages, the Flutter SDK, Java JDK and the Android SDK. For a lighter install that only covers the Qt5/C++ desktop app and server:
scripts/setup.sh --qt
The full list of what the script installs is documented in
scripts/setup.sh. The manual steps are shown below for reference.
Qt5/C++ dependencies (desktop app + server):
sudo apt-get install -y \
build-essential qt5-qmake qtbase5-dev qtbase5-dev-tools \
libqt5sql5-sqlite libpoppler-qt5-dev libpodofo-dev \
libtiff-dev libjpeg-dev libsane-dev zlib1g-dev \
imagemagick tesseract-ocr tesseract-ocr-eng
Qt6/C++ dependencies (alternative to Qt5):
sudo apt-get install -y \
build-essential qmake6 qt6-base-dev qt6-base-dev-tools \
libqt6sql6-sqlite libpoppler-qt6-dev libpodofo-dev \
qt6-scxml-dev libqt6statemachine6 \
libtiff-dev libjpeg-dev libsane-dev zlib1g-dev \
imagemagick tesseract-ocr tesseract-ocr-eng
Python packages for demo-asset generation and documentation:
sudo apt-get install -y \
python3-reportlab python3-pil python3-numpy poppler-utils \
python3-sphinx python3-sphinx-rtd-theme
Flutter app (Android + Linux desktop) additionally needs the Flutter SDK,
Java 21 and several Linux desktop libraries. See scripts/setup.sh for
the full details.
Building
Generate the qmake Makefile and build with Qt5:
qmake "CONFIG+=test" paperman.pro
make
Or with Qt6:
qmake6 "CONFIG+=test" paperman.pro -o Makefile.qt6
make -f Makefile.qt6
The CONFIG+=test flag compiles in the built-in test suites. Without it
the -t option is not available.
The top-level GNUmakefile wraps the qmake-generated Makefile and adds
extra targets. GNU make picks it up automatically, so a plain make in the
project root builds everything including the server, Flutter app and Sphinx
documentation. Run make help to list all targets.
Project Layout
*.cpp / *.h Desktop app sources (Qt Widgets)
qi/ Scanner interface widgets
test/ Test sources and generated test data
scripts/ Helper scripts (test-file generation, etc.)
doc/ Sphinx documentation
app/ Flutter mobile app
paperman.pro Qt project file (desktop app)
paperman-server.pro Qt project file (search server)
GNUmakefile Top-level build wrapper
Key Source Files
desktopmodel.cppCentral model that manages the stack/page tree shown in the GUI.
file.cpp,filemax.cpp,filepdf.cpp,filejpeg.cppFile-format backends.
Fileis the abstract base; the subclasses handle .max, .pdf and .jpg respectively.dirmodel.cppDirectory tree model for the left-hand panel.
desktopundo.cpp,dmop.cpp,dmuserop.cppUndo/redo framework and desktop-model operations.
searchserver.cppEmbedded HTTP server for the REST API.
searchindex.cppSQLite FTS5 index used by the search server.
Testing
See Testing for full details on running and writing tests.
Quick reference:
# Run all suites
QT_QPA_PLATFORM=offscreen ./paperman -t
# Run a single suite
QT_QPA_PLATFORM=offscreen ./paperman -t TestOps
# List available suites
./paperman -t list
# Generate test files (also done automatically by 'make test')
make test-setup
Test suites live in test/ and are registered in test/suite.cpp. Each
suite is a QObject subclass using the Qt Test framework (QCOMPARE,
QVERIFY, etc.). Test data files are generated at build time by
scripts/make_test_files.py and are not tracked in git.
Build Targets
The most useful targets during development:
make setup # Install all build dependencies
make paperman # Build the desktop app only
make test # Build and run all tests (includes test-setup)
make test-setup # Generate test files without running tests
make app-test # Run Flutter widget tests
make docs # Build the Sphinx documentation
make clean # Remove all build artefacts
Continuous Integration
A GitHub Actions workflow (.github/workflows/ci.yml) runs on every push
to master and on pull requests. It has four parallel jobs:
- qt — Desktop app, server and C++ tests (Qt5)
Installs Qt5/C++ dependencies, builds
papermanandpaperman-server, generates test data, then runs the Qt unit tests, page-fetch integration test and parallel conversion test.- qt6 — Desktop app, server and C++ tests (Qt6)
Same as qt but builds against Qt6 instead of Qt5.
- flutter — Flutter app and widget tests
Sets up Java 21 and Flutter 3.41.1, generates demo assets, runs
flutter analyzeandflutter test, then builds a release APK and uploads it as a build artefact.- docs — Sphinx documentation
Installs Python 3.12, the Sphinx dependencies from
doc/requirements.txtand builds the HTML documentation.
Coding Style
C++ sources use Qt naming conventions (camelCase for methods, CamelCase for classes)
Indentation is 3 spaces in most files
Commit messages use present/imperative tense and British spelling
Main Classes
The display is laid out as follows:
Mainwindow (QMainWindow)
+-- Mainwidget (QStackedWidget)
|
+-- Page 0: Desktopwidget (QSplitter, horizontal)
| |
| +-- LEFT: Dirview (QTreeView)
| | Model: Dirmodel
| |
| +-- MIDDLE: QWidget "group"
| | +-- Toolbar
| | +-- Desktopview (QListView, IconMode)
| | Delegate: Desktopdelegate
| | Model: Desktopmodel via Desktopproxy
| |
| +-- RIGHT: Pagewidget
| +-- Pagetools (toolbar, from pagetools.ui)
| +-- QStackedWidget
| +-- _splitter (QSplitter, horizontal)
| | |
| | +-- LEFT: Pageview (QListView, IconMode)
| | | Delegate: Pagedelegate
| | | Model: Pagemodel
| | |
| | +-- RIGHT: _ocr_split (QSplitter, vertical)
| | +-- TOP: MyScrollArea (big page preview)
| | +-- BOTTOM: OCR area (QTextEdit + Ocrbar)
| |
| +-- _textframe (annotation/info view)
|
+-- Page 1: Pagewidget (single-stack view, used for full-screen)