This way we can tell the app that a folder contains mangas so the user doesn't have to constantly set comics as manga when new issues are added. And it should be easier to set all the content in a folder as manga from the folder tree.
List initialization ended using movable constructors which surprisingly caused data troubles in release mode, at least in VC2019 compiler. The tree being messed up caused crashes while SQL was generated.
I have no explanation for it.
When setting ports, temporary or for good, we need to go via the config
files and not QTcpServer or we get undefined behavior. To support temp
ports, we need to back up the fixed port in the settings.
In a later commit WorkerThread should also replace classes similar to
ImageLoader: PageLoader, ImageLoaderGL and ImageLoaderByteArrayGL.
Bugs fixed:
1. Eliminated a data race between ImageLoader::run() and
ComicFlow::updateImageData()->ImageLoader::result(). Specifically when
ImageLoader::busy() returns false, then ImageLoader::run() sets
ImageLoader::working to true, loads the image and starts assigning it to
ImageLoader::img, while ImageLoader::result() is accessed without
locking from updateImageData().
Making ImageLoader::working atomic is clearly insufficient to eliminate
this data race. The fix is to set 'working' to true immediately and
synchronously as soon as a new task is assigned to the worker.
2. Replaced thread termination with graceful thread exit. ComicFlow
destructor called QThread::terminate(), using which is discouraged by Qt
documentation. The application exited without errors in Release mode.
In Debug mode, however, it received the SIG32 signal on exit and printed
the following warning - "QWaitCondition: mutex destroy failure:
Device or resource busy".
The loop in WorkerThread::run() is no longer endless. The worker thread
properly ends and is joined in WorkerThread destructor.
Design decisions:
1. WorkerThread could emit a signal when it completes a task.
Thus updateTimer could be removed from ComicFlow and GoToFlow. However,
there is no obvious way to use this new signal in the two GL classes.
Also I don't know whether updateTimer is just an inefficient polling
substitute for notification or an intentional animation mechanism.
2. The index variable is no longer stored in the worker class, but in
ComicFlow directly. Thing is, this data member was never actually
accessed by the worker, but ComicFlow went so far as to lock worker's
mutex to "protect" access to the index.
3. The common ImageLoader implementation turned out to be very general.
So I converted it into the WorkerThread class template that is not
restricted to producing QImage results and can be reused elsewhere.
4. I used standard classes (such as std::thread) instead of their Qt
equivalents (e.g. QThread) because they are more thoroughly documented.
The standard classes should also be more efficient as they were more
carefully designed and provide much fewer unnecessary features.
5. Release-Acquire ordering is safe for the WorkerThread::working
use case and is more efficient than the std::atomic-default
Sequentially-consistent ordering.
6. condition.notify_one() is called while the mutex is unlocked
to improve performance. This is safe in both cases:
a) if the worker thread exits due to a spurious wakeup just before
the condition.notify_one() call in WorkerThread destructor, so much the
better;
b) if a spurious wakeup lets the worker thread finish the task and
start waiting on the condition again just before the
condition.notify_one() call in WorkerThread::performTask(), the second
waking will be ignored by the worker thread as 'working' and 'abort'
will be false then.
Manual editing of a config file for setting a port is not ideal.
Solution: add a set-port command to save a port and also a
--port option to allow setting a temporary port during startup
Qt's database and query model requires that both the queries and the database
objects are out of scope before a database connection can safely be removed.
Solution: Properly encapsulate databases and queries in "{ }" and use a string
to cache the connection name for out-of-scope removal.
- Adapt server code for QtWebapp namespace 'stefanfrings'
- Implement custom modifications needed by v1 controller
via template engine
- Unify iphone and ipad templates
server_config_dialog.cpp:57:30: error: member access into incomplete type 'struct sockaddr'
if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
^
/usr/local/include/qt5/QtNetwork/qhostaddress.h:50:8: note: forward declaration of 'sockaddr'
struct sockaddr;
^
server_config_dialog.cpp:61:27: error: use of undeclared identifier 'AF_INET'
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
^
server_config_dialog.cpp:64:37: error: member access into incomplete type 'struct sockaddr'
} else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
^
/usr/local/include/qt5/QtNetwork/qhostaddress.h:50:8: note: forward declaration of 'sockaddr'
struct sockaddr;
^
server_config_dialog.cpp:68:27: error: use of undeclared identifier 'AF_INET6'
inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
^
Stopped QThreads don't process events, so cleanup signals get lost.
Prevent this from happening by keeping the threads alive and the comic
inside the thread (as we already do in the viewer). Cleanup happens by
connecting the comic's destroyed() signal to the thread's quit() slot.
Adds vertical navigation (up down) to FlowView. This corresponds visually to the File Name list display -- especially when the flow pane is hidden, pressing up-down is the intuitive way to navigate up-down in the list.
There were many run-time warnings in YACReaderLibrary built in Debug
mode with hardware acceleration disabled and with ClassicComicsView
as the active comics view:
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
The ComicFlowWidgetSW::paintEvent() implementation now corresponds to
ComicFlowWidgetGL::paintEvent(), which has been fixed earlier.
QWidget::repaint() calls paintEvent() immediately.
PictureFlow::paintEvent() calls d->renderer->paint(). So the
d->renderer->paint() call in PictureFlow::updateMarks() was redundant.