forked from qt-creator/qt-creator
Terminal: Support clipboard selection
Change-Id: Ief59f9e21782e0dd0292f3625e35c1742cf9b3bc Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -273,9 +273,7 @@ void TerminalWidget::setupSurface()
|
|||||||
&Internal::TerminalSurface::invalidated,
|
&Internal::TerminalSurface::invalidated,
|
||||||
this,
|
this,
|
||||||
[this](const QRect &rect) {
|
[this](const QRect &rect) {
|
||||||
if (setSelection(std::nullopt))
|
setSelection(std::nullopt);
|
||||||
updateViewport();
|
|
||||||
else
|
|
||||||
updateViewport(gridToViewport(rect));
|
updateViewport(gridToViewport(rect));
|
||||||
});
|
});
|
||||||
connect(m_surface.get(),
|
connect(m_surface.get(),
|
||||||
@@ -300,8 +298,8 @@ void TerminalWidget::setupSurface()
|
|||||||
});
|
});
|
||||||
connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] {
|
connect(m_surface.get(), &Internal::TerminalSurface::altscreenChanged, this, [this] {
|
||||||
updateScrollBars();
|
updateScrollBars();
|
||||||
|
if (!setSelection(std::nullopt))
|
||||||
updateViewport();
|
updateViewport();
|
||||||
setSelection(std::nullopt);
|
|
||||||
});
|
});
|
||||||
connect(m_surface.get(), &Internal::TerminalSurface::unscroll, this, [this] {
|
connect(m_surface.get(), &Internal::TerminalSurface::unscroll, this, [this] {
|
||||||
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
|
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
|
||||||
@@ -385,21 +383,7 @@ QAction &TerminalWidget::zoomOutAction()
|
|||||||
|
|
||||||
void TerminalWidget::copyToClipboard() const
|
void TerminalWidget::copyToClipboard() const
|
||||||
{
|
{
|
||||||
if (!m_selection)
|
QString text = textFromSelection();
|
||||||
return;
|
|
||||||
|
|
||||||
Internal::CellIterator it = m_surface->iteratorAt(m_selection->start);
|
|
||||||
Internal::CellIterator end = m_surface->iteratorAt(m_selection->end);
|
|
||||||
|
|
||||||
std::u32string s;
|
|
||||||
for (; it != end; ++it) {
|
|
||||||
if (it.gridPos().x() == 0 && !s.empty())
|
|
||||||
s += U'\n';
|
|
||||||
if (*it != 0)
|
|
||||||
s += *it;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString text = QString::fromUcs4(s.data(), static_cast<int>(s.size()));
|
|
||||||
|
|
||||||
qCDebug(selectionLog) << "Copied to clipboard: " << text;
|
qCDebug(selectionLog) << "Copied to clipboard: " << text;
|
||||||
|
|
||||||
@@ -420,7 +404,6 @@ void TerminalWidget::pasteFromClipboard()
|
|||||||
void TerminalWidget::clearSelection()
|
void TerminalWidget::clearSelection()
|
||||||
{
|
{
|
||||||
setSelection(std::nullopt);
|
setSelection(std::nullopt);
|
||||||
updateViewport();
|
|
||||||
m_surface->sendKey(Qt::Key_Escape);
|
m_surface->sendKey(Qt::Key_Escape);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,19 +455,59 @@ void TerminalWidget::flushVTerm(bool force)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TerminalWidget::setSelection(const std::optional<Selection> &selection)
|
QString TerminalWidget::textFromSelection() const
|
||||||
{
|
{
|
||||||
if (selection.has_value() != m_selection.has_value()) {
|
if (!m_selection)
|
||||||
qCDebug(selectionLog) << "Copy enabled:" << selection.has_value();
|
return {};
|
||||||
m_copyAction.setEnabled(selection.has_value());
|
|
||||||
|
Internal::CellIterator it = m_surface->iteratorAt(m_selection->start);
|
||||||
|
Internal::CellIterator end = m_surface->iteratorAt(m_selection->end);
|
||||||
|
|
||||||
|
std::u32string s;
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
if (it.gridPos().x() == 0 && !s.empty())
|
||||||
|
s += U'\n';
|
||||||
|
if (*it != 0)
|
||||||
|
s += *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selection.has_value() && m_selection.has_value()) {
|
return QString::fromUcs4(s.data(), static_cast<int>(s.size()));
|
||||||
if (*selection == *m_selection)
|
}
|
||||||
|
|
||||||
|
bool TerminalWidget::setSelection(const std::optional<Selection> &selection)
|
||||||
|
{
|
||||||
|
if (selectionLog().isDebugEnabled())
|
||||||
|
updateViewport();
|
||||||
|
|
||||||
|
if (selection == m_selection) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*if (m_selection && m_selection->final) {
|
||||||
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
if (clipboard->supportsSelection()) {
|
||||||
|
qCDebug(selectionLog) << "Clearing selection from clipboard";
|
||||||
|
clipboard->clear(QClipboard::Selection);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
m_selection = selection;
|
m_selection = selection;
|
||||||
|
|
||||||
|
if (m_selection && m_selection->final) {
|
||||||
|
qCDebug(selectionLog) << "Copy enabled:" << selection.has_value();
|
||||||
|
m_copyAction.setEnabled(selection.has_value());
|
||||||
|
|
||||||
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
if (clipboard->supportsSelection()) {
|
||||||
|
QString text = textFromSelection();
|
||||||
|
qCDebug(selectionLog) << "Selection set to clipboard: " << text;
|
||||||
|
clipboard->setText(text, QClipboard::Selection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selectionLog().isDebugEnabled())
|
||||||
|
updateViewport();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,8 +945,7 @@ void TerminalWidget::keyPressEvent(QKeyEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (actionTriggered) {
|
if (actionTriggered) {
|
||||||
if (setSelection(std::nullopt))
|
setSelection(std::nullopt);
|
||||||
updateViewport();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1053,14 +1075,17 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event)
|
|||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
if (std::chrono::system_clock::now() - m_lastDoubleClick < 500ms) {
|
if (std::chrono::system_clock::now() - m_lastDoubleClick < 500ms) {
|
||||||
m_selectLineMode = true;
|
m_selectLineMode = true;
|
||||||
m_selection->start = m_surface->gridToPos(
|
const Selection newSelection{m_surface->gridToPos(
|
||||||
{0, m_surface->posToGrid(m_selection->start).y()});
|
{0, m_surface->posToGrid(m_selection->start).y()}),
|
||||||
m_selection->end = m_surface->gridToPos(
|
m_surface->gridToPos(
|
||||||
{m_surface->liveSize().width(), m_surface->posToGrid(m_selection->end).y()});
|
{m_surface->liveSize().width(),
|
||||||
|
m_surface->posToGrid(m_selection->end).y()}),
|
||||||
|
false};
|
||||||
|
setSelection(newSelection);
|
||||||
} else {
|
} else {
|
||||||
m_selectLineMode = false;
|
m_selectLineMode = false;
|
||||||
int pos = m_surface->gridToPos(globalToGrid(viewportToGlobal(event->pos())));
|
int pos = m_surface->gridToPos(globalToGrid(viewportToGlobal(event->pos())));
|
||||||
setSelection(Selection{pos, pos});
|
setSelection(Selection{pos, pos, false});
|
||||||
}
|
}
|
||||||
event->accept();
|
event->accept();
|
||||||
updateViewport();
|
updateViewport();
|
||||||
@@ -1068,7 +1093,6 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event)
|
|||||||
if (m_selection) {
|
if (m_selection) {
|
||||||
m_copyAction.trigger();
|
m_copyAction.trigger();
|
||||||
setSelection(std::nullopt);
|
setSelection(std::nullopt);
|
||||||
updateViewport();
|
|
||||||
} else {
|
} else {
|
||||||
m_pasteAction.trigger();
|
m_pasteAction.trigger();
|
||||||
}
|
}
|
||||||
@@ -1077,7 +1101,7 @@ void TerminalWidget::mousePressEvent(QMouseEvent *event)
|
|||||||
void TerminalWidget::mouseMoveEvent(QMouseEvent *event)
|
void TerminalWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (m_selection && event->buttons() & Qt::LeftButton) {
|
if (m_selection && event->buttons() & Qt::LeftButton) {
|
||||||
const auto old = m_selection;
|
Selection newSelection = *m_selection;
|
||||||
int scrollVelocity = 0;
|
int scrollVelocity = 0;
|
||||||
if (event->pos().y() < 0) {
|
if (event->pos().y() < 0) {
|
||||||
scrollVelocity = (event->pos().y());
|
scrollVelocity = (event->pos().y());
|
||||||
@@ -1110,16 +1134,15 @@ void TerminalWidget::mouseMoveEvent(QMouseEvent *event)
|
|||||||
start = 0;
|
start = 0;
|
||||||
|
|
||||||
if (m_selectLineMode) {
|
if (m_selectLineMode) {
|
||||||
m_selection->start = m_surface->gridToPos({0, m_surface->posToGrid(start).y()});
|
newSelection.start = m_surface->gridToPos({0, m_surface->posToGrid(start).y()});
|
||||||
m_selection->end = m_surface->gridToPos(
|
newSelection.end = m_surface->gridToPos(
|
||||||
{m_surface->liveSize().width(), m_surface->posToGrid(newEnd).y()});
|
{m_surface->liveSize().width(), m_surface->posToGrid(newEnd).y()});
|
||||||
} else {
|
} else {
|
||||||
m_selection->start = start;
|
newSelection.start = start;
|
||||||
m_selection->end = newEnd;
|
newSelection.end = newEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old != *m_selection || selectionLog().isDebugEnabled())
|
setSelection(newSelection);
|
||||||
updateViewport();
|
|
||||||
} else if (event->modifiers() == Qt::ControlModifier) {
|
} else if (event->modifiers() == Qt::ControlModifier) {
|
||||||
checkLinkAt(event->pos());
|
checkLinkAt(event->pos());
|
||||||
} else if (m_linkSelection) {
|
} else if (m_linkSelection) {
|
||||||
@@ -1171,10 +1194,10 @@ void TerminalWidget::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
m_scrollTimer.stop();
|
m_scrollTimer.stop();
|
||||||
|
|
||||||
if (m_selection && event->button() == Qt::LeftButton) {
|
if (m_selection && event->button() == Qt::LeftButton) {
|
||||||
if (m_selection->end - m_selection->start == 0) {
|
if (m_selection->end - m_selection->start == 0)
|
||||||
setSelection(std::nullopt);
|
setSelection(std::nullopt);
|
||||||
updateViewport();
|
else
|
||||||
}
|
setSelection(Selection{m_selection->start, m_selection->end, true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1208,11 +1231,10 @@ void TerminalWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
|||||||
{
|
{
|
||||||
const auto hit = textAt(event->pos());
|
const auto hit = textAt(event->pos());
|
||||||
|
|
||||||
setSelection(Selection{hit.start, hit.end});
|
setSelection(Selection{hit.start, hit.end, true});
|
||||||
|
|
||||||
m_lastDoubleClick = std::chrono::system_clock::now();
|
m_lastDoubleClick = std::chrono::system_clock::now();
|
||||||
|
|
||||||
updateViewport();
|
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,10 +51,11 @@ public:
|
|||||||
{
|
{
|
||||||
int start;
|
int start;
|
||||||
int end;
|
int end;
|
||||||
|
bool final{false};
|
||||||
|
|
||||||
bool operator!=(const Selection &other) const
|
bool operator!=(const Selection &other) const
|
||||||
{
|
{
|
||||||
return start != other.start || end != other.end;
|
return start != other.start || end != other.end || final != other.final;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Selection &other) const { return !operator!=(other); }
|
bool operator==(const Selection &other) const { return !operator!=(other); }
|
||||||
@@ -151,12 +152,12 @@ protected:
|
|||||||
TextAndOffsets textAt(const QPoint &pos) const;
|
TextAndOffsets textAt(const QPoint &pos) const;
|
||||||
|
|
||||||
void applySizeChange();
|
void applySizeChange();
|
||||||
|
|
||||||
void updateScrollBars();
|
void updateScrollBars();
|
||||||
|
|
||||||
void flushVTerm(bool force);
|
void flushVTerm(bool force);
|
||||||
|
|
||||||
bool setSelection(const std::optional<Selection> &selection);
|
bool setSelection(const std::optional<Selection> &selection);
|
||||||
|
QString textFromSelection() const;
|
||||||
|
|
||||||
void configBlinkTimer();
|
void configBlinkTimer();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user