view libgui/qterminal/libqterminal/unix/QUnixTerminalImpl.cpp @ 23404:314ac710f2ae

highlight error messages in gui and provide links to open files (bug #35619) * QTerminal.cc (handleCustomContextMenuReques): use method via selecting the message only in windows * Filter.cpp (Filter::HotSpot::type(), Filter::HotSpot::setType): make Type a type in Filter, not in HotSpot; (RegExpFilter::RegExpFilter) create a filter with the corresponding type instead of different filters for different types; (RegExpFilter::HotSpot::HotSpot): A found hot spot is created with the types of the filter that found that hot spot; (RegExpFilter::process): remove some old debug message, which were already commented out, call newHotSpot with type as new parameter; (RegExpFilter::newHotSpot, UrlFilter::newHotSpot): new parameter type; (UrlFilter::process): derive this method for UrlFilter, too, allowing to connect signals for opening files later on; (UrlFilter::HotSpot::HotSpot): no extra action here, get type from filter; (UrlFilter::HotSpot::urlType): add new url type; (UrlFilter::HotSpot::activate): depending on link type, open link as before or call method for opening the file mentioned in the link; (UrlFilter::ErrorLinkRegExp): const defined reg. expression for error link; (UrlFilter::UrlFilter): set reg. expression depending on type; (UrlFilter::HotSpot::actions): in a case of a file link, only prepare an open, but no copy action for the context menu; (UrlFilter::request_open_file): method emitting the signal to the main window for opening the desired file at desired line; * Filter.h: make Filter class inherit from QObject for using singals, move enum Type from HotSpot to Filter and add the types Error and ErrorLink, Filter and Filter::HotSpot ctors with type parameter, add file opening signal to RegExpFilter and FilterObject, add Q_OBJECT directives, add method to FilterObject returning the instance variable _urlObject, add new urlType ErrorLink, add own process method and open file slot to UrlFilter, FilterObject: open file slot only emitting open file singal * QUnixTerminalImpl.cpp (ctor): initialize instance variable _parent; (initialize): add new filters for errors and for links to related files, connect latters signal to the appropriate main windows slot; * QUnixTerminalImpl.h: add instance variable _parent for signal connections * TerminalView.cpp (paintFilters): underline Link and ErrorLink, draw rectangle with transparency for Error and LinkError; (mousePressEvent, mouseMoveEvent): treat Link and ErrorLink the same way
author Torsten <mttl@mailbox.org>
date Mon, 17 Apr 2017 21:28:55 +0200
parents fee531225679
children c8722519330a
line wrap: on
line source

/*  Copyright (C) 2008 e_k (e_k@users.sourceforge.net)
    Copyright (C) 2012-2016 Jacob Dawid <jacob.dawid@cybercatalyst.com>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include <QDebug>

#include "unix/QUnixTerminalImpl.h"
#include "unix/kpty.h"

#include <termios.h>

QUnixTerminalImpl::QUnixTerminalImpl(QWidget *p)
    : QTerminal(p),
      _parent (p)
{
    setMinimumSize(300, 200);
    initialize();
}

void QUnixTerminalImpl::initialize()
{
    m_terminalView = new TerminalView(this);
    m_terminalView->setKeyboardCursorShape(TerminalView::UnderlineCursor);
    m_terminalView->setBlinkingCursor(true);
    m_terminalView->setBellMode(TerminalView::NotifyBell);
    m_terminalView->setTerminalSizeHint(true);
    m_terminalView->setContextMenuPolicy(Qt::CustomContextMenu);
    m_terminalView->setTripleClickMode(TerminalView::SelectWholeLine);
    m_terminalView->setTerminalSizeStartup(true);
    m_terminalView->setSize(80, 40);
    m_terminalView->setScrollBarPosition(TerminalView::ScrollBarRight);

    UrlFilter *url_filter = new UrlFilter();
    m_terminalView->filterChain ()->addFilter (url_filter);

    RegExpFilter *error_filter = new RegExpFilter (Filter::Type::Error);
    error_filter->setRegExp (QRegExp ("error:"));
    m_terminalView->filterChain ()->addFilter (error_filter);

    UrlFilter *file_filter = new UrlFilter (Filter::Type::ErrorLink);
    m_terminalView->filterChain ()->addFilter (file_filter);

    connect (file_filter, SIGNAL (request_open_file_signal (const QString&, int)),
             _parent, SLOT (edit_mfile (const QString&, int)));

    connect(m_terminalView, SIGNAL(customContextMenuRequested(QPoint)),
            this, SLOT(handleCustomContextMenuRequested(QPoint)));

    connect (m_terminalView, SIGNAL (interrupt_signal (void)),
             this, SLOT (terminal_interrupt ()));

#ifdef Q_OS_MAC
    QFont font = QFont("Monaco");
    font.setStyleHint(QFont::TypeWriter);
    font.setPointSize(11);
#else
    QFont font = QFont("Monospace");
    font.setStyleHint(QFont::TypeWriter);
    font.setPointSize(10);
#endif
    setTerminalFont(font);
    setFocusPolicy (Qt::StrongFocus);
    setFocusProxy(m_terminalView);
    setFocus(Qt::OtherFocusReason);

    m_kpty = new KPty();
    m_kpty->open();

    m_terminalModel = new TerminalModel(m_kpty);
    m_terminalModel->setAutoClose(true);
    m_terminalModel->setCodec(QTextCodec::codecForName("UTF-8"));
    m_terminalModel->setHistoryType(HistoryTypeBuffer (1000));
    m_terminalModel->setDarkBackground(true);
    m_terminalModel->setKeyBindings("");
    m_terminalModel->run();
    m_terminalModel->addView(m_terminalView);
    connectToPty();
}
void QUnixTerminalImpl::setScrollBufferSize(int value)
{
  if (value > 0)
    {
      m_terminalModel->clearHistory ();
      m_terminalModel->setHistoryType (HistoryTypeBuffer ( value ));
    }
  else
    m_terminalModel->setHistoryType (HistoryTypeNone ());
}

QList<QAction*>
QUnixTerminalImpl::get_hotspot_actions (const QPoint& at)
{
  return m_terminalView->filterActions (at);
}

void QUnixTerminalImpl::connectToPty()
{
    // Store the file descriptor associated with the STDERR stream onto
    // another temporary file descriptor for reconnect in the destructor.
    fdstderr = dup (STDERR_FILENO);

    int fds = m_kpty->slaveFd();

    dup2 (fds, STDIN_FILENO);
    dup2 (fds, STDOUT_FILENO);
    dup2 (fds, STDERR_FILENO);

    if(!isatty(STDIN_FILENO)) {
        qDebug("Error: stdin is not a tty.");
    }

    if(!isatty(STDOUT_FILENO)) {
        qDebug("Error: stdout is not a tty.");
    }

    if(!isatty(STDERR_FILENO)) {
        qDebug("Error: stderr is not a tty.");
    }
}

QUnixTerminalImpl::~QUnixTerminalImpl()
{
    delete m_terminalModel;
    delete m_kpty;
    delete m_terminalView;

    // Restore stderr so that any errors at exit might appear somewhere.
    dup2 (fdstderr, STDERR_FILENO);

    emit destroyed();
}

void QUnixTerminalImpl::setTerminalFont(const QFont &font)
{
    if(!m_terminalView)
        return;
    m_terminalView->setVTFont(font);
}

void QUnixTerminalImpl::setSize(int h, int v)
{
    if(!m_terminalView)
        return;
    m_terminalView->setSize(h, v);
}

void QUnixTerminalImpl::sendText(const QString& text)
{
    m_terminalModel->sendText(text);
}

void QUnixTerminalImpl::setCursorType(CursorType type, bool blinking)
{
    switch(type) {
        case UnderlineCursor: m_terminalView->setKeyboardCursorShape(TerminalView::UnderlineCursor); break;
        case BlockCursor: m_terminalView->setKeyboardCursorShape(TerminalView::BlockCursor); break;
        case IBeamCursor: m_terminalView->setKeyboardCursorShape(TerminalView::IBeamCursor); break;
    }
    m_terminalView->setBlinkingCursor(blinking);
}

// FIXME -- not sure how to make these work properly given the way the
// Unix terminal handles colors.
void QUnixTerminalImpl::setBackgroundColor (const QColor& color)
  {
    ColorEntry cols[TABLE_COLORS];

    const ColorEntry * curr_cols = m_terminalView->colorTable();
    for(int i=0;i<TABLE_COLORS;i++)
    {
     cols[i] = curr_cols[i];
    }

    cols[DEFAULT_BACK_COLOR].color = color;

    m_terminalView->setColorTable(cols);

  }
void QUnixTerminalImpl::setForegroundColor (const QColor& color)
{
    ColorEntry cols[TABLE_COLORS];

    const ColorEntry * curr_cols = m_terminalView->colorTable();
    for(int i=0;i<TABLE_COLORS;i++)
    {
     cols[i] = curr_cols[i];
    }

    cols[DEFAULT_FORE_COLOR].color = color;

    m_terminalView->setColorTable(cols);


}
void QUnixTerminalImpl::setSelectionColor (const QColor& color) { }

void QUnixTerminalImpl::setCursorColor (bool useForegroundColor,
                                        const QColor& color)
{
  m_terminalView->setKeyboardCursorColor (useForegroundColor, color);
}

void QUnixTerminalImpl::showEvent(QShowEvent *)
{
    m_terminalView->updateImage();
    m_terminalView->repaint();
    m_terminalView->update();
}

void QUnixTerminalImpl::resizeEvent(QResizeEvent*)
{
    m_terminalView->resize(this->size());
    m_terminalView->updateImage();
    m_terminalView->repaint();
    m_terminalView->update();
}

void QUnixTerminalImpl::copyClipboard()
{
    m_terminalView->copyClipboard (_extra_interrupt);
}

void QUnixTerminalImpl::pasteClipboard()
{
    m_terminalView->pasteClipboard();
}

void QUnixTerminalImpl::selectAll()
{
    m_terminalView->selectAll();
}


QString QUnixTerminalImpl::selectedText ()
{
  return m_terminalView->selectedText ();
}

void
QUnixTerminalImpl::has_extra_interrupt (bool extra)
{
  _extra_interrupt = extra;
}