goldendict-ng/src/ui/historypanewidget.cc
2023-06-11 11:27:49 -04:00

264 lines
7.8 KiB
C++

/* This file is (c) 2013 Tvangeste <i.4m.l33t@yandex.ru>
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
#include <QApplication>
#include <QDockWidget>
#include <QKeyEvent>
#include <QClipboard>
#include <algorithm>
#include <functional>
#include "historypanewidget.hh"
void HistoryPaneWidget::setUp( Config::Class * cfg, History * history, QMenu * menu )
{
m_cfg = cfg;
m_history = history;
m_historyList = findChild<QListView*>( "historyList" );
QDockWidget * historyPane = qobject_cast<QDockWidget*>( parentWidget() );
// Delete selected items action
m_deleteSelectedAction = new QAction( this );
m_deleteSelectedAction->setText( tr( "&Delete Selected" ) );
m_deleteSelectedAction->setShortcut( QKeySequence( QKeySequence::Delete ) );
m_deleteSelectedAction->setShortcutContext( Qt::WidgetWithChildrenShortcut );
addAction( m_deleteSelectedAction );
connect( m_deleteSelectedAction, &QAction::triggered, this, &HistoryPaneWidget::deleteSelectedItems );
// Copy selected items to clipboard
m_copySelectedToClipboard = new QAction( this );
m_copySelectedToClipboard->setText( tr( "Copy Selected" ) );
m_copySelectedToClipboard->setShortcut( QKeySequence( QKeySequence::Copy ) );
m_copySelectedToClipboard->setShortcutContext( Qt::WidgetWithChildrenShortcut );
addAction( m_copySelectedToClipboard );
connect( m_copySelectedToClipboard, &QAction::triggered, this, &HistoryPaneWidget::copySelectedItems );
// Handle context menu, reusing some of the top-level window's History menu
m_historyMenu = new QMenu( this );
m_separator = m_historyMenu->addSeparator();
QListIterator<QAction *> actionsIter( menu->actions() );
while ( actionsIter.hasNext() )
m_historyMenu->addAction( actionsIter.next() );
// Make the history pane's titlebar
historyLabel.setText( tr( "History:" ) );
historyLabel.setObjectName( "historyLabel" );
historyCountLabel.setObjectName( "historyCountLabel" );
if ( layoutDirection() == Qt::LeftToRight )
{
historyLabel.setAlignment( Qt::AlignLeft );
historyCountLabel.setAlignment( Qt::AlignRight );
}
else
{
historyLabel.setAlignment( Qt::AlignRight );
historyCountLabel.setAlignment( Qt::AlignLeft );
}
updateHistoryCounts();
historyPaneTitleBarLayout.addWidget( &historyLabel );
historyPaneTitleBarLayout.addWidget( &historyCountLabel );
historyPaneTitleBarLayout.setContentsMargins(5, 5, 5, 5);
historyPaneTitleBar.setLayout( &historyPaneTitleBarLayout );
historyPaneTitleBar.setObjectName("historyPaneTitleBar");
historyPane->setTitleBarWidget( &historyPaneTitleBar );
// History list
HistoryModel * historyModel = new HistoryModel( m_history, this );
m_historyList->setModel( historyModel );
m_historyList->setContextMenuPolicy( Qt::CustomContextMenu );
// very important call, for performance reasons:
m_historyList->setUniformItemSizes( true );
m_historyList->setSelectionMode( QAbstractItemView::ExtendedSelection );
m_historyList->installEventFilter( this );
m_historyList->viewport()->installEventFilter( this );
// list selection and keyboard navigation
connect( m_historyList, &QAbstractItemView::clicked, this, &HistoryPaneWidget::onItemClicked );
connect( m_history, &History::itemsChanged, this, &HistoryPaneWidget::updateHistoryCounts );
connect( m_historyList->selectionModel(),
&QItemSelectionModel::selectionChanged,
this,
&HistoryPaneWidget::onSelectionChanged );
connect( m_historyList, &QWidget::customContextMenuRequested, this, &HistoryPaneWidget::showCustomMenu );
listItemDelegate = new WordListItemDelegate( m_historyList->itemDelegate() );
m_historyList->setItemDelegate( listItemDelegate );
}
HistoryPaneWidget::~HistoryPaneWidget()
{
if( listItemDelegate )
delete listItemDelegate;
}
void HistoryPaneWidget::copySelectedItems()
{
QModelIndexList selectedIdxs = m_historyList->selectionModel()->selectedIndexes();
if ( selectedIdxs.isEmpty() )
{
// nothing to do
return;
}
QStringList selectedStrings;
QListIterator<QModelIndex> i( selectedIdxs );
while ( i.hasNext() )
{
selectedStrings << m_historyList->model()->data( i.next() ).toString();
}
QApplication::clipboard()->setText( selectedStrings.join( QString::fromLatin1( "\n" ) ) );
}
void HistoryPaneWidget::deleteSelectedItems()
{
QModelIndexList selectedIdxs = m_historyList->selectionModel()->selectedIndexes();
if ( selectedIdxs.isEmpty() )
{
// nothing to do
return;
}
QList<int> idxsToDelete;
QListIterator<QModelIndex> i( selectedIdxs );
while ( i.hasNext() )
{
idxsToDelete << i.next().row();
}
// Need to sort indexes in the decreasing order so that
// the first deletions won't affect the indexes for subsequent deletions.
std::sort( idxsToDelete.begin(), idxsToDelete.end(), std::greater<int>() );
QListIterator<int> idxs( idxsToDelete );
while ( idxs.hasNext() )
m_history->removeItem( idxs.next() );
if ( idxsToDelete.size() == 1 )
{
// We've just removed a single entry,
// keep the selection at the same index.
m_historyList->setCurrentIndex(selectedIdxs.front());
m_historyList->selectionModel()->select(
selectedIdxs.front(), QItemSelectionModel::SelectCurrent );
}
else
{
// Too many deletions, better to reset the selection.
m_historyList->selectionModel()->reset();
}
}
bool HistoryPaneWidget::eventFilter( QObject * obj, QEvent * ev )
{
// unused for now
return QWidget::eventFilter( obj, ev );
}
void HistoryPaneWidget::showCustomMenu(QPoint const & pos)
{
bool selectionEmpty = m_historyList->selectionModel()->selection().empty();
m_historyMenu->removeAction( m_copySelectedToClipboard );
m_historyMenu->removeAction( m_deleteSelectedAction );
m_separator->setVisible( !selectionEmpty );
if ( !selectionEmpty )
{
m_historyMenu->insertAction( m_separator, m_copySelectedToClipboard );
m_historyMenu->insertAction( m_separator, m_deleteSelectedAction );
}
m_historyMenu->exec( m_historyList->mapToGlobal( pos ) );
}
void HistoryPaneWidget::emitHistoryItemRequested( QModelIndex const & idx )
{
QVariant value = m_historyList->model()->data( idx );
if ( !value.isNull() )
{
emit historyItemRequested( value.toString() );
}
}
void HistoryPaneWidget::onSelectionChanged( const QItemSelection & selection, const QItemSelection & deselected )
{
Q_UNUSED( deselected );
if ( selection.empty() )
return;
itemSelectionChanged = true;
emitHistoryItemRequested( selection.front().topLeft() );
}
void HistoryPaneWidget::onItemClicked( QModelIndex const & idx )
{
// qDebug() << "clicked";
if ( !itemSelectionChanged )
{
emitHistoryItemRequested( idx );
}
itemSelectionChanged = false;
}
void HistoryPaneWidget::updateHistoryCounts()
{
historyCountLabel.setText( tr( "%1/%2" ).
arg( m_history->size() ).
arg( m_cfg->preferences.maxStringsInHistory ) );
historyCountLabel.setToolTip(
tr( "History size: %1 entries out of maximum %2" ).
arg( m_history->size() ).
arg( m_cfg->preferences.maxStringsInHistory ));
}
HistoryModel::HistoryModel( History * history, QObject * parent )
: QAbstractListModel( parent ), m_history(history)
{
connect( m_history, &History::itemsChanged, this, &HistoryModel::historyChanged );
}
int HistoryModel::rowCount( QModelIndex const & /*parent*/ ) const
{
return m_history->size();
}
QVariant HistoryModel::data( QModelIndex const & index, int role ) const
{
// qDebug() << "data: " << index;
if ( !index.isValid() || index.row() >= m_history->size() )
{
return QVariant();
}
if ( role == Qt::DisplayRole || role == Qt::ToolTipRole )
{
return m_history->getItem( index.row() ).word;
}
else
{
return QVariant();
}
}
void HistoryModel::historyChanged()
{
// qDebug() << "History Changed!!";
beginResetModel();
endResetModel();
}