/** Copyright (C) 2006, Ian Paul Larsen.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License along
** with this program; if not, write to the Free Software Foundation, Inc.,
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "Settings.h"
#include "BasicOutput.h"
#include "BasicKeyboard.h"
extern QMutex *mymutex;
extern BasicKeyboard *basicKeyboard;
BasicOutput::BasicOutput( ) : QTextEdit () {
inputText.clear();
setReadOnly(true);
setInputMethodHints(Qt::ImhNoPredictiveText);
setFocusPolicy(Qt::StrongFocus);
setAcceptRichText(false);
setUndoRedoEnabled(false);
gettingInput = false;
saveLastPosition();
}
BasicOutput::~BasicOutput( ) {
// destructor for basic output
}
void BasicOutput::getInput() {
// move cursor to the end of the existing text and start input
inputText.clear();
gettingInput = true;
setFocus();
emit(mainWindowsVisible(2,true));
restoreLastPosition();
inputPosition = lastPosition;
setReadOnly(false);
updatePasteButton();
}
void BasicOutput::stopInput() {
gettingInput = false;
setReadOnly(true);
updatePasteButton();
}
void BasicOutput::keyPressEvent(QKeyEvent *e) {
e->accept();
if (!gettingInput) {
mymutex->lock();
basicKeyboard->keyPressed(e);
QTextEdit::keyPressEvent(e);
mymutex->unlock();
} else {
if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
saveLastPosition();
QTextCursor t(textCursor());
t.setPosition(inputPosition);
t.movePosition(QTextCursor::Start, QTextCursor::KeepAnchor);
t.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, lastPosition);
inputText=t.selectedText();
restoreLastPosition();
insertPlainText("\n");
saveLastPosition();
stopInput();
emit(inputEntered(inputText)); // send the string back to the interperter and run controller
} else if (e->key() == Qt::Key_Backspace) {
QTextCursor t(textCursor());
t.movePosition(QTextCursor::PreviousCharacter);
if (t.position() >= inputPosition) {
QTextEdit::keyPressEvent(e);
}
saveLastPosition();
} else {
QTextEdit::keyPressEvent(e);
}
}
}
void BasicOutput::keyReleaseEvent(QKeyEvent *e) {
e->accept();
if (!gettingInput) {
mymutex->lock();
basicKeyboard->keyReleased(e);
QTextEdit::keyReleaseEvent(e);
mymutex->unlock();
}
}
void BasicOutput::focusOutEvent(QFocusEvent* ){
//clear pressed keys list when lose focus to avoid detecting still pressed keys
basicKeyboard->reset();
}
bool BasicOutput::initActions(QMenu * vMenu, QToolBar * vToolBar) {
if ((NULL == vMenu) || (NULL == vToolBar)) {
return false;
}
vToolBar->setObjectName("outtoolbar");
copyAct = vMenu->addAction(QObject::tr("Copy"));
copyAct->setShortcutContext(Qt::WidgetShortcut);
copyAct->setShortcuts(QKeySequence::keyBindings(QKeySequence::Copy));
copyAct->setEnabled(false);
pasteAct = vMenu->addAction(QObject::tr("Paste"));
pasteAct->setShortcutContext(Qt::WidgetShortcut);
pasteAct->setShortcuts(QKeySequence::keyBindings(QKeySequence::Paste));
pasteAct->setEnabled(false);
printAct = vMenu->addAction(QObject::tr("Print"));
printAct->setShortcutContext(Qt::WidgetShortcut);
printAct->setShortcuts(QKeySequence::keyBindings(QKeySequence::Print));
clearAct = vMenu->addAction(QObject::tr("Clear"));
clearAct->setEnabled(false);
vToolBar->addAction(copyAct);
vToolBar->addAction(pasteAct);
vToolBar->addAction(printAct);
vToolBar->addAction(clearAct);
QObject::connect(copyAct, SIGNAL(triggered()), this, SLOT(copy()));
QObject::connect(pasteAct, SIGNAL(triggered()), this, SLOT(paste()));
QObject::connect(printAct, SIGNAL(triggered()), this, SLOT(slotPrint()));
QObject::connect(this, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));
QObject::connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(updatePasteButton()));
QObject::connect(clearAct, SIGNAL(triggered()), this, SLOT(slotClear()));
m_usesToolBar = true;
m_usesMenu = true;
return true;
}
void BasicOutput::slotPrint() {
#ifdef ANDROID
QMessageBox::warning(this, QObject::tr("Print Error"), QObject::tr("Printing is not supported in this platform at this time."));
#else
QTextDocument *document = this->document();
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, this);
dialog->setWindowTitle(QObject::tr("Print Text Output"));
if (dialog->exec() == QDialog::Accepted) {
if ((printer.printerState() != QPrinter::Error) && (printer.printerState() != QPrinter::Aborted)) {
document->print(&printer);
} else {
QMessageBox::warning(this, QObject::tr("Print Error"), QObject::tr("Unable to carry out printing.\nPlease check your printer settings."));
}
}
#endif
}
void BasicOutput::paintEvent(QPaintEvent* event) {
// paint a visible cursor at the text cursor
QTextEdit::paintEvent(event);
QRect cursor = cursorRect();
cursor.setWidth(2);
QPainter p(viewport());
p.fillRect(cursor, Qt::SolidPattern);
}
// Ensure that drag and drop is allowed only in permitted area when BASIC-256 wait for input
void BasicOutput::dragEnterEvent(QDragEnterEvent *e){
if (e->mimeData()->hasFormat("text/plain") && gettingInput && !isReadOnly() )
e->acceptProposedAction();
}
void BasicOutput::dragMoveEvent (QDragMoveEvent *event){
QTextCursor t = cursorForPosition(event->pos());
if (t.position() >= inputPosition){
event->acceptProposedAction();
QDragMoveEvent move(event->pos(), event->dropAction(), event->mimeData(), event->mouseButtons(),
event->keyboardModifiers(), event->type());
QTextEdit::dragMoveEvent(&move); // Call the parent function (show cursor and keep selection)
} else {
event->ignore();
}
}
//Ensure that drang and drop operation or paste operation will add only first line of the copied text.
void BasicOutput::insertFromMimeData(const QMimeData* source)
{
if (source->hasText()) {
QString s = source->text();
QStringList l = s.split(QRegularExpression("[\\r\\n]"), Qt::SkipEmptyParts);
textCursor().insertText(l.at(0));
setFocus();
}
}
void BasicOutput::updatePasteButton(){
pasteAct->setEnabled(this->canPaste());
}
void BasicOutput::slotClear(){
clearAct->setEnabled(false);
clear();
lastPosition = 0;
}
void BasicOutput::slotWrap(bool checked) {
if (checked) {
setLineWrapMode(QTextEdit::WidgetWidth);
} else {
setLineWrapMode(QTextEdit::NoWrap);
}
}
void BasicOutput::outputText(QString text) {
outputText(text, Qt::black);
}
void BasicOutput::outputText(QString text, QColor color) {
this->setTextColor(color); //back to black color
restoreLastPosition();
this->insertPlainText(text);
this->ensureCursorVisible();
saveLastPosition();
}
int BasicOutput::getCurrentPosition() {
QTextCursor t(textCursor());
return t.position();
}
void BasicOutput::saveLastPosition() {
lastPosition = getCurrentPosition();
}
void BasicOutput::restoreLastPosition() {
moveToPosition(lastPosition);
}
void BasicOutput::moveToPosition(int pos) {
// move to an absolute character number (position) in the document
QTextCursor t(textCursor());
t.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
t.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, pos);
setTextCursor(t);
}
void BasicOutput::outputTextAt(int col, int row, QString s) {
//fprintf(stderr, "moveToPosition = col %i row %i\n", col, row);
QTextCursor t(textCursor());
t.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
//fprintf(stderr, "moveToPosition start=%i\n", t.position());
// move to the begining of the sprecified line or append lines
int lines = toPlainText().count("\n");
//fprintf(stderr, "moveToPosition lines=%i\n", lines);
if (row>lines) {
// go to end and append
for (; lines < row; lines++) {
t.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
this->setTextCursor(t);
insertPlainText("\n");
//fprintf(stderr, "moveToPosition add line\n", lines);
}
} else {
// go down to the row
for (int i=0; i < row; i++) {
t.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor);
//fprintf(stderr, "moveToPosition down line\n", lines);
}
this->setTextCursor(t);
}
//fprintf(stderr, "moveToPosition after position=%i\n", t.position());
// move to the specified character on the current line or append
t.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
int lineStart = t.position();
t.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor);
int lineEnd = t.position();
//fprintf(stderr, "moveToPosition = ls %i le %i\n", lineStart, lineEnd);
if (col <= lineEnd-lineStart) {
// line is long enough to start - replace mode
t.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
t.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, col);
this->setTextCursor(t);
// replace text at cursor
int startText = t.position();
t.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, s.length());
int endLength = t.position();
t.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
t.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, startText);
t.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor);
int endLine = t.position();
int replaceLen= (endLinesetTextCursor(t);
this->insertPlainText(s);
} else {
// line is not long enough - insert spaces and insert
t.movePosition(QTextCursor::EndOfLine, QTextCursor::MoveAnchor);
this->setTextCursor(t);
for (int i=lineEnd-lineStart; iinsertPlainText(s);
}
saveLastPosition();
//fprintf(stderr, "moveToPosition = -----------------------------------\n");
}