mirror of
https://github.com/YACReader/yacreader
synced 2025-05-28 03:10:27 -04:00
Focusing the current comics view allows to use keyboard arrow keys to choose among the visible comics. The shortcut for this new action should not be a single character without modifiers because it won't work when the search line has focus. The Qt::FocusReason parameter in ComicsView::focusComicsNavigation() allows to reuse this function for other keyboard navigation features. For instance the search line can transfer focus to comics navigation when the user presses Return or Enter key. In this case Qt::OtherFocusReason can be used (an application-specific reason).
378 lines
12 KiB
C++
378 lines
12 KiB
C++
#include "classic_comics_view.h"
|
|
|
|
#include "QStackedWidget"
|
|
|
|
#include "comic_flow_widget.h"
|
|
#include "QsLog.h"
|
|
#include "shortcuts_manager.h"
|
|
#include "yacreader_table_view.h"
|
|
#include "yacreader_tool_bar_stretch.h"
|
|
|
|
ClassicComicsView::ClassicComicsView(QWidget *parent)
|
|
: ComicsView(parent), searching(false)
|
|
{
|
|
auto layout = new QHBoxLayout;
|
|
|
|
settings = new QSettings(YACReader::getSettingsPath() + "/YACReaderLibrary.ini", QSettings::IniFormat); //TODO unificar la creación del fichero de config con el servidor
|
|
settings->beginGroup("libraryConfig");
|
|
//FLOW-----------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
//FORCE_ANGLE is not used here, because ComicFlowWidgetGL will use OpenGL ES in the future
|
|
#ifndef NO_OPENGL
|
|
if ((settings->value(USE_OPEN_GL).toBool() == true))
|
|
comicFlow = new ComicFlowWidgetGL(0);
|
|
else
|
|
comicFlow = new ComicFlowWidgetSW(0);
|
|
#else
|
|
comicFlow = new ComicFlowWidgetSW(0);
|
|
#endif
|
|
comicFlow->updateConfig(settings);
|
|
comicFlow->setFocusPolicy(Qt::StrongFocus);
|
|
comicFlow->setShowMarks(true);
|
|
setFocusProxy(comicFlow);
|
|
|
|
comicFlow->setFocus(Qt::OtherFocusReason);
|
|
|
|
comicFlow->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
//layout-----------------------------------------------
|
|
sVertical = new QSplitter(Qt::Vertical); //spliter derecha
|
|
|
|
stack = new QStackedWidget;
|
|
stack->addWidget(comicFlow);
|
|
setupSearchingIcon();
|
|
stack->addWidget(searchingIcon);
|
|
|
|
sVertical->addWidget(stack);
|
|
comics = new QWidget;
|
|
auto comicsLayout = new QVBoxLayout;
|
|
comicsLayout->setSpacing(0);
|
|
comicsLayout->setContentsMargins(0, 0, 0, 0);
|
|
//TODO ComicsView:(set toolbar) comicsLayout->addWidget(editInfoToolBar);
|
|
|
|
tableView = new YACReaderTableView;
|
|
tableView->verticalHeader()->hide();
|
|
tableView->setFocusPolicy(Qt::StrongFocus);
|
|
comicsLayout->addWidget(tableView);
|
|
comics->setLayout(comicsLayout);
|
|
sVertical->addWidget(comics);
|
|
|
|
tableView->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
//config--------------------------------------------------
|
|
if (settings->contains(COMICS_VIEW_HEADERS))
|
|
tableView->horizontalHeader()->restoreState(settings->value(COMICS_VIEW_HEADERS).toByteArray());
|
|
|
|
//connections---------------------------------------------
|
|
connect(tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(centerComicFlow(QModelIndex)));
|
|
connect(tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(selectedComicForOpening(QModelIndex)));
|
|
connect(comicFlow, SIGNAL(centerIndexChanged(int)), this, SLOT(updateTableView(int)));
|
|
connect(tableView, SIGNAL(comicRated(int, QModelIndex)), this, SIGNAL(comicRated(int, QModelIndex)));
|
|
connect(comicFlow, SIGNAL(selected(uint)), this, SIGNAL(selected(uint)));
|
|
connect(tableView->horizontalHeader(), SIGNAL(sectionMoved(int, int, int)), this, SLOT(saveTableHeadersStatus()));
|
|
connect(tableView->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), this, SLOT(saveTableHeadersStatus()));
|
|
connect(comicFlow, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(requestedViewContextMenu(QPoint)));
|
|
connect(tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(requestedItemContextMenu(QPoint)));
|
|
layout->addWidget(sVertical);
|
|
setLayout(layout);
|
|
|
|
layout->setMargin(0);
|
|
|
|
#ifdef Q_OS_MAC
|
|
sVertical->setCollapsible(1, false);
|
|
#endif
|
|
|
|
if (settings->contains(COMICS_VIEW_FLOW_SPLITTER_STATUS))
|
|
sVertical->restoreState(settings->value(COMICS_VIEW_FLOW_SPLITTER_STATUS).toByteArray());
|
|
|
|
//hide flow widgets
|
|
hideFlowViewAction = new QAction(this);
|
|
hideFlowViewAction->setText(tr("Hide comic flow"));
|
|
hideFlowViewAction->setData(HIDE_COMIC_VIEW_ACTION_YL);
|
|
hideFlowViewAction->setShortcut(ShortcutsManager::getShortcutsManager().getShortcut(HIDE_COMIC_VIEW_ACTION_YL));
|
|
hideFlowViewAction->setIcon(QIcon(":/images/comics_view_toolbar/hideComicFlow.png"));
|
|
hideFlowViewAction->setCheckable(true);
|
|
hideFlowViewAction->setChecked(false);
|
|
|
|
connect(hideFlowViewAction, SIGNAL(toggled(bool)), this, SLOT(hideComicFlow(bool)));
|
|
}
|
|
|
|
void ClassicComicsView::hideComicFlow(bool hide)
|
|
{
|
|
if (hide) {
|
|
QList<int> sizes;
|
|
sizes.append(0);
|
|
int total = sVertical->sizes().at(0) + sVertical->sizes().at(1);
|
|
sizes.append(total);
|
|
sVertical->setSizes(sizes);
|
|
} else {
|
|
QList<int> sizes;
|
|
int total = sVertical->sizes().at(0) + sVertical->sizes().at(1);
|
|
sizes.append(2 * total / 3);
|
|
sizes.append(total / 3);
|
|
sVertical->setSizes(sizes);
|
|
}
|
|
}
|
|
|
|
//the toolbar has to be populated
|
|
void ClassicComicsView::setToolBar(QToolBar *toolBar)
|
|
{
|
|
static_cast<QVBoxLayout *>(comics->layout())->insertWidget(0, toolBar);
|
|
this->toolbar = toolBar;
|
|
|
|
toolBarStretch = new YACReaderToolBarStretch(this);
|
|
|
|
toolBarStretchAction = toolBar->addWidget(toolBarStretch);
|
|
toolBar->addAction(hideFlowViewAction);
|
|
}
|
|
|
|
void ClassicComicsView::setModel(ComicModel *model)
|
|
{
|
|
ComicsView::setModel(model);
|
|
|
|
if (model == NULL) {
|
|
comicFlow->clear();
|
|
} else {
|
|
connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex, QVector<int>)), this, SLOT(applyModelChanges(QModelIndex, QModelIndex, QVector<int>)), Qt::UniqueConnection);
|
|
connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(removeItemsFromFlow(QModelIndex, int, int)), Qt::UniqueConnection);
|
|
connect(model, SIGNAL(resortedIndexes(QList<int>)), comicFlow, SLOT(resortCovers(QList<int>)), Qt::UniqueConnection);
|
|
connect(model, SIGNAL(newSelectedIndex(QModelIndex)), this, SLOT(setCurrentIndex(QModelIndex)), Qt::UniqueConnection);
|
|
|
|
tableView->setModel(model);
|
|
if (model->rowCount() > 0)
|
|
tableView->setCurrentIndex(model->index(0, 0));
|
|
|
|
tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
|
|
#if QT_VERSION >= 0x050000
|
|
tableView->horizontalHeader()->setSectionsMovable(true);
|
|
#else
|
|
tableView->horizontalHeader()->setMovable(true);
|
|
#endif
|
|
//TODO parametrizar la configuración de las columnas
|
|
/*if(!settings->contains(COMICS_VIEW_HEADERS))
|
|
{*/
|
|
for (int i = 0; i < tableView->horizontalHeader()->count(); i++)
|
|
tableView->horizontalHeader()->hideSection(i);
|
|
|
|
tableView->horizontalHeader()->showSection(ComicModel::Number);
|
|
tableView->horizontalHeader()->showSection(ComicModel::Title);
|
|
tableView->horizontalHeader()->showSection(ComicModel::FileName);
|
|
tableView->horizontalHeader()->showSection(ComicModel::NumPages);
|
|
tableView->horizontalHeader()->showSection(ComicModel::Hash); //Size is part of the Hash...TODO add Columns::Size to Columns
|
|
tableView->horizontalHeader()->showSection(ComicModel::ReadColumn);
|
|
tableView->horizontalHeader()->showSection(ComicModel::CurrentPage);
|
|
tableView->horizontalHeader()->showSection(ComicModel::Rating);
|
|
//}
|
|
|
|
//debido a un bug, qt4 no es capaz de ajustar el ancho teniendo en cuenta todas la filas (no sólo las visibles)
|
|
//así que se ecala la primera vez y después se deja el control al usuario.
|
|
//if(!settings->contains(COMICS_VIEW_HEADERS))
|
|
|
|
QStringList paths = model->getPaths(model->getCurrentPath()); //TODO ComicsView: get currentpath from somewhere currentPath());
|
|
comicFlow->setImagePaths(paths);
|
|
comicFlow->setMarks(model->getReadList());
|
|
//comicFlow->setFocus(Qt::OtherFocusReason);
|
|
|
|
if (settings->contains(COMICS_VIEW_HEADERS))
|
|
tableView->horizontalHeader()->restoreState(settings->value(COMICS_VIEW_HEADERS).toByteArray());
|
|
|
|
tableView->resizeColumnsToContents();
|
|
|
|
tableView->horizontalHeader()->setStretchLastSection(true);
|
|
}
|
|
}
|
|
|
|
void ClassicComicsView::setCurrentIndex(const QModelIndex &index)
|
|
{
|
|
tableView->setCurrentIndex(index);
|
|
centerComicFlow(index);
|
|
}
|
|
|
|
QModelIndex ClassicComicsView::currentIndex()
|
|
{
|
|
return tableView->currentIndex();
|
|
}
|
|
|
|
QItemSelectionModel *ClassicComicsView::selectionModel()
|
|
{
|
|
return tableView->selectionModel();
|
|
}
|
|
|
|
void ClassicComicsView::scrollTo(const QModelIndex &mi, QAbstractItemView::ScrollHint hint)
|
|
{
|
|
Q_UNUSED(hint);
|
|
|
|
comicFlow->setCenterIndex(mi.row());
|
|
}
|
|
|
|
void ClassicComicsView::toFullScreen()
|
|
{
|
|
comicFlow->hide();
|
|
comicFlow->setCenterIndex(comicFlow->centerIndex());
|
|
comics->hide();
|
|
|
|
//showFullScreen() //parent windows
|
|
|
|
comicFlow->show();
|
|
comicFlow->setFocus(Qt::OtherFocusReason);
|
|
}
|
|
|
|
void ClassicComicsView::toNormal()
|
|
{
|
|
comicFlow->hide();
|
|
comicFlow->setCenterIndex(comicFlow->centerIndex());
|
|
comicFlow->render();
|
|
comics->show();
|
|
comicFlow->show();
|
|
}
|
|
|
|
void ClassicComicsView::updateConfig(QSettings *settings)
|
|
{
|
|
comicFlow->updateConfig(settings);
|
|
}
|
|
|
|
void ClassicComicsView::enableFilterMode(bool enabled)
|
|
{
|
|
if (enabled) {
|
|
comicFlow->clear();
|
|
if (previousSplitterStatus.isEmpty())
|
|
previousSplitterStatus = sVertical->saveState();
|
|
sVertical->setSizes(QList<int>() << 100 << 10000000);
|
|
showSearchingIcon();
|
|
} else {
|
|
hideSearchingIcon();
|
|
sVertical->restoreState(previousSplitterStatus);
|
|
previousSplitterStatus.clear();
|
|
}
|
|
|
|
//sVertical->setCollapsible(0,!enabled);
|
|
searching = enabled;
|
|
}
|
|
|
|
void ClassicComicsView::selectIndex(int index)
|
|
{
|
|
tableView->selectRow(index);
|
|
}
|
|
|
|
void ClassicComicsView::updateCurrentComicView()
|
|
{
|
|
}
|
|
|
|
void ClassicComicsView::focusComicsNavigation(Qt::FocusReason reason)
|
|
{
|
|
const bool comicFlowVisible = stack->currentWidget() == comicFlow && sVertical->sizes().constFirst() != 0;
|
|
if (comicFlowVisible)
|
|
comicFlow->setFocus(reason);
|
|
else // Let the user navigate the table.
|
|
tableView->setFocus(reason);
|
|
}
|
|
|
|
void ClassicComicsView::selectAll()
|
|
{
|
|
tableView->selectAll();
|
|
}
|
|
|
|
void ClassicComicsView::selectedComicForOpening(const QModelIndex &mi)
|
|
{
|
|
emit selected(mi.row());
|
|
}
|
|
|
|
void ClassicComicsView::requestedViewContextMenu(const QPoint &point)
|
|
{
|
|
emit customContextMenuViewRequested(comicFlow->mapTo(this, point));
|
|
}
|
|
|
|
void ClassicComicsView::requestedItemContextMenu(const QPoint &point)
|
|
{
|
|
emit customContextMenuItemRequested(tableView->mapTo(this, point));
|
|
}
|
|
|
|
void ClassicComicsView::setShowMarks(bool show)
|
|
{
|
|
comicFlow->setShowMarks(show);
|
|
}
|
|
|
|
void ClassicComicsView::centerComicFlow(const QModelIndex &mi)
|
|
{
|
|
comicFlow->showSlide(mi.row());
|
|
comicFlow->setFocus(Qt::OtherFocusReason);
|
|
}
|
|
|
|
void ClassicComicsView::updateTableView(int i)
|
|
{
|
|
QModelIndex mi = model->index(i, 2);
|
|
tableView->setCurrentIndex(mi);
|
|
tableView->scrollTo(mi, QAbstractItemView::EnsureVisible);
|
|
}
|
|
|
|
void ClassicComicsView::saveTableHeadersStatus()
|
|
{
|
|
settings->setValue(COMICS_VIEW_HEADERS, tableView->horizontalHeader()->saveState());
|
|
}
|
|
|
|
void ClassicComicsView::saveSplitterStatus()
|
|
{
|
|
settingsMutex.lock();
|
|
if (!searching)
|
|
settings->setValue(COMICS_VIEW_FLOW_SPLITTER_STATUS, sVertical->saveState());
|
|
settingsMutex.unlock();
|
|
}
|
|
|
|
void ClassicComicsView::applyModelChanges(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
|
|
{
|
|
Q_UNUSED(topLeft);
|
|
Q_UNUSED(bottomRight);
|
|
if (roles.contains(ComicModel::ReadColumnRole)) {
|
|
comicFlow->setMarks(model->getReadList());
|
|
comicFlow->updateMarks();
|
|
}
|
|
}
|
|
|
|
void ClassicComicsView::removeItemsFromFlow(const QModelIndex &parent, int from, int to)
|
|
{
|
|
Q_UNUSED(parent);
|
|
for (int i = from; i <= to; i++)
|
|
comicFlow->remove(i);
|
|
}
|
|
|
|
void ClassicComicsView::closeEvent(QCloseEvent *event)
|
|
{
|
|
toolbar->removeAction(toolBarStretchAction);
|
|
toolbar->removeAction(hideFlowViewAction);
|
|
|
|
saveTableHeadersStatus();
|
|
saveSplitterStatus();
|
|
ComicsView::closeEvent(event);
|
|
}
|
|
|
|
void ClassicComicsView::setupSearchingIcon()
|
|
{
|
|
searchingIcon = new QWidget(comicFlow);
|
|
|
|
auto h = new QHBoxLayout;
|
|
|
|
QPixmap p(":/images/searching_icon.png");
|
|
QLabel *l = new QLabel(searchingIcon);
|
|
l->setPixmap(p);
|
|
l->setFixedSize(p.size());
|
|
h->addWidget(l, 0, Qt::AlignCenter);
|
|
searchingIcon->setLayout(h);
|
|
|
|
QPalette pal(searchingIcon->palette());
|
|
pal.setColor(QPalette::Background, Qt::black);
|
|
searchingIcon->setAutoFillBackground(true);
|
|
searchingIcon->setPalette(pal);
|
|
|
|
hideSearchingIcon();
|
|
}
|
|
|
|
void ClassicComicsView::showSearchingIcon()
|
|
{
|
|
stack->setCurrentWidget(searchingIcon);
|
|
}
|
|
|
|
void ClassicComicsView::hideSearchingIcon()
|
|
{
|
|
stack->setCurrentWidget(comicFlow);
|
|
}
|