parent
aa98b44a5f
commit
d949b72cad
@ -0,0 +1,75 @@
|
||||
project(cl-install-gui)
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "cmake")
|
||||
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||
|
||||
set(QT_MIN_VERSION 4.6.0)
|
||||
find_package(Qt4 REQUIRED)
|
||||
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
add_subdirectory(libs/qtermwidget)
|
||||
|
||||
include_directories(
|
||||
${QT_INCLUDES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
libs/qtermwidget
|
||||
)
|
||||
|
||||
set( cl_install_gui_SRCS
|
||||
src/main.cpp
|
||||
src/pagecfdisk.cpp
|
||||
src/pageconfiguration.cpp
|
||||
src/pagefinish.cpp
|
||||
src/pageinstall.cpp
|
||||
src/pagelanguage.cpp
|
||||
src/pagelicense.cpp
|
||||
src/pagemanager.cpp
|
||||
src/pagepartitioning.cpp
|
||||
src/systeminstaller.cpp
|
||||
src/tools.cpp
|
||||
)
|
||||
|
||||
set (cl_install_gui_HDRS
|
||||
src/installerpage.h
|
||||
src/pagecfdisk.h
|
||||
src/pageconfiguration.h
|
||||
src/pagefinish.h
|
||||
src/pageinstall.h
|
||||
src/pagelanguage.h
|
||||
src/pagelicense.h
|
||||
src/pagemanager.h
|
||||
src/pagepartitioning.h
|
||||
src/systeminstaller.h
|
||||
)
|
||||
|
||||
set( cl_install_gui_RCC
|
||||
resources/systeminstaller.qrc
|
||||
)
|
||||
|
||||
add_definitions( -DQT_GUI_LIB -DQT_CORE_LIB )
|
||||
|
||||
qt4_wrap_cpp( cl_install_gui_MOC_SRCS
|
||||
${cl_install_gui_HDRS}
|
||||
)
|
||||
qt4_add_resources( cl_install_gui_RCC_SRCS
|
||||
${cl_install_gui_RCC}
|
||||
)
|
||||
|
||||
add_executable( cl-install-gui
|
||||
${cl_install_gui_SRCS}
|
||||
${cl_install_gui_MOC_SRCS}
|
||||
${cl_install_gui_RCC_SRCS}
|
||||
)
|
||||
|
||||
target_link_libraries( cl-install-gui
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
qtermwidget
|
||||
)
|
||||
|
||||
install( TARGETS cl-install-gui DESTINATION bin )
|
||||
|
@ -0,0 +1,337 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
Copyright (C) 2000 by Stephan Kulow <coolo@kde.org>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "BlockArray.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
// System
|
||||
#include <assert.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
static int blocksize = 0;
|
||||
|
||||
BlockArray::BlockArray()
|
||||
: size(0),
|
||||
current(size_t(-1)),
|
||||
index(size_t(-1)),
|
||||
lastmap(0),
|
||||
lastmap_index(size_t(-1)),
|
||||
lastblock(0), ion(-1),
|
||||
length(0)
|
||||
{
|
||||
// lastmap_index = index = current = size_t(-1);
|
||||
if (blocksize == 0)
|
||||
blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
|
||||
|
||||
}
|
||||
|
||||
BlockArray::~BlockArray()
|
||||
{
|
||||
setHistorySize(0);
|
||||
assert(!lastblock);
|
||||
}
|
||||
|
||||
size_t BlockArray::append(Block *block)
|
||||
{
|
||||
if (!size)
|
||||
return size_t(-1);
|
||||
|
||||
++current;
|
||||
if (current >= size) current = 0;
|
||||
|
||||
int rc;
|
||||
rc = lseek(ion, current * blocksize, SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setHistorySize(0); return size_t(-1); }
|
||||
rc = write(ion, block, blocksize); if (rc < 0) { perror("HistoryBuffer::add.write"); setHistorySize(0); return size_t(-1); }
|
||||
|
||||
length++;
|
||||
if (length > size) length = size;
|
||||
|
||||
++index;
|
||||
|
||||
delete block;
|
||||
return current;
|
||||
}
|
||||
|
||||
size_t BlockArray::newBlock()
|
||||
{
|
||||
if (!size)
|
||||
return size_t(-1);
|
||||
append(lastblock);
|
||||
|
||||
lastblock = new Block();
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
Block *BlockArray::lastBlock() const
|
||||
{
|
||||
return lastblock;
|
||||
}
|
||||
|
||||
bool BlockArray::has(size_t i) const
|
||||
{
|
||||
if (i == index + 1)
|
||||
return true;
|
||||
|
||||
if (i > index)
|
||||
return false;
|
||||
if (index - i >= length)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const Block* BlockArray::at(size_t i)
|
||||
{
|
||||
if (i == index + 1)
|
||||
return lastblock;
|
||||
|
||||
if (i == lastmap_index)
|
||||
return lastmap;
|
||||
|
||||
if (i > index) {
|
||||
qDebug() << "BlockArray::at() i > index\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if (index - i >= length) {
|
||||
// kDebug(1211) << "BlockArray::at() index - i >= length\n";
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
|
||||
|
||||
assert(j < size);
|
||||
unmap();
|
||||
|
||||
Block *block = (Block*)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
|
||||
|
||||
if (block == (Block*)-1) { perror("mmap"); return 0; }
|
||||
|
||||
lastmap = block;
|
||||
lastmap_index = i;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
void BlockArray::unmap()
|
||||
{
|
||||
if (lastmap) {
|
||||
int res = munmap((char*)lastmap, blocksize);
|
||||
if (res < 0) perror("munmap");
|
||||
}
|
||||
lastmap = 0;
|
||||
lastmap_index = size_t(-1);
|
||||
}
|
||||
|
||||
bool BlockArray::setSize(size_t newsize)
|
||||
{
|
||||
return setHistorySize(newsize * 1024 / blocksize);
|
||||
}
|
||||
|
||||
bool BlockArray::setHistorySize(size_t newsize)
|
||||
{
|
||||
// kDebug(1211) << "setHistorySize " << size << " " << newsize;
|
||||
|
||||
if (size == newsize)
|
||||
return false;
|
||||
|
||||
unmap();
|
||||
|
||||
if (!newsize) {
|
||||
delete lastblock;
|
||||
lastblock = 0;
|
||||
if (ion >= 0) close(ion);
|
||||
ion = -1;
|
||||
current = size_t(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
FILE* tmp = tmpfile();
|
||||
if (!tmp) {
|
||||
perror("konsole: cannot open temp file.\n");
|
||||
} else {
|
||||
ion = dup(fileno(tmp));
|
||||
if (ion<0) {
|
||||
perror("konsole: cannot dup temp file.\n");
|
||||
fclose(tmp);
|
||||
}
|
||||
}
|
||||
if (ion < 0)
|
||||
return false;
|
||||
|
||||
assert(!lastblock);
|
||||
|
||||
lastblock = new Block();
|
||||
size = newsize;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newsize > size) {
|
||||
increaseBuffer();
|
||||
size = newsize;
|
||||
return false;
|
||||
} else {
|
||||
decreaseBuffer(newsize);
|
||||
ftruncate(ion, length*blocksize);
|
||||
size = newsize;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
|
||||
{
|
||||
int res = fseek(fion, cursor * blocksize, SEEK_SET);
|
||||
if (res)
|
||||
perror("fseek");
|
||||
res = fread(buffer2, blocksize, 1, fion);
|
||||
if (res != 1)
|
||||
perror("fread");
|
||||
|
||||
res = fseek(fion, newpos * blocksize, SEEK_SET);
|
||||
if (res)
|
||||
perror("fseek");
|
||||
res = fwrite(buffer2, blocksize, 1, fion);
|
||||
if (res != 1)
|
||||
perror("fwrite");
|
||||
// printf("moving block %d to %d\n", cursor, newpos);
|
||||
}
|
||||
|
||||
void BlockArray::decreaseBuffer(size_t newsize)
|
||||
{
|
||||
if (index < newsize) // still fits in whole
|
||||
return;
|
||||
|
||||
int offset = (current - (newsize - 1) + size) % size;
|
||||
|
||||
if (!offset)
|
||||
return;
|
||||
|
||||
// The Block constructor could do somthing in future...
|
||||
char *buffer1 = new char[blocksize];
|
||||
|
||||
FILE *fion = fdopen(dup(ion), "w+b");
|
||||
if (!fion) {
|
||||
delete [] buffer1;
|
||||
perror("fdopen/dup");
|
||||
return;
|
||||
}
|
||||
|
||||
int firstblock;
|
||||
if (current <= newsize) {
|
||||
firstblock = current + 1;
|
||||
} else {
|
||||
firstblock = 0;
|
||||
}
|
||||
|
||||
size_t oldpos;
|
||||
for (size_t i = 0, cursor=firstblock; i < newsize; i++) {
|
||||
oldpos = (size + cursor + offset) % size;
|
||||
moveBlock(fion, oldpos, cursor, buffer1);
|
||||
if (oldpos < newsize) {
|
||||
cursor = oldpos;
|
||||
} else
|
||||
cursor++;
|
||||
}
|
||||
|
||||
current = newsize - 1;
|
||||
length = newsize;
|
||||
|
||||
delete [] buffer1;
|
||||
|
||||
fclose(fion);
|
||||
|
||||
}
|
||||
|
||||
void BlockArray::increaseBuffer()
|
||||
{
|
||||
if (index < size) // not even wrapped once
|
||||
return;
|
||||
|
||||
int offset = (current + size + 1) % size;
|
||||
if (!offset) // no moving needed
|
||||
return;
|
||||
|
||||
// The Block constructor could do somthing in future...
|
||||
char *buffer1 = new char[blocksize];
|
||||
char *buffer2 = new char[blocksize];
|
||||
|
||||
int runs = 1;
|
||||
int bpr = size; // blocks per run
|
||||
|
||||
if (size % offset == 0) {
|
||||
bpr = size / offset;
|
||||
runs = offset;
|
||||
}
|
||||
|
||||
FILE *fion = fdopen(dup(ion), "w+b");
|
||||
if (!fion) {
|
||||
perror("fdopen/dup");
|
||||
delete [] buffer1;
|
||||
delete [] buffer2;
|
||||
return;
|
||||
}
|
||||
|
||||
int res;
|
||||
for (int i = 0; i < runs; i++)
|
||||
{
|
||||
// free one block in chain
|
||||
int firstblock = (offset + i) % size;
|
||||
res = fseek(fion, firstblock * blocksize, SEEK_SET);
|
||||
if (res)
|
||||
perror("fseek");
|
||||
res = fread(buffer1, blocksize, 1, fion);
|
||||
if (res != 1)
|
||||
perror("fread");
|
||||
int newpos = 0;
|
||||
for (int j = 1, cursor=firstblock; j < bpr; j++)
|
||||
{
|
||||
cursor = (cursor + offset) % size;
|
||||
newpos = (cursor - offset + size) % size;
|
||||
moveBlock(fion, cursor, newpos, buffer2);
|
||||
}
|
||||
res = fseek(fion, i * blocksize, SEEK_SET);
|
||||
if (res)
|
||||
perror("fseek");
|
||||
res = fwrite(buffer1, blocksize, 1, fion);
|
||||
if (res != 1)
|
||||
perror("fwrite");
|
||||
}
|
||||
current = size - 1;
|
||||
length = size;
|
||||
|
||||
delete [] buffer1;
|
||||
delete [] buffer2;
|
||||
|
||||
fclose(fion);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
Copyright (C) 2000 by Stephan Kulow <coolo@kde.org>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef BLOCKARRAY_H
|
||||
#define BLOCKARRAY_H
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
//#error Do not use in KDE 2.1
|
||||
|
||||
#define BlockSize (1 << 12)
|
||||
#define ENTRIES ((BlockSize - sizeof(size_t) ) / sizeof(unsigned char))
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
struct Block {
|
||||
Block() { size = 0; }
|
||||
unsigned char data[ENTRIES];
|
||||
size_t size;
|
||||
};
|
||||
|
||||
// ///////////////////////////////////////////////////////
|
||||
|
||||
class BlockArray {
|
||||
public:
|
||||
/**
|
||||
* Creates a history file for holding
|
||||
* maximal size blocks. If more blocks
|
||||
* are requested, then it drops earlier
|
||||
* added ones.
|
||||
*/
|
||||
BlockArray();
|
||||
|
||||
/// destructor
|
||||
~BlockArray();
|
||||
|
||||
/**
|
||||
* adds the Block at the end of history.
|
||||
* This may drop other blocks.
|
||||
*
|
||||
* The ownership on the block is transfered.
|
||||
* An unique index number is returned for accessing
|
||||
* it later (if not yet dropped then)
|
||||
*
|
||||
* Note, that the block may be dropped completely
|
||||
* if history is turned off.
|
||||
*/
|
||||
size_t append(Block *block);
|
||||
|
||||
/**
|
||||
* gets the block at the index. Function may return
|
||||
* 0 if the block isn't available any more.
|
||||
*
|
||||
* The returned block is strictly readonly as only
|
||||
* maped in memory - and will be invalid on the next
|
||||
* operation on this class.
|
||||
*/
|
||||
const Block *at(size_t index);
|
||||
|
||||
/**
|
||||
* reorders blocks as needed. If newsize is null,
|
||||
* the history is emptied completely. The indices
|
||||
* returned on append won't change their semantic,
|
||||
* but they may not be valid after this call.
|
||||
*/
|
||||
bool setHistorySize(size_t newsize);
|
||||
|
||||
size_t newBlock();
|
||||
|
||||
Block *lastBlock() const;
|
||||
|
||||
/**
|
||||
* Convenient function to set the size in KBytes
|
||||
* instead of blocks
|
||||
*/
|
||||
bool setSize(size_t newsize);
|
||||
|
||||
size_t len() const { return length; }
|
||||
|
||||
bool has(size_t index) const;
|
||||
|
||||
size_t getCurrent() const { return current; }
|
||||
|
||||
private:
|
||||
void unmap();
|
||||
void increaseBuffer();
|
||||
void decreaseBuffer(size_t newsize);
|
||||
|
||||
size_t size;
|
||||
// current always shows to the last inserted block
|
||||
size_t current;
|
||||
size_t index;
|
||||
|
||||
Block *lastmap;
|
||||
size_t lastmap_index;
|
||||
Block *lastblock;
|
||||
|
||||
int ion;
|
||||
size_t length;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,68 @@
|
||||
project(qtermwidget)
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
set(QT_MIN_VERSION 4.6.0)
|
||||
|
||||
find_package(Qt4 REQUIRED)
|
||||
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
include_directories(
|
||||
${QT_INCLUDES}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
.
|
||||
)
|
||||
|
||||
link_directories(
|
||||
.
|
||||
)
|
||||
|
||||
set( qtermwidget_SRCS
|
||||
qtermwidget.cpp
|
||||
BlockArray.cpp
|
||||
Emulation.cpp
|
||||
Filter.cpp
|
||||
History.cpp
|
||||
k3processcontroller.cpp
|
||||
k3process.cpp
|
||||
KeyboardTranslator.cpp
|
||||
konsole_wcwidth.cpp
|
||||
kpty.cpp
|
||||
Pty.cpp
|
||||
Screen.cpp
|
||||
ScreenWindow.cpp
|
||||
Session.cpp
|
||||
ShellCommand.cpp
|
||||
TerminalCharacterDecoder.cpp
|
||||
TerminalDisplay.cpp
|
||||
Vt102Emulation.cpp
|
||||
)
|
||||
|
||||
set( qtermwidget_HDRS
|
||||
qtermwidget.h
|
||||
Emulation.h
|
||||
Filter.h
|
||||
k3processcontroller.h
|
||||
k3process.h
|
||||
Pty.h
|
||||
ScreenWindow.h
|
||||
Session.h
|
||||
TerminalDisplay.h
|
||||
Vt102Emulation.h
|
||||
)
|
||||
|
||||
add_definitions( -DQT_GUI_LIB -DQT_CORE_LIB -DHAVE_POSIX_OPENPT )
|
||||
|
||||
qt4_wrap_cpp( qtermwidget_MOC_SRCS
|
||||
${qtermwidget_HDRS}
|
||||
)
|
||||
|
||||
add_library (qtermwidget STATIC
|
||||
${qtermwidget_SRCS}
|
||||
${qtermwidget_MOC_SRCS}
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
)
|
||||
|
@ -0,0 +1,210 @@
|
||||
/*
|
||||
This file is part of Konsole, KDE's terminal.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef CHARACTER_H
|
||||
#define CHARACTER_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QHash>
|
||||
|
||||
// Local
|
||||
#include "CharacterColor.h"
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
typedef unsigned char LineProperty;
|
||||
|
||||
static const int LINE_DEFAULT = 0;
|
||||
static const int LINE_WRAPPED = (1 << 0);
|
||||
static const int LINE_DOUBLEWIDTH = (1 << 1);
|
||||
static const int LINE_DOUBLEHEIGHT = (1 << 2);
|
||||
|
||||
#define DEFAULT_RENDITION 0
|
||||
#define RE_BOLD (1 << 0)
|
||||
#define RE_BLINK (1 << 1)
|
||||
#define RE_UNDERLINE (1 << 2)
|
||||
#define RE_REVERSE (1 << 3) // Screen only
|
||||
#define RE_INTENSIVE (1 << 3) // Widget only
|
||||
#define RE_CURSOR (1 << 4)
|
||||
#define RE_EXTENDED_CHAR (1 << 5)
|
||||
|
||||
/**
|
||||
* A single character in the terminal which consists of a unicode character
|
||||
* value, foreground and background colors and a set of rendition attributes
|
||||
* which specify how it should be drawn.
|
||||
*/
|
||||
class Character
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new character.
|
||||
*
|
||||
* @param _c The unicode character value of this character.
|
||||
* @param _f The foreground color used to draw the character.
|
||||
* @param _b The color used to draw the character's background.
|
||||
* @param _r A set of rendition flags which specify how this character is to be drawn.
|
||||
*/
|
||||
inline Character(quint16 _c = ' ',
|
||||
CharacterColor _f = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),
|
||||
CharacterColor _b = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),
|
||||
quint8 _r = DEFAULT_RENDITION)
|
||||
: character(_c), rendition(_r), foregroundColor(_f), backgroundColor(_b) {}
|
||||
|
||||
union
|
||||
{
|
||||
/** The unicode character value for this character. */
|
||||
quint16 character;
|
||||
/**
|
||||
* Experimental addition which allows a single Character instance to contain more than
|
||||
* one unicode character.
|
||||
*
|
||||
* charSequence is a hash code which can be used to look up the unicode
|
||||
* character sequence in the ExtendedCharTable used to create the sequence.
|
||||
*/
|
||||
quint16 charSequence;
|
||||
};
|
||||
|
||||
/** A combination of RENDITION flags which specify options for drawing the character. */
|
||||
quint8 rendition;
|
||||
|
||||
/** The foreground color used to draw this character. */
|
||||
CharacterColor foregroundColor;
|
||||
/** The color used to draw this character's background. */
|
||||
CharacterColor backgroundColor;
|
||||
|
||||
/**
|
||||
* Returns true if this character has a transparent background when
|
||||
* it is drawn with the specified @p palette.
|
||||
*/
|
||||
bool isTransparent(const ColorEntry* palette) const;
|
||||
/**
|
||||
* Returns true if this character should always be drawn in bold when
|
||||
* it is drawn with the specified @p palette, independent of whether
|
||||
* or not the character has the RE_BOLD rendition flag.
|
||||
*/
|
||||
bool isBold(const ColorEntry* base) const;
|
||||
|
||||
/**
|
||||
* Compares two characters and returns true if they have the same unicode character value,
|
||||
* rendition and colors.
|
||||
*/
|
||||
friend bool operator == (const Character& a, const Character& b);
|
||||
/**
|
||||
* Compares two characters and returns true if they have different unicode character values,
|
||||
* renditions or colors.
|
||||
*/
|
||||
friend bool operator != (const Character& a, const Character& b);
|
||||
};
|
||||
|
||||
inline bool operator == (const Character& a, const Character& b)
|
||||
{
|
||||
return a.character == b.character &&
|
||||
a.rendition == b.rendition &&
|
||||
a.foregroundColor == b.foregroundColor &&
|
||||
a.backgroundColor == b.backgroundColor;
|
||||
}
|
||||
|
||||
inline bool operator != (const Character& a, const Character& b)
|
||||
{
|
||||
return a.character != b.character ||
|
||||
a.rendition != b.rendition ||
|
||||
a.foregroundColor != b.foregroundColor ||
|
||||
a.backgroundColor != b.backgroundColor;
|
||||
}
|
||||
|
||||
inline bool Character::isTransparent(const ColorEntry* base) const
|
||||
{
|
||||
return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) &&
|
||||
base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].transparent)
|
||||
|| ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) &&
|
||||
base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].transparent);
|
||||
}
|
||||
|
||||
inline bool Character::isBold(const ColorEntry* base) const
|
||||
{
|
||||
return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) &&
|
||||
base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].bold)
|
||||
|| ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) &&
|
||||
base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].bold);
|
||||
}
|
||||
|
||||
extern unsigned short vt100_graphics[32];
|
||||
|
||||
|
||||
/**
|
||||
* A table which stores sequences of unicode characters, referenced
|
||||
* by hash keys. The hash key itself is the same size as a unicode
|
||||
* character ( ushort ) so that it can occupy the same space in
|
||||
* a structure.
|
||||
*/
|
||||
class ExtendedCharTable
|
||||
{
|
||||
public:
|
||||
/** Constructs a new character table. */
|
||||
ExtendedCharTable();
|
||||
~ExtendedCharTable();
|
||||
|
||||
/**
|
||||
* Adds a sequences of unicode characters to the table and returns
|
||||
* a hash code which can be used later to look up the sequence
|
||||
* using lookupExtendedChar()
|
||||
*
|
||||
* If the same sequence already exists in the table, the hash
|
||||
* of the existing sequence will be returned.
|
||||
*
|
||||
* @param unicodePoints An array of unicode character points
|
||||
* @param length Length of @p unicodePoints
|
||||
*/
|
||||
ushort createExtendedChar(ushort* unicodePoints , ushort length);
|
||||
/**
|
||||
* Looks up and returns a pointer to a sequence of unicode characters
|
||||
* which was added to the table using createExtendedChar().
|
||||
*
|
||||
* @param hash The hash key returned by createExtendedChar()
|
||||
* @param length This variable is set to the length of the
|
||||
* character sequence.
|
||||
*
|
||||
* @return A unicode character sequence of size @p length.
|
||||
*/
|
||||
ushort* lookupExtendedChar(ushort hash , ushort& length) const;
|
||||
|
||||
/** The global ExtendedCharTable instance. */
|
||||
static ExtendedCharTable instance;
|
||||
private:
|
||||
// calculates the hash key of a sequence of unicode points of size 'length'
|
||||
ushort extendedCharHash(ushort* unicodePoints , ushort length) const;
|
||||
// tests whether the entry in the table specified by 'hash' matches the
|
||||
// character sequence 'unicodePoints' of size 'length'
|
||||
bool extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const;
|
||||
// internal, maps hash keys to character sequence buffers. The first ushort
|
||||
// in each value is the length of the buffer, followed by the ushorts in the buffer
|
||||
// themselves.
|
||||
QHash<ushort,ushort*> extendedCharTable;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CHARACTER_H
|
||||
|
@ -0,0 +1,301 @@
|
||||
/*
|
||||
This file is part of Konsole, KDE's terminal.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef CHARACTERCOLOR_H
|
||||
#define CHARACTERCOLOR_H
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QColor>
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
/**
|
||||
* An entry in a terminal display's color palette.
|
||||
*
|
||||
* A color palette is an array of 16 ColorEntry instances which map
|
||||
* system color indexes (from 0 to 15) into actual colors.
|
||||
*
|
||||
* Each entry can be set as bold, in which case any text
|
||||
* drawn using the color should be drawn in bold.
|
||||
*
|
||||
* Each entry can also be transparent, in which case the terminal
|
||||
* display should avoid drawing the background for any characters
|
||||
* using the entry as a background.
|
||||
*/
|
||||
class ColorEntry
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new color palette entry.
|
||||
*
|
||||
* @param c The color value for this entry.
|
||||
* @param tr Specifies that the color should be transparent when used as a background color.
|
||||
* @param b Specifies that text drawn with this color should be bold.
|
||||
*/
|
||||
ColorEntry(QColor c, bool tr, bool b) : color(c), transparent(tr), bold(b) {}
|
||||
|
||||
/**
|
||||
* Constructs a new color palette entry with an undefined color, and
|
||||
* with the transparent and bold flags set to false.
|
||||
*/
|
||||
ColorEntry() : transparent(false), bold(false) {}
|
||||
|
||||
/**
|
||||
* Sets the color, transparency and boldness of this color to those of @p rhs.
|
||||
*/
|
||||
void operator=(const ColorEntry& rhs)
|
||||
{
|
||||
color = rhs.color;
|
||||
transparent = rhs.transparent;
|
||||
bold = rhs.bold;
|
||||
}
|
||||
|
||||
/** The color value of this entry for display. */
|
||||
QColor color;
|
||||
|
||||
/**
|
||||
* If true character backgrounds using this color should be transparent.
|
||||
* This is not applicable when the color is used to render text.
|
||||
*/
|
||||
bool transparent;
|
||||
/**
|
||||
* If true characters drawn using this color should be bold.
|
||||
* This is not applicable when the color is used to draw a character's background.
|
||||
*/
|
||||
bool bold;
|
||||
};
|
||||
|
||||
|
||||
// Attributed Character Representations ///////////////////////////////
|
||||
|
||||
// Colors
|
||||
|
||||
#define BASE_COLORS (2+8)
|
||||
#define INTENSITIES 2
|
||||
#define TABLE_COLORS (INTENSITIES*BASE_COLORS)
|
||||
|
||||
#define DEFAULT_FORE_COLOR 0
|
||||
#define DEFAULT_BACK_COLOR 1
|
||||
|
||||
//a standard set of colors using black text on a white background.
|
||||
//defined in TerminalDisplay.cpp
|
||||
|
||||
static const ColorEntry base_color_table[TABLE_COLORS] =
|
||||
// The following are almost IBM standard color codes, with some slight
|
||||
// gamma correction for the dim colors to compensate for bright X screens.
|
||||
// It contains the 8 ansiterm/xterm colors in 2 intensities.
|
||||
{
|
||||
// Fixme: could add faint colors here, also.
|
||||
// normal
|
||||
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback
|
||||
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
|
||||
ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
|
||||
ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
|
||||
ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
|
||||
// intensiv
|
||||
ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
|
||||
ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
|
||||
ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
|
||||
ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
|
||||
ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
|
||||
};
|
||||
|
||||
/* CharacterColor is a union of the various color spaces.
|
||||
|
||||
Assignment is as follows:
|
||||
|
||||
Type - Space - Values
|
||||
|
||||
0 - Undefined - u: 0, v:0 w:0
|
||||
1 - Default - u: 0..1 v:intense w:0
|
||||
2 - System - u: 0..7 v:intense w:0
|
||||
3 - Index(256) - u: 16..255 v:0 w:0
|
||||
4 - RGB - u: 0..255 v:0..256 w:0..256
|
||||
|
||||
Default colour space has two separate colours, namely
|
||||
default foreground and default background colour.
|
||||
*/
|
||||
|
||||
#define COLOR_SPACE_UNDEFINED 0
|
||||
#define COLOR_SPACE_DEFAULT 1
|
||||
#define COLOR_SPACE_SYSTEM 2
|
||||
#define COLOR_SPACE_256 3
|
||||
#define COLOR_SPACE_RGB 4
|
||||
|
||||
/**
|
||||
* Describes the color of a single character in the terminal.
|
||||
*/
|
||||
class CharacterColor
|
||||
{
|
||||
friend class Character;
|
||||
|
||||
public:
|
||||
/** Constructs a new CharacterColor whoose color and color space are undefined. */
|
||||
CharacterColor()
|
||||
: _colorSpace(COLOR_SPACE_UNDEFINED),
|
||||
_u(0),
|
||||
_v(0),
|
||||
_w(0)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Constructs a new CharacterColor using the specified @p colorSpace and with
|
||||
* color value @p co
|
||||
*
|
||||
* The meaning of @p co depends on the @p colorSpace used.
|
||||
*
|
||||
* TODO : Document how @p co relates to @p colorSpace
|
||||
*
|
||||
* TODO : Add documentation about available color spaces.
|
||||
*/
|
||||
CharacterColor(quint8 colorSpace, int co)
|
||||
: _colorSpace(colorSpace),
|
||||
_u(0),
|
||||
_v(0),
|
||||
_w(0)
|
||||
{
|
||||
switch (colorSpace)
|
||||
{
|
||||
case COLOR_SPACE_DEFAULT:
|
||||
_u = co & 1;
|
||||
break;
|
||||
case COLOR_SPACE_SYSTEM:
|
||||
_u = co & 7;
|
||||
_v = (co >> 3) & 1;
|
||||
break;
|
||||
case COLOR_SPACE_256:
|
||||
_u = co & 255;
|
||||
break;
|
||||
case COLOR_SPACE_RGB:
|
||||
_u = co >> 16;
|
||||
_v = co >> 8;
|
||||
_w = co;
|
||||
break;
|
||||
default:
|
||||
_colorSpace = COLOR_SPACE_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this character color entry is valid.
|
||||
*/
|
||||
bool isValid()
|
||||
{
|
||||
return _colorSpace != COLOR_SPACE_UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the value of this color between a normal system color and the corresponding intensive
|
||||
* system color.
|
||||
*
|
||||
* This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM
|
||||
* color spaces.
|
||||
*/
|
||||
void toggleIntensive();
|
||||
|
||||
/**
|
||||
* Returns the color within the specified color @palette
|
||||
*
|
||||
* The @p palette is only used if this color is one of the 16 system colors, otherwise
|
||||
* it is ignored.
|
||||
*/
|
||||
QColor color(const ColorEntry* palette) const;
|
||||
|
||||
/**
|
||||
* Compares two colors and returns true if they represent the same color value and
|
||||
* use the same color space.
|
||||
*/
|
||||
friend bool operator == (const CharacterColor& a, const CharacterColor& b);
|
||||
/**
|
||||
* Compares two colors and returns true if they represent different color values
|
||||
* or use different color spaces.
|
||||
*/
|
||||
friend bool operator != (const CharacterColor& a, const CharacterColor& b);
|
||||
|
||||
private:
|
||||
quint8 _colorSpace;
|
||||
|
||||
// bytes storing the character color
|
||||
quint8 _u;
|
||||
quint8 _v;
|
||||
quint8 _w;
|
||||
};
|
||||
|
||||
inline bool operator == (const CharacterColor& a, const CharacterColor& b)
|
||||
{
|
||||
return *reinterpret_cast<const quint32*>(&a._colorSpace) ==
|
||||
*reinterpret_cast<const quint32*>(&b._colorSpace);
|
||||
}
|
||||
|
||||
inline bool operator != (const CharacterColor& a, const CharacterColor& b)
|
||||
{
|
||||
return *reinterpret_cast<const quint32*>(&a._colorSpace) !=
|
||||
*reinterpret_cast<const quint32*>(&b._colorSpace);
|
||||
}
|
||||
|
||||
inline const QColor color256(quint8 u, const ColorEntry* base)
|
||||
{
|
||||
// 0.. 16: system colors
|
||||
if (u < 8) return base[u+2 ].color; u -= 8;
|
||||
if (u < 8) return base[u+2+BASE_COLORS].color; u -= 8;
|
||||
|
||||
// 16..231: 6x6x6 rgb color cube
|
||||
if (u < 216) return QColor(255*((u/36)%6)/5,
|
||||
255*((u/ 6)%6)/5,
|
||||
255*((u/ 1)%6)/5); u -= 216;
|
||||
|
||||
// 232..255: gray, leaving out black and white
|
||||
int gray = u*10+8; return QColor(gray,gray,gray);
|
||||
}
|
||||
|
||||
inline QColor CharacterColor::color(const ColorEntry* base) const
|
||||
{
|
||||
switch (_colorSpace)
|
||||
{
|
||||
case COLOR_SPACE_DEFAULT: return base[_u+0+(_v?BASE_COLORS:0)].color;
|
||||
case COLOR_SPACE_SYSTEM: return base[_u+2+(_v?BASE_COLORS:0)].color;
|
||||
case COLOR_SPACE_256: return color256(_u,base);
|
||||
case COLOR_SPACE_RGB: return QColor(_u,_v,_w);
|
||||
case COLOR_SPACE_UNDEFINED: return QColor();
|
||||
}
|
||||
|
||||
Q_ASSERT(false); // invalid color space
|
||||
|
||||
return QColor();
|
||||
}
|
||||
|
||||
inline void CharacterColor::toggleIntensive()
|
||||
{
|
||||
if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT)
|
||||
{
|
||||
_v = !_v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // CHARACTERCOLOR_H
|
||||
|
@ -0,0 +1,58 @@
|
||||
#ifndef _COLOR_TABLE_H
|
||||
#define _COLOR_TABLE_H
|
||||
|
||||
#include "CharacterColor.h"
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
static const ColorEntry whiteonblack_color_table[TABLE_COLORS] =
|
||||
{
|
||||
// normal
|
||||
ColorEntry(QColor(0xFF,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0x00,0x00,0x00), 1, 0 ), // Dfore, Dback
|
||||
ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
|
||||
ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
|
||||
ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
|
||||
ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
|
||||
// intensiv
|
||||
ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
|
||||
ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
|
||||
ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
|
||||
ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0xFF), 0, 0 ),
|
||||
ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
|
||||
};
|
||||
|
||||
static const ColorEntry greenonblack_color_table[TABLE_COLORS] =
|
||||
{
|
||||
ColorEntry(QColor( 24, 240, 24), 0, 0), ColorEntry(QColor( 0, 0, 0), 1, 0),
|
||||
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 178, 24, 24), 0, 0),
|
||||
ColorEntry(QColor( 24, 178, 24), 0, 0), ColorEntry(QColor( 178, 104, 24), 0, 0),
|
||||
ColorEntry(QColor( 24, 24, 178), 0, 0), ColorEntry(QColor( 178, 24, 178), 0, 0),
|
||||
ColorEntry(QColor( 24, 178, 178), 0, 0), ColorEntry(QColor( 178, 178, 178), 0, 0),
|
||||
// intensive colors
|
||||
ColorEntry(QColor( 24, 240, 24), 0, 1 ), ColorEntry(QColor( 0, 0, 0), 1, 0 ),
|
||||
ColorEntry(QColor( 104, 104, 104), 0, 0 ), ColorEntry(QColor( 255, 84, 84), 0, 0 ),
|
||||
ColorEntry(QColor( 84, 255, 84), 0, 0 ), ColorEntry(QColor( 255, 255, 84), 0, 0 ),
|
||||
ColorEntry(QColor( 84, 84, 255), 0, 0 ), ColorEntry(QColor( 255, 84, 255), 0, 0 ),
|
||||
ColorEntry(QColor( 84, 255, 255), 0, 0 ), ColorEntry(QColor( 255, 255, 255), 0, 0 )
|
||||
};
|
||||
|
||||
static const ColorEntry blackonlightyellow_color_table[TABLE_COLORS] =
|
||||
{
|
||||
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 255, 255, 221), 1, 0),
|
||||
ColorEntry(QColor( 0, 0, 0), 0, 0), ColorEntry(QColor( 178, 24, 24), 0, 0),
|
||||
ColorEntry(QColor( 24, 178, 24), 0, 0), ColorEntry(QColor( 178, 104, 24), 0, 0),
|
||||
ColorEntry(QColor( 24, 24, 178), 0, 0), ColorEntry(QColor( 178, 24, 178), 0, 0),
|
||||
ColorEntry(QColor( 24, 178, 178), 0, 0), ColorEntry(QColor( 178, 178, 178), 0, 0),
|
||||
ColorEntry(QColor( 0, 0, 0), 0, 1), ColorEntry(QColor( 255, 255, 221), 1, 0),
|
||||
ColorEntry(QColor(104, 104, 104), 0, 0), ColorEntry(QColor( 255, 84, 84), 0, 0),
|
||||
ColorEntry(QColor( 84, 255, 84), 0, 0), ColorEntry(QColor( 255, 255, 84), 0, 0),
|
||||
ColorEntry(QColor( 84, 84, 255), 0, 0), ColorEntry(QColor( 255, 84, 255), 0, 0),
|
||||
ColorEntry(QColor( 84, 255, 255), 0, 0), ColorEntry(QColor( 255, 255, 255), 0, 0)
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,2 @@
|
||||
"keyboard \"Fallback Key Translator\"\n"
|
||||
"key Tab : \"\\t\" \0"
|
@ -0,0 +1,543 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
|
||||
Copyright (C) 2007 Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
Copyright (C) 1996 by Matthias Ettrich <ettrich@kde.org>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "Emulation.h"
|
||||
|
||||
// System
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtCore/QRegExp>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <QtCore/QTime>
|
||||
|
||||
// Konsole
|
||||
#include "KeyboardTranslator.h"
|
||||
#include "Screen.h"
|
||||
#include "TerminalCharacterDecoder.h"
|
||||
#include "ScreenWindow.h"
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* */
|
||||
/* Emulation */
|
||||
/* */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
//#define CNTL(c) ((c)-'@')
|
||||
|
||||
/*!
|
||||
*/
|
||||
|
||||
Emulation::Emulation() :
|
||||
_currentScreen(0),
|
||||
_codec(0),
|
||||
_decoder(0),
|
||||
_keyTranslator(0),
|
||||
_usesMouse(false)
|
||||
{
|
||||
|
||||
// create screens with a default size
|
||||
_screen[0] = new Screen(40,80);
|
||||
_screen[1] = new Screen(40,80);
|
||||
_currentScreen = _screen[0];
|
||||
|
||||
QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) );
|
||||
QObject::connect(&_bulkTimer2, SIGNAL(timeout()), this, SLOT(showBulk()) );
|
||||
|
||||
// listen for mouse status changes
|
||||
connect( this , SIGNAL(programUsesMouseChanged(bool)) ,
|
||||
SLOT(usesMouseChanged(bool)) );
|
||||
}
|
||||
|
||||
bool Emulation::programUsesMouse() const
|
||||
{
|
||||
return _usesMouse;
|
||||
}
|
||||
|
||||
void Emulation::usesMouseChanged(bool usesMouse)
|
||||
{
|
||||
_usesMouse = usesMouse;
|
||||
}
|
||||
|
||||
ScreenWindow* Emulation::createWindow()
|
||||
{
|
||||
ScreenWindow* window = new ScreenWindow();
|
||||
window->setScreen(_currentScreen);
|
||||
_windows << window;
|
||||
|
||||
connect(window , SIGNAL(selectionChanged()),
|
||||
this , SLOT(bufferedUpdate()));
|
||||
|
||||
connect(this , SIGNAL(outputChanged()),
|
||||
window , SLOT(notifyOutputChanged()) );
|
||||
return window;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
|
||||
Emulation::~Emulation()
|
||||
{
|
||||
QListIterator<ScreenWindow*> windowIter(_windows);
|
||||
|
||||
while (windowIter.hasNext())
|
||||
{
|
||||
delete windowIter.next();
|
||||
}
|
||||
|
||||
delete _screen[0];
|
||||
delete _screen[1];
|
||||
delete _decoder;
|
||||
}
|
||||
|
||||
/*! change between primary and alternate _screen
|
||||
*/
|
||||
|
||||
void Emulation::setScreen(int n)
|
||||
{
|
||||
Screen *old = _currentScreen;
|
||||
_currentScreen = _screen[n&1];
|
||||
if (_currentScreen != old)
|
||||
{
|
||||
old->setBusySelecting(false);
|
||||
|
||||
// tell all windows onto this emulation to switch to the newly active _screen
|
||||
QListIterator<ScreenWindow*> windowIter(_windows);
|
||||
while ( windowIter.hasNext() )
|
||||
{
|
||||
windowIter.next()->setScreen(_currentScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Emulation::clearHistory()
|
||||
{
|
||||
_screen[0]->setScroll( _screen[0]->getScroll() , false );
|
||||
}
|
||||
void Emulation::setHistory(const HistoryType& t)
|
||||
{
|
||||
_screen[0]->setScroll(t);
|
||||
|
||||
showBulk();
|
||||
}
|
||||
|
||||
const HistoryType& Emulation::history()
|
||||
{
|
||||
return _screen[0]->getScroll();
|
||||
}
|
||||
|
||||
void Emulation::setCodec(const QTextCodec * qtc)
|
||||
{
|
||||
Q_ASSERT( qtc );
|
||||
|
||||
_codec = qtc;
|
||||
delete _decoder;
|
||||
_decoder = _codec->makeDecoder();
|
||||
|
||||
emit useUtf8Request(utf8());
|
||||
}
|
||||
|
||||
void Emulation::setCodec(EmulationCodec codec)
|
||||
{
|
||||
if ( codec == Utf8Codec )
|
||||
setCodec( QTextCodec::codecForName("utf8") );
|
||||
else if ( codec == LocaleCodec )
|
||||
setCodec( QTextCodec::codecForLocale() );
|
||||
}
|
||||
|
||||
void Emulation::setKeyBindings(const QString& name)
|
||||
{
|
||||
_keyTranslator = KeyboardTranslatorManager::instance()->findTranslator(name);
|
||||
}
|
||||
|
||||
QString Emulation::keyBindings()
|
||||
{
|
||||
return _keyTranslator->name();
|
||||
}
|
||||
|
||||
|
||||
// Interpreting Codes ---------------------------------------------------------
|
||||
|
||||
/*
|
||||
This section deals with decoding the incoming character stream.
|
||||
Decoding means here, that the stream is first separated into `tokens'
|
||||
which are then mapped to a `meaning' provided as operations by the
|
||||
`Screen' class.
|
||||
*/
|
||||
|
||||
/*!
|
||||
*/
|
||||
|
||||
void Emulation::receiveChar(int c)
|
||||
// process application unicode input to terminal
|
||||
// this is a trivial scanner
|
||||
{
|
||||
c &= 0xff;
|
||||
switch (c)
|
||||
{
|
||||
case '\b' : _currentScreen->BackSpace(); break;
|
||||
case '\t' : _currentScreen->Tabulate(); break;
|
||||
case '\n' : _currentScreen->NewLine(); break;
|
||||
case '\r' : _currentScreen->Return(); break;
|
||||
case 0x07 : emit stateSet(NOTIFYBELL);
|
||||
break;
|
||||
default : _currentScreen->ShowCharacter(c); break;
|
||||
};
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* */
|
||||
/* Keyboard Handling */
|
||||
/* */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*!
|
||||
*/
|
||||
|
||||
void Emulation::sendKeyEvent( QKeyEvent* ev )
|
||||
{
|
||||
emit stateSet(NOTIFYNORMAL);
|
||||
|
||||
if (!ev->text().isEmpty())
|
||||
{ // A block of text
|
||||
// Note that the text is proper unicode.
|
||||
// We should do a conversion here, but since this
|
||||
// routine will never be used, we simply emit plain ascii.
|
||||
//emit sendBlock(ev->text().toAscii(),ev->text().length());
|
||||
emit sendData(ev->text().toUtf8(),ev->text().length());
|
||||
}
|
||||
}
|
||||
|
||||
void Emulation::sendString(const char*,int)
|
||||
{
|
||||
// default implementation does nothing
|
||||
}
|
||||
|
||||
void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/)
|
||||
{
|
||||
// default implementation does nothing
|
||||
}
|
||||
|
||||
// Unblocking, Byte to Unicode translation --------------------------------- --
|
||||
|
||||
/*
|
||||
We are doing code conversion from locale to unicode first.
|
||||
TODO: Character composition from the old code. See #96536
|
||||
*/
|
||||
|
||||
void Emulation::receiveData(const char* text, int length)
|
||||
{
|
||||
emit stateSet(NOTIFYACTIVITY);
|
||||
|
||||
bufferedUpdate();
|
||||
|
||||
QString unicodeText = _decoder->toUnicode(text,length);
|
||||
|
||||
//send characters to terminal emulator
|
||||
for (int i=0;i<unicodeText.length();i++)
|
||||
{
|
||||
receiveChar(unicodeText[i].unicode());
|
||||
}
|
||||
|
||||
//look for z-modem indicator
|
||||
//-- someone who understands more about z-modems that I do may be able to move
|
||||
//this check into the above for loop?
|
||||
for (int i=0;i<length;i++)
|
||||
{
|
||||
if (text[i] == '\030')
|
||||
{
|
||||
if ((length-i-1 > 3) && (strncmp(text+i+1, "B00", 3) == 0))
|
||||
emit zmodemDetected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//OLDER VERSION
|
||||
//This version of onRcvBlock was commented out because
|
||||
// a) It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview)
|
||||
// b) It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters
|
||||
// were not printed properly.
|
||||
//
|
||||
//There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below)
|
||||
//which hasn't been ported into the newer function (above). Hopefully someone who understands this better
|
||||
//can find an alternative way of handling the check.
|
||||
|
||||
|
||||
/*void Emulation::onRcvBlock(const char *s, int len)
|
||||
{
|
||||
emit notifySessionState(NOTIFYACTIVITY);
|
||||
|
||||
bufferedUpdate();
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
|
||||
QString result = _decoder->toUnicode(&s[i],1);
|
||||
int reslen = result.length();
|
||||
|
||||
// If we get a control code halfway a multi-byte sequence
|
||||
// we flush the _decoder and continue with the control code.
|
||||
if ((s[i] < 32) && (s[i] > 0))
|
||||
{
|
||||
// Flush _decoder
|
||||
while(!result.length())
|
||||
result = _decoder->toUnicode(&s[i],1);
|
||||
reslen = 1;
|
||||
result.resize(reslen);
|
||||
result[0] = QChar(s[i]);
|
||||
}
|
||||
|
||||
for (int j = 0; j < reslen; j++)
|
||||
{
|
||||
if (result[j].characterategory() == QChar::Mark_NonSpacing)
|
||||
_currentScreen->compose(result.mid(j,1));
|
||||
else
|
||||
onRcvChar(result[j].unicode());
|
||||
}
|
||||
if (s[i] == '\030')
|
||||
{
|
||||
if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0))
|
||||
emit zmodemDetected();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Selection --------------------------------------------------------------- --
|
||||
|
||||
#if 0
|
||||
void Emulation::onSelectionBegin(const int x, const int y, const bool columnmode) {
|
||||
if (!connected) return;
|
||||
_currentScreen->setSelectionStart( x,y,columnmode);
|
||||
showBulk();
|
||||
}
|
||||
|
||||
void Emulation::onSelectionExtend(const int x, const int y) {
|
||||
if (!connected) return;
|
||||
_currentScreen->setSelectionEnd(x,y);
|
||||
showBulk();
|
||||
}
|
||||
|
||||
void Emulation::setSelection(const bool preserve_line_breaks) {
|
||||
if (!connected) return;
|
||||
QString t = _currentScreen->selectedText(preserve_line_breaks);
|
||||
if (!t.isNull())
|
||||
{
|
||||
QListIterator< TerminalDisplay* > viewIter(_views);
|
||||
|
||||
while (viewIter.hasNext())
|
||||
viewIter.next()->setSelection(t);
|
||||
}
|
||||
}
|
||||
|
||||
void Emulation::testIsSelected(const int x, const int y, bool &selected)
|
||||
{
|
||||
if (!connected) return;
|
||||
selected=_currentScreen->isSelected(x,y);
|
||||
}
|
||||
|
||||
void Emulation::clearSelection() {
|
||||
if (!connected) return;
|
||||
_currentScreen->clearSelection();
|
||||
showBulk();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Emulation::writeToStream( TerminalCharacterDecoder* _decoder ,
|
||||
int startLine ,
|
||||
int endLine)
|
||||
{
|
||||
_currentScreen->writeToStream(_decoder,startLine,endLine);
|
||||
}
|
||||
|
||||
int Emulation::lineCount()
|
||||
{
|
||||
// sum number of lines currently on _screen plus number of lines in history
|
||||
return _currentScreen->getLines() + _currentScreen->getHistLines();
|
||||
}
|
||||
|
||||
// Refreshing -------------------------------------------------------------- --
|
||||
|
||||
#define BULK_TIMEOUT1 10
|
||||
#define BULK_TIMEOUT2 40
|
||||
|
||||
/*!
|
||||
*/
|
||||
void Emulation::showBulk()
|
||||
{
|
||||
_bulkTimer1.stop();
|
||||
_bulkTimer2.stop();
|
||||
|
||||
emit outputChanged();
|
||||
|
||||
_currentScreen->resetScrolledLines();
|
||||
_currentScreen->resetDroppedLines();
|
||||
}
|
||||
|
||||
void Emulation::bufferedUpdate()
|
||||
{
|
||||
_bulkTimer1.setSingleShot(true);
|
||||
_bulkTimer1.start(BULK_TIMEOUT1);
|
||||
if (!_bulkTimer2.isActive())
|
||||
{
|
||||
_bulkTimer2.setSingleShot(true);
|
||||
_bulkTimer2.start(BULK_TIMEOUT2);
|
||||
}
|
||||
}
|
||||
|
||||
char Emulation::getErase() const
|
||||
{
|
||||
return '\b';
|
||||
}
|
||||
|
||||
void Emulation::setImageSize(int lines, int columns)
|
||||
{
|
||||
//kDebug() << "Resizing image to: " << lines << "by" << columns << QTime::currentTime().msec();
|
||||
Q_ASSERT( lines > 0 );
|
||||
Q_ASSERT( columns > 0 );
|
||||
|
||||
_screen[0]->resizeImage(lines,columns);
|
||||
_screen[1]->resizeImage(lines,columns);
|
||||
|
||||
emit imageSizeChanged(lines,columns);
|
||||
|
||||
bufferedUpdate();
|
||||
}
|
||||
|
||||
QSize Emulation::imageSize()
|
||||
{
|
||||
return QSize(_currentScreen->getColumns(), _currentScreen->getLines());
|
||||
}
|
||||
|
||||
ushort ExtendedCharTable::extendedCharHash(ushort* unicodePoints , ushort length) const
|
||||
{
|
||||
ushort hash = 0;
|
||||
for ( ushort i = 0 ; i < length ; i++ )
|
||||
{
|
||||
hash = 31*hash + unicodePoints[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const
|
||||
{
|
||||
ushort* entry = extendedCharTable[hash];
|
||||
|
||||
// compare given length with stored sequence length ( given as the first ushort in the
|
||||
// stored buffer )
|
||||
if ( entry == 0 || entry[0] != length )
|
||||
return false;
|
||||
// if the lengths match, each character must be checked. the stored buffer starts at
|
||||
// entry[1]
|
||||
for ( int i = 0 ; i < length ; i++ )
|
||||
{
|
||||
if ( entry[i+1] != unicodePoints[i] )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort length)
|
||||
{
|
||||
// look for this sequence of points in the table
|
||||
ushort hash = extendedCharHash(unicodePoints,length);
|
||||
|
||||
// check existing entry for match
|
||||
while ( extendedCharTable.contains(hash) )
|
||||
{
|
||||
if ( extendedCharMatch(hash,unicodePoints,length) )
|
||||
{
|
||||
// this sequence already has an entry in the table,
|
||||
// return its hash
|
||||
return hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if hash is already used by another, different sequence of unicode character
|
||||
// points then try next hash
|
||||
hash++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// add the new sequence to the table and
|
||||
// return that index
|
||||
ushort* buffer = new ushort[length+1];
|
||||
buffer[0] = length;
|
||||
for ( int i = 0 ; i < length ; i++ )
|
||||
buffer[i+1] = unicodePoints[i];
|
||||
|
||||
extendedCharTable.insert(hash,buffer);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
ushort* ExtendedCharTable::lookupExtendedChar(ushort hash , ushort& length) const
|
||||
{
|
||||
// lookup index in table and if found, set the length
|
||||
// argument and return a pointer to the character sequence
|
||||
|
||||
ushort* buffer = extendedCharTable[hash];
|
||||
if ( buffer )
|
||||
{
|
||||
length = buffer[0];
|
||||
return buffer+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ExtendedCharTable::ExtendedCharTable()
|
||||
{
|
||||
}
|
||||
ExtendedCharTable::~ExtendedCharTable()
|
||||
{
|
||||
// free all allocated character buffers
|
||||
QHashIterator<ushort,ushort*> iter(extendedCharTable);
|
||||
while ( iter.hasNext() )
|
||||
{
|
||||
iter.next();
|
||||
delete[] iter.value();
|
||||
}
|
||||
}
|
||||
|
||||
// global instance
|
||||
ExtendedCharTable ExtendedCharTable::instance;
|
||||
|
||||
|
||||
//#include "moc_Emulation.cpp"
|
||||
|
@ -0,0 +1,465 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef EMULATION_H
|
||||
#define EMULATION_H
|
||||
|
||||
// System
|
||||
#include <stdio.h>
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QKeyEvent>
|
||||
//#include <QPointer>
|
||||
#include <QtCore/QTextCodec>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
class KeyboardTranslator;
|
||||
class HistoryType;
|
||||
class Screen;
|
||||
class ScreenWindow;
|
||||
class TerminalCharacterDecoder;
|
||||
|
||||
/**
|
||||
* This enum describes the available states which
|
||||
* the terminal emulation may be set to.
|
||||
*
|
||||
* These are the values used by Emulation::stateChanged()
|
||||
*/
|
||||
enum
|
||||
{
|
||||
/** The emulation is currently receiving user input. */
|
||||
NOTIFYNORMAL=0,
|
||||
/**
|
||||
* The terminal program has triggered a bell event
|
||||
* to get the user's attention.
|
||||
*/
|
||||
NOTIFYBELL=1,
|
||||
/**
|
||||
* The emulation is currently receiving data from its
|
||||
* terminal input.
|
||||
*/
|
||||
NOTIFYACTIVITY=2,
|
||||
|
||||
// unused here?
|
||||
NOTIFYSILENCE=3
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for terminal emulation back-ends.
|
||||
*
|
||||
* The back-end is responsible for decoding an incoming character stream and
|
||||
* producing an output image of characters.
|
||||
*
|
||||
* When input from the terminal is received, the receiveData() slot should be called with
|
||||
* the data which has arrived. The emulation will process the data and update the
|
||||
* screen image accordingly. The codec used to decode the incoming character stream
|
||||
* into the unicode characters used internally can be specified using setCodec()
|
||||
*
|
||||
* The size of the screen image can be specified by calling setImageSize() with the
|
||||
* desired number of lines and columns. When new lines are added, old content
|
||||
* is moved into a history store, which can be set by calling setHistory().
|
||||
*
|
||||
* The screen image can be accessed by creating a ScreenWindow onto this emulation
|
||||
* by calling createWindow(). Screen windows provide access to a section of the
|
||||
* output. Each screen window covers the same number of lines and columns as the
|
||||
* image size returned by imageSize(). The screen window can be moved up and down
|
||||
* and provides transparent access to both the current on-screen image and the
|
||||
* previous output. The screen windows emit an outputChanged signal
|
||||
* when the section of the image they are looking at changes.
|
||||
* Graphical views can then render the contents of a screen window, listening for notifications
|
||||
* of output changes from the screen window which they are associated with and updating
|
||||
* accordingly.
|
||||
*
|
||||
* The emulation also is also responsible for converting input from the connected views such
|
||||
* as keypresses and mouse activity into a character string which can be sent
|
||||
* to the terminal program. Key presses can be processed by calling the sendKeyEvent() slot,
|
||||
* while mouse events can be processed using the sendMouseEvent() slot. When the character
|
||||
* stream has been produced, the emulation will emit a sendData() signal with a pointer
|
||||
* to the character buffer. This data should be fed to the standard input of the terminal
|
||||
* process. The translation of key presses into an output character stream is performed
|
||||
* using a lookup in a set of key bindings which map key sequences to output
|
||||
* character sequences. The name of the key bindings set used can be specified using
|
||||
* setKeyBindings()
|
||||
*
|
||||
* The emulation maintains certain state information which changes depending on the
|
||||
* input received. The emulation can be reset back to its starting state by calling
|
||||
* reset().
|
||||
*
|
||||
* The emulation also maintains an activity state, which specifies whether
|
||||
* terminal is currently active ( when data is received ), normal
|
||||
* ( when the terminal is idle or receiving user input ) or trying
|
||||
* to alert the user ( also known as a "Bell" event ). The stateSet() signal
|
||||
* is emitted whenever the activity state is set. This can be used to determine
|
||||
* how long the emulation has been active/idle for and also respond to
|
||||
* a 'bell' event in different ways.
|
||||
*/
|
||||
class Emulation : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/** Constructs a new terminal emulation */
|
||||
Emulation();
|
||||
~Emulation();
|
||||
|
||||
/**
|
||||
* Creates a new window onto the output from this emulation. The contents
|
||||
* of the window are then rendered by views which are set to use this window using the
|
||||
* TerminalDisplay::setScreenWindow() method.
|
||||
*/
|
||||
ScreenWindow* createWindow();
|
||||
|
||||
/** Returns the size of the screen image which the emulation produces */
|
||||
QSize imageSize();
|
||||
|
||||
/**
|
||||
* Returns the total number of lines, including those stored in the history.
|
||||
*/
|
||||
int lineCount();
|
||||
|
||||
|
||||
/**
|
||||
* Sets the history store used by this emulation. When new lines
|
||||
* are added to the output, older lines at the top of the screen are transferred to a history
|
||||
* store.
|
||||
*
|
||||
* The number of lines which are kept and the storage location depend on the
|
||||
* type of store.
|
||||
*/
|
||||
void setHistory(const HistoryType&);
|
||||
/** Returns the history store used by this emulation. See setHistory() */
|
||||
const HistoryType& history();
|
||||
/** Clears the history scroll. */
|
||||
void clearHistory();
|
||||
|
||||
/**
|
||||
* Copies the output history from @p startLine to @p endLine
|
||||
* into @p stream, using @p decoder to convert the terminal
|
||||
* characters into text.
|
||||
*
|
||||
* @param decoder A decoder which converts lines of terminal characters with
|
||||
* appearance attributes into output text. PlainTextDecoder is the most commonly
|
||||
* used decoder.
|
||||
* @param startLine The first
|
||||
*/
|
||||
virtual void writeToStream(TerminalCharacterDecoder* decoder,int startLine,int endLine);
|
||||
|
||||
|
||||
/** Returns the codec used to decode incoming characters. See setCodec() */
|
||||
const QTextCodec* codec() { return _codec; }
|
||||
/** Sets the codec used to decode incoming characters. */
|
||||
void setCodec(const QTextCodec*);
|
||||
|
||||
/**
|
||||
* Convenience method.
|
||||
* Returns true if the current codec used to decode incoming
|
||||
* characters is UTF-8
|
||||
*/
|
||||
bool utf8() { Q_ASSERT(_codec); return _codec->mibEnum() == 106; }
|
||||
|
||||
|
||||
/** TODO Document me */
|
||||
virtual char getErase() const;
|
||||
|
||||
/**
|
||||
* Sets the key bindings used to key events
|
||||
* ( received through sendKeyEvent() ) into character
|
||||
* streams to send to the terminal.
|
||||
*/
|
||||
void setKeyBindings(const QString& name);
|
||||
/**
|
||||
* Returns the name of the emulation's current key bindings.
|
||||
* See setKeyBindings()
|
||||
*/
|
||||
QString keyBindings();
|
||||
|
||||
/**
|
||||
* Copies the current image into the history and clears the screen.
|
||||
*/
|
||||
virtual void clearEntireScreen() =0;
|
||||
|
||||
/** Resets the state of the terminal. */
|
||||
virtual void reset() =0;
|
||||
|
||||
/**
|
||||
* Returns true if the active terminal program wants
|
||||
* mouse input events.
|
||||
*
|
||||
* The programUsesMouseChanged() signal is emitted when this
|
||||
* changes.
|
||||
*/
|
||||
bool programUsesMouse() const;
|
||||
|
||||
public slots:
|
||||
|
||||
/** Change the size of the emulation's image */
|
||||
virtual void setImageSize(int lines, int columns);
|
||||
|
||||
/**
|
||||
* Interprets a sequence of characters and sends the result to the terminal.
|
||||
* This is equivalent to calling sendKeyEvent() for each character in @p text in succession.
|
||||
*/
|
||||
virtual void sendText(const QString& text) = 0;
|
||||
|
||||
/**
|
||||
* Interprets a key press event and emits the sendData() signal with
|
||||
* the resulting character stream.
|
||||
*/
|
||||
virtual void sendKeyEvent(QKeyEvent*);
|
||||
|
||||
/**
|
||||
* Converts information about a mouse event into an xterm-compatible escape
|
||||
* sequence and emits the character sequence via sendData()
|
||||
*/
|
||||
virtual void sendMouseEvent(int buttons, int column, int line, int eventType);
|
||||
|
||||
/**
|
||||
* Sends a string of characters to the foreground terminal process.
|
||||
*
|
||||
* @param string The characters to send.
|
||||
* @param length Length of @p string or if set to a negative value, @p string will
|
||||
* be treated as a null-terminated string and its length will be determined automatically.
|
||||
*/
|
||||
virtual void sendString(const char* string, int length = -1) = 0;
|
||||
|
||||
/**
|
||||
* Processes an incoming stream of characters. receiveData() decodes the incoming
|
||||
* character buffer using the current codec(), and then calls receiveChar() for
|
||||
* each unicode character in the resulting buffer.
|
||||
*
|
||||
* receiveData() also starts a timer which causes the outputChanged() signal
|
||||
* to be emitted when it expires. The timer allows multiple updates in quick
|
||||
* succession to be buffered into a single outputChanged() signal emission.
|
||||
*
|
||||
* @param buffer A string of characters received from the terminal program.
|
||||
* @param len The length of @p buffer
|
||||
*/
|
||||
void receiveData(const char* buffer,int len);
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted when a buffer of data is ready to send to the
|
||||
* standard input of the terminal.
|
||||
*
|
||||
* @param data The buffer of data ready to be sent
|
||||
* @paran len The length of @p data in bytes
|
||||
*/
|
||||
void sendData(const char* data,int len);
|
||||
|
||||
/**
|
||||
* Requests that sending of input to the emulation
|
||||
* from the terminal process be suspended or resumed.
|
||||
*
|
||||
* @param suspend If true, requests that sending of
|
||||
* input from the terminal process' stdout be
|
||||
* suspended. Otherwise requests that sending of
|
||||
* input be resumed.
|
||||
*/
|
||||
void lockPtyRequest(bool suspend);
|
||||
|
||||
/**
|
||||
* Requests that the pty used by the terminal process
|
||||
* be set to UTF 8 mode.
|
||||
*
|
||||
* TODO: More documentation
|
||||
*/
|
||||
void useUtf8Request(bool);
|
||||
|
||||
/**
|
||||
* Emitted when the activity state of the emulation is set.
|
||||
*
|
||||
* @param state The new activity state, one of NOTIFYNORMAL, NOTIFYACTIVITY
|
||||
* or NOTIFYBELL
|
||||
*/
|
||||
void stateSet(int state);
|
||||
|
||||
/** TODO Document me */
|
||||
void zmodemDetected();
|
||||
|
||||
|
||||
/**
|
||||
* Requests that the color of the text used
|
||||
* to represent the tabs associated with this
|
||||
* emulation be changed. This is a Konsole-specific
|
||||
* extension from pre-KDE 4 times.
|
||||
*
|
||||
* TODO: Document how the parameter works.
|
||||
*/
|
||||
void changeTabTextColorRequest(int color);
|
||||
|
||||
/**
|
||||
* This is emitted when the program running in the shell indicates whether or
|
||||
* not it is interested in mouse events.
|
||||
*
|
||||
* @param usesMouse This will be true if the program wants to be informed about
|
||||
* mouse events or false otherwise.
|
||||
*/
|
||||
void programUsesMouseChanged(bool usesMouse);
|
||||
|
||||
/**
|
||||
* Emitted when the contents of the screen image change.
|
||||
* The emulation buffers the updates from successive image changes,
|
||||
* and only emits outputChanged() at sensible intervals when
|
||||
* there is a lot of terminal activity.
|
||||
*
|
||||
* Normally there is no need for objects other than the screen windows
|
||||
* created with createWindow() to listen for this signal.
|
||||
*
|
||||
* ScreenWindow objects created using createWindow() will emit their
|
||||
* own outputChanged() signal in response to this signal.
|
||||
*/
|
||||
void outputChanged();
|
||||
|
||||
/**
|
||||
* Emitted when the program running in the terminal wishes to update the
|
||||
* session's title. This also allows terminal programs to customize other
|
||||
* aspects of the terminal emulation display.
|
||||
*
|
||||
* This signal is emitted when the escape sequence "\033]ARG;VALUE\007"
|
||||
* is received in the input string, where ARG is a number specifying what
|
||||
* should change and VALUE is a string specifying the new value.
|
||||
*
|
||||
* TODO: The name of this method is not very accurate since this method
|
||||
* is used to perform a whole range of tasks besides just setting
|
||||
* the user-title of the session.
|
||||
*
|
||||
* @param title Specifies what to change.
|
||||
* <ul>
|
||||
* <li>0 - Set window icon text and session title to @p newTitle</li>
|
||||
* <li>1 - Set window icon text to @p newTitle</li>
|
||||
* <li>2 - Set session title to @p newTitle</li>
|
||||
* <li>11 - Set the session's default background color to @p newTitle,
|
||||
* where @p newTitle can be an HTML-style string (#RRGGBB) or a named
|
||||
* color (eg 'red', 'blue').
|
||||
* See http://doc.trolltech.com/4.2/qcolor.html#setNamedColor for more
|
||||
* details.
|
||||
* </li>
|
||||
* <li>31 - Supposedly treats @p newTitle as a URL and opens it (NOT IMPLEMENTED)</li>
|
||||
* <li>32 - Sets the icon associated with the session. @p newTitle is the name
|
||||
* of the icon to use, which can be the name of any icon in the current KDE icon
|
||||
* theme (eg: 'konsole', 'kate', 'folder_home')</li>
|
||||
* </ul>
|
||||
* @param newTitle Specifies the new title
|
||||
*/
|
||||
|
||||
void titleChanged(int title,const QString& newTitle);
|
||||
|
||||
/**
|
||||
* Emitted when the program running in the terminal changes the
|
||||
* screen size.
|
||||
*/
|
||||
void imageSizeChanged(int lineCount , int columnCount);
|
||||
|
||||
/**
|
||||
* Emitted when the terminal program requests to change various properties
|
||||
* of the terminal display.
|
||||
*
|
||||
* A profile change command occurs when a special escape sequence, followed
|
||||
* by a string containing a series of name and value pairs is received.
|
||||
* This string can be parsed using a ProfileCommandParser instance.
|
||||
*
|
||||
* @param text A string expected to contain a series of key and value pairs in
|
||||
* the form: name=value;name2=value2 ...
|
||||
*/
|
||||
void profileChangeCommandReceived(const QString& text);
|
||||
|
||||
protected:
|
||||
virtual void setMode (int mode) = 0;
|
||||
virtual void resetMode(int mode) = 0;
|
||||
|
||||
/**
|
||||
* Processes an incoming character. See receiveData()
|
||||
* @p ch A unicode character code.
|
||||
*/
|
||||
virtual void receiveChar(int ch);
|
||||
|
||||
/**
|
||||
* Sets the active screen. The terminal has two screens, primary and alternate.
|
||||
* The primary screen is used by default. When certain interactive programs such
|
||||
* as Vim are run, they trigger a switch to the alternate screen.
|
||||
*
|
||||
* @param index 0 to switch to the primary screen, or 1 to switch to the alternate screen
|
||||
*/
|
||||
void setScreen(int index);
|
||||
|
||||
enum EmulationCodec
|
||||
{
|
||||
LocaleCodec = 0,
|
||||
Utf8Codec = 1
|
||||
};
|
||||
void setCodec(EmulationCodec codec); // codec number, 0 = locale, 1=utf8
|
||||
|
||||
|
||||
QList<ScreenWindow*> _windows;
|
||||
|
||||
Screen* _currentScreen; // pointer to the screen which is currently active,
|
||||
// this is one of the elements in the screen[] array
|
||||
|
||||
Screen* _screen[2]; // 0 = primary screen ( used by most programs, including the shell
|
||||
// scrollbars are enabled in this mode )
|
||||
// 1 = alternate ( used by vi , emacs etc.
|
||||
// scrollbars are not enabled in this mode )
|
||||
|
||||
|
||||
//decodes an incoming C-style character stream into a unicode QString using
|
||||
//the current text codec. (this allows for rendering of non-ASCII characters in text files etc.)
|
||||
const QTextCodec* _codec;
|
||||
QTextDecoder* _decoder;
|
||||
|
||||
const KeyboardTranslator* _keyTranslator; // the keyboard layout
|
||||
|
||||
protected slots:
|
||||
/**
|
||||
* Schedules an update of attached views.
|
||||
* Repeated calls to bufferedUpdate() in close succession will result in only a single update,
|
||||
* much like the Qt buffered update of widgets.
|
||||
*/
|
||||
void bufferedUpdate();
|
||||
|
||||
private slots:
|
||||
|
||||
// triggered by timer, causes the emulation to send an updated screen image to each
|
||||
// view
|
||||
void showBulk();
|
||||
|
||||
void usesMouseChanged(bool usesMouse);
|
||||
|
||||
private:
|
||||
|
||||
bool _usesMouse;
|
||||
QTimer _bulkTimer1;
|
||||
QTimer _bulkTimer2;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ifndef EMULATION_H
|
@ -0,0 +1,74 @@
|
||||
"keyboard \"Default (XFree 4)\""
|
||||
"key Escape : \"\\E\""
|
||||
"key Tab -Shift : \"\\t\"\n"
|
||||
"key Tab +Shift+Ansi : \"\\E[Z\"\n"
|
||||
"key Tab +Shift-Ansi : \"\\t\"\n"
|
||||
"key Backtab +Ansi : \"\\E[Z\"\n"
|
||||
"key Backtab -Ansi : \"\\t\"\n"
|
||||
"key Return-Shift-NewLine : \"\\r\"\n"
|
||||
"key Return-Shift+NewLine : \"\\r\\n\"\n"
|
||||
"key Return+Shift : \"\\EOM\"\n"
|
||||
"key Backspace : \"\\x7f\"\n"
|
||||
"key Up -Shift-Ansi : \"\\EA\"\n"
|
||||
"key Down -Shift-Ansi : \"\\EB\"\n"
|
||||
"key Right-Shift-Ansi : \"\\EC\"\n"
|
||||
"key Left -Shift-Ansi : \"\\ED\"\n"
|
||||
"key Up -Shift-AnyMod+Ansi+AppCuKeys : \"\\EOA\"\n"
|
||||
"key Down -Shift-AnyMod+Ansi+AppCuKeys : \"\\EOB\"\n"
|
||||
"key Right -Shift-AnyMod+Ansi+AppCuKeys : \"\\EOC\"\n"
|
||||
"key Left -Shift-AnyMod+Ansi+AppCuKeys : \"\\EOD\"\n"
|
||||
"key Up -Shift-AnyMod+Ansi-AppCuKeys : \"\\E[A\"\n"
|
||||
"key Down -Shift-AnyMod+Ansi-AppCuKeys : \"\\E[B\"\n"
|
||||
"key Right -Shift-AnyMod+Ansi-AppCuKeys : \"\\E[C\"\n"
|
||||
"key Left -Shift-AnyMod+Ansi-AppCuKeys : \"\\E[D\"\n"
|
||||
"key Up -Shift+AnyMod+Ansi : \"\\E[1;*A\"\n"
|
||||
"key Down -Shift+AnyMod+Ansi : \"\\E[1;*B\"\n"
|
||||
"key Right -Shift+AnyMod+Ansi : \"\\E[1;*C\"\n"
|
||||
"key Left -Shift+AnyMod+Ansi : \"\\E[1;*D\"\n"
|
||||
"key Enter+NewLine : \"\\r\\n\"\n"
|
||||
"key Enter-NewLine : \"\\r\"\n"
|
||||
"key Home -AnyMod -AppCuKeys : \"\\E[H\" \n"
|
||||
"key End -AnyMod -AppCuKeys : \"\\E[F\" \n"
|
||||
"key Home -AnyMod +AppCuKeys : \"\\EOH\" \n"
|
||||
"key End -AnyMod +AppCuKeys : \"\\EOF\" \n"
|
||||
"key Home +AnyMod : \"\\E[1;*H\"\n"
|
||||
"key End +AnyMod : \"\\E[1;*F\"\n"
|
||||
"key Insert -AnyMod : \"\\E[2~\"\n"
|
||||
"key Delete -AnyMod : \"\\E[3~\"\n"
|
||||
"key Insert +AnyMod : \"\\E[2;*~\"\n"
|
||||
"key Delete +AnyMod : \"\\E[3;*~\"\n"
|
||||
"key Prior -Shift-AnyMod : \"\\E[5~\"\n"
|
||||
"key Next -Shift-AnyMod : \"\\E[6~\"\n"
|
||||
"key Prior -Shift+AnyMod : \"\\E[5;*~\"\n"
|
||||
"key Next -Shift+AnyMod : \"\\E[6;*~\"\n"
|
||||
"key F1 -AnyMod : \"\\EOP\"\n"
|
||||
"key F2 -AnyMod : \"\\EOQ\"\n"
|
||||
"key F3 -AnyMod : \"\\EOR\"\n"
|
||||
"key F4 -AnyMod : \"\\EOS\"\n"
|
||||
"key F5 -AnyMod : \"\\E[15~\"\n"
|
||||
"key F6 -AnyMod : \"\\E[17~\"\n"
|
||||
"key F7 -AnyMod : \"\\E[18~\"\n"
|
||||
"key F8 -AnyMod : \"\\E[19~\"\n"
|
||||
"key F9 -AnyMod : \"\\E[20~\"\n"
|
||||
"key F10 -AnyMod : \"\\E[21~\"\n"
|
||||
"key F11 -AnyMod : \"\\E[23~\"\n"
|
||||
"key F12 -AnyMod : \"\\E[24~\"\n"
|
||||
"key F1 +AnyMod : \"\\EO*P\"\n"
|
||||
"key F2 +AnyMod : \"\\EO*Q\"\n"
|
||||
"key F3 +AnyMod : \"\\EO*R\"\n"
|
||||
"key F4 +AnyMod : \"\\EO*S\"\n"
|
||||
"key F5 +AnyMod : \"\\E[15;*~\"\n"
|
||||
"key F6 +AnyMod : \"\\E[17;*~\"\n"
|
||||
"key F7 +AnyMod : \"\\E[18;*~\"\n"
|
||||
"key F8 +AnyMod : \"\\E[19;*~\"\n"
|
||||
"key F9 +AnyMod : \"\\E[20;*~\"\n"
|
||||
"key F10 +AnyMod : \"\\E[21;*~\"\n"
|
||||
"key F11 +AnyMod : \"\\E[23;*~\"\n"
|
||||
"key F12 +AnyMod : \"\\E[24;*~\"\n"
|
||||
"key Space +Control : \"\\x00\"\n"
|
||||
"key Up +Shift-AppScreen : scrollLineUp\n"
|
||||
"key Prior +Shift-AppScreen : scrollPageUp\n"
|
||||
"key Down +Shift-AppScreen : scrollLineDown\n"
|
||||
"key Next +Shift-AppScreen : scrollPageDown\n"
|
||||
"key ScrollLock : scrollLock\n"
|
||||
"\0"
|
@ -0,0 +1,562 @@
|
||||
/*
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "Filter.h"
|
||||
|
||||
// System
|
||||
#include <iostream>
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtCore/QString>
|
||||
|
||||
#include <QtCore/QSharedData>
|
||||
#include <QtCore>
|
||||
|
||||
// KDE
|
||||
//#include <KLocale>
|
||||
//#include <KRun>
|
||||
|
||||
// Konsole
|
||||
#include "TerminalCharacterDecoder.h"
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
FilterChain::~FilterChain()
|
||||
{
|
||||
QMutableListIterator<Filter*> iter(*this);
|
||||
|
||||
while ( iter.hasNext() )
|
||||
{
|
||||
Filter* filter = iter.next();
|
||||
iter.remove();
|
||||
delete filter;
|
||||
}
|
||||
}
|
||||
|
||||
void FilterChain::addFilter(Filter* filter)
|
||||
{
|
||||
append(filter);
|
||||
}
|
||||
void FilterChain::removeFilter(Filter* filter)
|
||||
{
|
||||
removeAll(filter);
|
||||
}
|
||||
bool FilterChain::containsFilter(Filter* filter)
|
||||
{
|
||||
return contains(filter);
|
||||
}
|
||||
void FilterChain::reset()
|
||||
{
|
||||
QListIterator<Filter*> iter(*this);
|
||||
while (iter.hasNext())
|
||||
iter.next()->reset();
|
||||
}
|
||||
void FilterChain::setBuffer(const QString* buffer , const QList<int>* linePositions)
|
||||
{
|
||||
QListIterator<Filter*> iter(*this);
|
||||
while (iter.hasNext())
|
||||
iter.next()->setBuffer(buffer,linePositions);
|
||||
}
|
||||
void FilterChain::process()
|
||||
{
|
||||
QListIterator<Filter*> iter(*this);
|
||||
while (iter.hasNext())
|
||||
iter.next()->process();
|
||||
}
|
||||
void FilterChain::clear()
|
||||
{
|
||||
QList<Filter*>::clear();
|
||||
}
|
||||
Filter::HotSpot* FilterChain::hotSpotAt(int line , int column) const
|
||||
{
|
||||
QListIterator<Filter*> iter(*this);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
Filter* filter = iter.next();
|
||||
Filter::HotSpot* spot = filter->hotSpotAt(line,column);
|
||||
if ( spot != 0 )
|
||||
{
|
||||
return spot;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QList<Filter::HotSpot*> FilterChain::hotSpots() const
|
||||
{
|
||||
QList<Filter::HotSpot*> list;
|
||||
QListIterator<Filter*> iter(*this);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
Filter* filter = iter.next();
|
||||
list << filter->hotSpots();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
//QList<Filter::HotSpot*> FilterChain::hotSpotsAtLine(int line) const;
|
||||
|
||||
TerminalImageFilterChain::TerminalImageFilterChain()
|
||||
: _buffer(0)
|
||||
, _linePositions(0)
|
||||
{
|
||||
}
|
||||
|
||||
TerminalImageFilterChain::~TerminalImageFilterChain()
|
||||
{
|
||||
delete _buffer;
|
||||
delete _linePositions;
|
||||
}
|
||||
|
||||
void TerminalImageFilterChain::setImage(const Character* const image , int lines , int columns, const QVector<LineProperty>& lineProperties)
|
||||
{
|
||||
//qDebug("%s %d", __FILE__, __LINE__);
|
||||
if (empty())
|
||||
return;
|
||||
//qDebug("%s %d", __FILE__, __LINE__);
|
||||
|
||||
// reset all filters and hotspots
|
||||
reset();
|
||||
//qDebug("%s %d", __FILE__, __LINE__);
|
||||
|
||||
PlainTextDecoder decoder;
|
||||
decoder.setTrailingWhitespace(false);
|
||||
|
||||
//qDebug("%s %d", __FILE__, __LINE__);
|
||||
// setup new shared buffers for the filters to process on
|
||||
QString* newBuffer = new QString();
|
||||
QList<int>* newLinePositions = new QList<int>();
|
||||
setBuffer( newBuffer , newLinePositions );
|
||||
|
||||
// free the old buffers
|
||||
delete _buffer;
|
||||
delete _linePositions;
|
||||
|
||||
_buffer = newBuffer;
|
||||
_linePositions = newLinePositions;
|
||||
|
||||
QTextStream lineStream(_buffer);
|
||||
decoder.begin(&lineStream);
|
||||
|
||||
for (int i=0 ; i < lines ; i++)
|
||||
{
|
||||
_linePositions->append(_buffer->length());
|
||||
decoder.decodeLine(image + i*columns,columns,LINE_DEFAULT);
|
||||
|
||||
// pretend that each line ends with a newline character.
|
||||
// this prevents a link that occurs at the end of one line
|
||||
// being treated as part of a link that occurs at the start of the next line
|
||||
//
|
||||
// the downside is that links which are spread over more than one line are not
|
||||
// highlighted.
|
||||
//
|
||||
// TODO - Use the "line wrapped" attribute associated with lines in a
|
||||
// terminal image to avoid adding this imaginary character for wrapped
|
||||
// lines
|
||||
if ( !(lineProperties.value(i,LINE_DEFAULT) & LINE_WRAPPED) )
|
||||
lineStream << QChar('\n');
|
||||
}
|
||||
decoder.end();
|
||||
// qDebug("%s %d", __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
Filter::Filter() :
|
||||
_linePositions(0),
|
||||
_buffer(0)
|
||||
{
|
||||
}
|
||||
|
||||
Filter::~Filter()
|
||||
{
|
||||
QListIterator<HotSpot*> iter(_hotspotList);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
delete iter.next();
|
||||
}
|
||||
}
|
||||
void Filter::reset()
|
||||
{
|
||||
_hotspots.clear();
|
||||
_hotspotList.clear();
|
||||
}
|
||||
|
||||
void Filter::setBuffer(const QString* buffer , const QList<int>* linePositions)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_linePositions = linePositions;
|
||||
}
|
||||
|
||||
void Filter::getLineColumn(int position , int& startLine , int& startColumn)
|
||||
{
|
||||
Q_ASSERT( _linePositions );
|
||||
Q_ASSERT( _buffer );
|
||||
|
||||
|
||||
for (int i = 0 ; i < _linePositions->count() ; i++)
|
||||
{
|
||||
//kDebug() << "line position at " << i << " = " << _linePositions[i];
|
||||
int nextLine = 0;
|
||||
|
||||
if ( i == _linePositions->count()-1 )
|
||||
{
|
||||
nextLine = _buffer->length() + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextLine = _linePositions->value(i+1);
|
||||
}
|
||||
|
||||
// kDebug() << "pos - " << position << " line pos(" << i<< ") " << _linePositions->value(i) <<
|
||||
// " next = " << nextLine << " buffer len = " << _buffer->length();
|
||||
|
||||
if ( _linePositions->value(i) <= position && position < nextLine )
|
||||
{
|
||||
startLine = i;
|
||||
startColumn = position - _linePositions->value(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*void Filter::addLine(const QString& text)
|
||||
{
|
||||
_linePositions << _buffer.length();
|
||||
_buffer.append(text);
|
||||
}*/
|
||||
|
||||
const QString* Filter::buffer()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
Filter::HotSpot::~HotSpot()
|
||||
{
|
||||
}
|
||||
void Filter::addHotSpot(HotSpot* spot)
|
||||
{
|
||||
_hotspotList << spot;
|
||||
|
||||
for (int line = spot->startLine() ; line <= spot->endLine() ; line++)
|
||||
{
|
||||
_hotspots.insert(line,spot);
|
||||
}
|
||||
}
|
||||
QList<Filter::HotSpot*> Filter::hotSpots() const
|
||||
{
|
||||
return _hotspotList;
|
||||
}
|
||||
QList<Filter::HotSpot*> Filter::hotSpotsAtLine(int line) const
|
||||
{
|
||||
return _hotspots.values(line);
|
||||
}
|
||||
|
||||
Filter::HotSpot* Filter::hotSpotAt(int line , int column) const
|
||||
{
|
||||
QListIterator<HotSpot*> spotIter(_hotspots.values(line));
|
||||
|
||||
while (spotIter.hasNext())
|
||||
{
|
||||
HotSpot* spot = spotIter.next();
|
||||
|
||||
if ( spot->startLine() == line && spot->startColumn() > column )
|
||||
continue;
|
||||
if ( spot->endLine() == line && spot->endColumn() < column )
|
||||
continue;
|
||||
|
||||
return spot;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn)
|
||||
: _startLine(startLine)
|
||||
, _startColumn(startColumn)
|
||||
, _endLine(endLine)
|
||||
, _endColumn(endColumn)
|
||||
, _type(NotSpecified)
|
||||
{
|
||||
}
|
||||
QString Filter::HotSpot::tooltip() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
QList<QAction*> Filter::HotSpot::actions()
|
||||
{
|
||||
return QList<QAction*>();
|
||||
}
|
||||
int Filter::HotSpot::startLine() const
|
||||
{
|
||||
return _startLine;
|
||||
}
|
||||
int Filter::HotSpot::endLine() const
|
||||
{
|
||||
return _endLine;
|
||||
}
|
||||
int Filter::HotSpot::startColumn() const
|
||||
{
|
||||
return _startColumn;
|
||||
}
|
||||
int Filter::HotSpot::endColumn() const
|
||||
{
|
||||
return _endColumn;
|
||||
}
|
||||
Filter::HotSpot::Type Filter::HotSpot::type() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
void Filter::HotSpot::setType(Type type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
RegExpFilter::RegExpFilter()
|
||||
{
|
||||
}
|
||||
|
||||
RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
|
||||
: Filter::HotSpot(startLine,startColumn,endLine,endColumn)
|
||||
{
|
||||
setType(Marker);
|
||||
}
|
||||
|
||||
void RegExpFilter::HotSpot::activate(QObject*)
|
||||
{
|
||||
}
|
||||
|
||||
void RegExpFilter::HotSpot::setCapturedTexts(const QStringList& texts)
|
||||
{
|
||||
_capturedTexts = texts;
|
||||
}
|
||||
QStringList RegExpFilter::HotSpot::capturedTexts() const
|
||||
{
|
||||
return _capturedTexts;
|
||||
}
|
||||
|
||||
void RegExpFilter::setRegExp(const QRegExp& regExp)
|
||||
{
|
||||
_searchText = regExp;
|
||||
}
|
||||
QRegExp RegExpFilter::regExp() const
|
||||
{
|
||||
return _searchText;
|
||||
}
|
||||
/*void RegExpFilter::reset(int)
|
||||
{
|
||||
_buffer = QString();
|
||||
}*/
|
||||
void RegExpFilter::process()
|
||||
{
|
||||
int pos = 0;
|
||||
const QString* text = buffer();
|
||||
|
||||
Q_ASSERT( text );
|
||||
|
||||
// ignore any regular expressions which match an empty string.
|
||||
// otherwise the while loop below will run indefinitely
|
||||
static const QString emptyString("");
|
||||
if ( _searchText.exactMatch(emptyString) )
|
||||
return;
|
||||
|
||||
while(pos >= 0)
|
||||
{
|
||||
pos = _searchText.indexIn(*text,pos);
|
||||
|
||||
if ( pos >= 0 )
|
||||
{
|
||||
|
||||
int startLine = 0;
|
||||
int endLine = 0;
|
||||
int startColumn = 0;
|
||||
int endColumn = 0;
|
||||
|
||||
|
||||
//kDebug() << "pos from " << pos << " to " << pos + _searchText.matchedLength();
|
||||
|
||||
getLineColumn(pos,startLine,startColumn);
|
||||
getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn);
|
||||
|
||||
//kDebug() << "start " << startLine << " / " << startColumn;
|
||||
//kDebug() << "end " << endLine << " / " << endColumn;
|
||||
|
||||
RegExpFilter::HotSpot* spot = newHotSpot(startLine,startColumn,
|
||||
endLine,endColumn);
|
||||
spot->setCapturedTexts(_searchText.capturedTexts());
|
||||
|
||||
addHotSpot( spot );
|
||||
pos += _searchText.matchedLength();
|
||||
|
||||
// if matchedLength == 0, the program will get stuck in an infinite loop
|
||||
Q_ASSERT( _searchText.matchedLength() > 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn,
|
||||
int endLine,int endColumn)
|
||||
{
|
||||
return new RegExpFilter::HotSpot(startLine,startColumn,
|
||||
endLine,endColumn);
|
||||
}
|
||||
RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine,
|
||||
int endColumn)
|
||||
{
|
||||
return new UrlFilter::HotSpot(startLine,startColumn,
|
||||
endLine,endColumn);
|
||||
}
|
||||
UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
|
||||
: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
|
||||
, _urlObject(new FilterObject(this))
|
||||
{
|
||||
setType(Link);
|
||||
}
|
||||
QString UrlFilter::HotSpot::tooltip() const
|
||||
{
|
||||
QString url = capturedTexts().first();
|
||||
|
||||
const UrlType kind = urlType();
|
||||
|
||||
if ( kind == StandardUrl )
|
||||
return QString();
|
||||
else if ( kind == Email )
|
||||
return QString();
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const
|
||||
{
|
||||
QString url = capturedTexts().first();
|
||||
|
||||
if ( FullUrlRegExp.exactMatch(url) )
|
||||
return StandardUrl;
|
||||
else if ( EmailAddressRegExp.exactMatch(url) )
|
||||
return Email;
|
||||
else
|
||||
return Unknown;
|
||||
}
|
||||
|
||||
void UrlFilter::HotSpot::activate(QObject* object)
|
||||
{
|
||||
QString url = capturedTexts().first();
|
||||
|
||||
const UrlType kind = urlType();
|
||||
|
||||
const QString& actionName = object ? object->objectName() : QString();
|
||||
|
||||
if ( actionName == "copy-action" )
|
||||
{
|
||||
//kDebug() << "Copying url to clipboard:" << url;
|
||||
|
||||
QApplication::clipboard()->setText(url);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !object || actionName == "open-action" )
|
||||
{
|
||||
if ( kind == StandardUrl )
|
||||
{
|
||||
// if the URL path does not include the protocol ( eg. "www.kde.org" ) then
|
||||
// prepend http:// ( eg. "www.kde.org" --> "http://www.kde.org" )
|
||||
if (!url.contains("://"))
|
||||
{
|
||||
url.prepend("http://");
|
||||
}
|
||||
}
|
||||
else if ( kind == Email )
|
||||
{
|
||||
url.prepend("mailto:");
|
||||
}
|
||||
|
||||
// new KRun(url,QApplication::activeWindow());
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Altering these regular expressions can have a major effect on the performance of the filters
|
||||
// used for finding URLs in the text, especially if they are very general and could match very long
|
||||
// pieces of text.
|
||||
// Please be careful when altering them.
|
||||
|
||||
//regexp matches:
|
||||
// full url:
|
||||
// protocolname:// or www. followed by anything other than whitespaces, <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, comma and dot
|
||||
const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
|
||||
// email address:
|
||||
// [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
|
||||
const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
|
||||
|
||||
// matches full url or email address
|
||||
const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
|
||||
EmailAddressRegExp.pattern()+')');
|
||||
|
||||
UrlFilter::UrlFilter()
|
||||
{
|
||||
setRegExp( CompleteUrlRegExp );
|
||||
}
|
||||
UrlFilter::HotSpot::~HotSpot()
|
||||
{
|
||||
delete _urlObject;
|
||||
}
|
||||
void FilterObject::activated()
|
||||
{
|
||||
_filter->activate(sender());
|
||||
}
|
||||
QList<QAction*> UrlFilter::HotSpot::actions()
|
||||
{
|
||||
QList<QAction*> list;
|
||||
|
||||
const UrlType kind = urlType();
|
||||
|
||||
QAction* openAction = new QAction(_urlObject);
|
||||
QAction* copyAction = new QAction(_urlObject);;
|
||||
|
||||
Q_ASSERT( kind == StandardUrl || kind == Email );
|
||||
|
||||
if ( kind == StandardUrl )
|
||||
{
|
||||
openAction->setText(("Open Link"));
|
||||
copyAction->setText(("Copy Link Address"));
|
||||
}
|
||||
else if ( kind == Email )
|
||||
{
|
||||
openAction->setText(("Send Email To..."));
|
||||
copyAction->setText(("Copy Email Address"));
|
||||
}
|
||||
|
||||
// object names are set here so that the hotspot performs the
|
||||
// correct action when activated() is called with the triggered
|
||||
// action passed as a parameter.
|
||||
openAction->setObjectName("open-action");
|
||||
copyAction->setObjectName("copy-action");
|
||||
|
||||
QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
|
||||
QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) );
|
||||
|
||||
list << openAction;
|
||||
list << copyAction;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
//#include "moc_Filter.cpp"
|
@ -0,0 +1,383 @@
|
||||
/*
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef FILTER_H
|
||||
#define FILTER_H
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QAction>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QRegExp>
|
||||
|
||||
// Local
|
||||
#include "Character.h"
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
/**
|
||||
* A filter processes blocks of text looking for certain patterns (such as URLs or keywords from a list)
|
||||
* and marks the areas which match the filter's patterns as 'hotspots'.
|
||||
*
|
||||
* Each hotspot has a type identifier associated with it ( such as a link or a highlighted section ),
|
||||
* and an action. When the user performs some activity such as a mouse-click in a hotspot area ( the exact
|
||||
* action will depend on what is displaying the block of text which the filter is processing ), the hotspot's
|
||||
* activate() method should be called. Depending on the type of hotspot this will trigger a suitable response.
|
||||
*
|
||||
* For example, if a hotspot represents a URL then a suitable action would be opening that URL in a web browser.
|
||||
* Hotspots may have more than one action, in which case the list of actions can be obtained using the
|
||||
* actions() method.
|
||||
*
|
||||
* Different subclasses of filter will return different types of hotspot.
|
||||
* Subclasses must reimplement the process() method to examine a block of text and identify sections of interest.
|
||||
* When processing the text they should create instances of Filter::HotSpot subclasses for sections of interest
|
||||
* and add them to the filter's list of hotspots using addHotSpot()
|
||||
*/
|
||||
class Filter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Represents an area of text which matched the pattern a particular filter has been looking for.
|
||||
*
|
||||
* Each hotspot has a type identifier associated with it ( such as a link or a highlighted section ),
|
||||
* and an action. When the user performs some activity such as a mouse-click in a hotspot area ( the exact
|
||||
* action will depend on what is displaying the block of text which the filter is processing ), the hotspot's
|
||||
* activate() method should be called. Depending on the type of hotspot this will trigger a suitable response.
|
||||
*
|
||||
* For example, if a hotspot represents a URL then a suitable action would be opening that URL in a web browser.
|
||||
* Hotspots may have more than one action, in which case the list of actions can be obtained using the
|
||||
* actions() method. These actions may then be displayed in a popup menu or toolbar for example.
|
||||
*/
|
||||
class HotSpot
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new hotspot which covers the area from (@p startLine,@p startColumn) to (@p endLine,@p endColumn)
|
||||
* in a block of text.
|
||||
*/
|
||||
HotSpot(int startLine , int startColumn , int endLine , int endColumn);
|
||||
virtual ~HotSpot();
|
||||
|
||||
enum Type
|
||||
{
|
||||
// the type of the hotspot is not specified
|
||||
NotSpecified,
|
||||
// this hotspot represents a clickable link
|
||||
Link,
|
||||
// this hotspot represents a marker
|
||||
Marker
|
||||
};
|
||||
|
||||
/** Returns the line when the hotspot area starts */
|
||||
int startLine() const;
|
||||
/** Returns the line where the hotspot area ends */
|
||||
int endLine() const;
|
||||
/** Returns the column on startLine() where the hotspot area starts */
|
||||
int startColumn() const;
|
||||
/** Returns the column on endLine() where the hotspot area ends */
|
||||
int endColumn() const;
|
||||
/**
|
||||
* Returns the type of the hotspot. This is usually used as a hint for views on how to represent
|
||||
* the hotspot graphically. eg. Link hotspots are typically underlined when the user mouses over them
|
||||
*/
|
||||
Type type() const;
|
||||
/**
|
||||
* Causes the an action associated with a hotspot to be triggered.
|
||||
*
|
||||
* @param object The object which caused the hotspot to be triggered. This is
|
||||
* typically null ( in which case the default action should be performed ) or
|
||||
* one of the objects from the actions() list. In which case the associated
|
||||
* action should be performed.
|
||||
*/
|
||||
virtual void activate(QObject* object = 0) = 0;
|
||||
/**
|
||||
* Returns a list of actions associated with the hotspot which can be used in a
|
||||
* menu or toolbar
|
||||
*/
|
||||
virtual QList<QAction*> actions();
|
||||
|
||||
/**
|
||||
* Returns the text of a tooltip to be shown when the mouse moves over the hotspot, or
|
||||
* an empty string if there is no tooltip associated with this hotspot.
|
||||
*
|
||||
* The default implementation returns an empty string.
|
||||
*/
|
||||
virtual QString tooltip() const;
|
||||
|
||||
protected:
|
||||
/** Sets the type of a hotspot. This should only be set once */
|
||||
void setType(Type type);
|
||||
|
||||
private:
|
||||
int _startLine;
|
||||
int _startColumn;
|
||||
int _endLine;
|
||||
int _endColumn;
|
||||
Type _type;
|
||||
|
||||
};
|
||||
|
||||
/** Constructs a new filter. */
|
||||
Filter();
|
||||
virtual ~Filter();
|
||||
|
||||
/** Causes the filter to process the block of text currently in its internal buffer */
|
||||
virtual void process() = 0;
|
||||
|
||||
/**
|
||||
* Empties the filters internal buffer and resets the line count back to 0.
|
||||
* All hotspots are deleted.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/** Adds a new line of text to the filter and increments the line count */
|
||||
//void addLine(const QString& string);
|
||||
|
||||
/** Returns the hotspot which covers the given @p line and @p column, or 0 if no hotspot covers that area */
|
||||
HotSpot* hotSpotAt(int line , int column) const;
|
||||
|
||||
/** Returns the list of hotspots identified by the filter */
|
||||
QList<HotSpot*> hotSpots() const;
|
||||
|
||||
/** Returns the list of hotspots identified by the filter which occur on a given line */
|
||||
QList<HotSpot*> hotSpotsAtLine(int line) const;
|
||||
|
||||
/**
|
||||
* TODO: Document me
|
||||
*/
|
||||
void setBuffer(const QString* buffer , const QList<int>* linePositions);
|
||||
|
||||
protected:
|
||||
/** Adds a new hotspot to the list */
|
||||
void addHotSpot(HotSpot*);
|
||||
/** Returns the internal buffer */
|
||||
const QString* buffer();
|
||||
/** Converts a character position within buffer() to a line and column */
|
||||
void getLineColumn(int position , int& startLine , int& startColumn);
|
||||
|
||||
private:
|
||||
QMultiHash<int,HotSpot*> _hotspots;
|
||||
QList<HotSpot*> _hotspotList;
|
||||
|
||||
const QList<int>* _linePositions;
|
||||
const QString* _buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* A filter which searches for sections of text matching a regular expression and creates a new RegExpFilter::HotSpot
|
||||
* instance for them.
|
||||
*
|
||||
* Subclasses can reimplement newHotSpot() to return custom hotspot types when matches for the regular expression
|
||||
* are found.
|
||||
*/
|
||||
class RegExpFilter : public Filter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Type of hotspot created by RegExpFilter. The capturedTexts() method can be used to find the text
|
||||
* matched by the filter's regular expression.
|
||||
*/
|
||||
class HotSpot : public Filter::HotSpot
|
||||
{
|
||||
public:
|
||||
HotSpot(int startLine, int startColumn, int endLine , int endColumn);
|
||||
virtual void activate(QObject* object = 0);
|
||||
|
||||
/** Sets the captured texts associated with this hotspot */
|
||||
void setCapturedTexts(const QStringList& texts);
|
||||
/** Returns the texts found by the filter when matching the filter's regular expression */
|
||||
QStringList capturedTexts() const;
|
||||
private:
|
||||
QStringList _capturedTexts;
|
||||
};
|
||||
|
||||
/** Constructs a new regular expression filter */
|
||||
RegExpFilter();
|
||||
|
||||
/**
|
||||
* Sets the regular expression which the filter searches for in blocks of text.
|
||||
*
|
||||
* Regular expressions which match the empty string are treated as not matching
|
||||
* anything.
|
||||
*/
|
||||
void setRegExp(const QRegExp& text);
|
||||
/** Returns the regular expression which the filter searches for in blocks of text */
|
||||
QRegExp regExp() const;
|
||||
|
||||
/**
|
||||
* Reimplemented to search the filter's text buffer for text matching regExp()
|
||||
*
|
||||
* If regexp matches the empty string, then process() will return immediately
|
||||
* without finding results.
|
||||
*/
|
||||
virtual void process();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Called when a match for the regular expression is encountered. Subclasses should reimplement this
|
||||
* to return custom hotspot types
|
||||
*/
|
||||
virtual RegExpFilter::HotSpot* newHotSpot(int startLine,int startColumn,
|
||||
int endLine,int endColumn);
|
||||
|
||||
private:
|
||||
QRegExp _searchText;
|
||||
};
|
||||
|
||||
class FilterObject;
|
||||
|
||||
/** A filter which matches URLs in blocks of text */
|
||||
class UrlFilter : public RegExpFilter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Hotspot type created by UrlFilter instances. The activate() method opens a web browser
|
||||
* at the given URL when called.
|
||||
*/
|
||||
class HotSpot : public RegExpFilter::HotSpot
|
||||
{
|
||||
public:
|
||||
HotSpot(int startLine,int startColumn,int endLine,int endColumn);
|
||||
virtual ~HotSpot();
|
||||
|
||||
virtual QList<QAction*> actions();
|
||||
|
||||
/**
|
||||
* Open a web browser at the current URL. The url itself can be determined using
|
||||
* the capturedTexts() method.
|
||||
*/
|
||||
virtual void activate(QObject* object = 0);
|
||||
|
||||
virtual QString tooltip() const;
|
||||
private:
|
||||
enum UrlType
|
||||
{
|
||||
StandardUrl,
|
||||
Email,
|
||||
Unknown
|
||||
};
|
||||
UrlType urlType() const;
|
||||
|
||||
FilterObject* _urlObject;
|
||||
};
|
||||
|
||||
UrlFilter();
|
||||
|
||||
protected:
|
||||
virtual RegExpFilter::HotSpot* newHotSpot(int,int,int,int);
|
||||
|
||||
private:
|
||||
|
||||
static const QRegExp FullUrlRegExp;
|
||||
static const QRegExp EmailAddressRegExp;
|
||||
|
||||
// combined OR of FullUrlRegExp and EmailAddressRegExp
|
||||
static const QRegExp CompleteUrlRegExp;
|
||||
};
|
||||
|
||||
class FilterObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FilterObject(Filter::HotSpot* filter) : _filter(filter) {}
|
||||
private slots:
|
||||
void activated();
|
||||
private:
|
||||
Filter::HotSpot* _filter;
|
||||
};
|
||||
|
||||
/**
|
||||
* A chain which allows a group of filters to be processed as one.
|
||||
* The chain owns the filters added to it and deletes them when the chain itself is destroyed.
|
||||
*
|
||||
* Use addFilter() to add a new filter to the chain.
|
||||
* When new text to be filtered arrives, use addLine() to add each additional
|
||||
* line of text which needs to be processed and then after adding the last line, use
|
||||
* process() to cause each filter in the chain to process the text.
|
||||
*
|
||||
* After processing a block of text, the reset() method can be used to set the filter chain's
|
||||
* internal cursor back to the first line.
|
||||
*
|
||||
* The hotSpotAt() method will return the first hotspot which covers a given position.
|
||||
*
|
||||
* The hotSpots() and hotSpotsAtLine() method return all of the hotspots in the text and on
|
||||
* a given line respectively.
|
||||
*/
|
||||
class FilterChain : protected QList<Filter*>
|
||||
{
|
||||
public:
|
||||
virtual ~FilterChain();
|
||||
|
||||
/** Adds a new filter to the chain. The chain will delete this filter when it is destroyed */
|
||||
void addFilter(Filter* filter);
|
||||
/** Removes a filter from the chain. The chain will no longer delete the filter when destroyed */
|
||||
void removeFilter(Filter* filter);
|
||||
/** Returns true if the chain contains @p filter */
|
||||
bool containsFilter(Filter* filter);
|
||||
/** Removes all filters from the chain */
|
||||
void clear();
|
||||
|
||||
/** Resets each filter in the chain */
|
||||
void reset();
|
||||
/**
|
||||
* Processes each filter in the chain
|
||||
*/
|
||||
void process();
|
||||
|
||||
/** Sets the buffer for each filter in the chain to process. */
|
||||
void setBuffer(const QString* buffer , const QList<int>* linePositions);
|
||||
|
||||
/** Returns the first hotspot which occurs at @p line, @p column or 0 if no hotspot was found */
|
||||
Filter::HotSpot* hotSpotAt(int line , int column) const;
|
||||
/** Returns a list of all the hotspots in all the chain's filters */
|
||||
QList<Filter::HotSpot*> hotSpots() const;
|
||||
/** Returns a list of all hotspots at the given line in all the chain's filters */
|
||||
QList<Filter::HotSpot> hotSpotsAtLine(int line) const;
|
||||
|
||||
};
|
||||
|
||||
/** A filter chain which processes character images from terminal displays */
|
||||
class TerminalImageFilterChain : public FilterChain
|
||||
{
|
||||
public:
|
||||
TerminalImageFilterChain();
|
||||
virtual ~TerminalImageFilterChain();
|
||||
|
||||
/**
|
||||
* Set the current terminal image to @p image.
|
||||
*
|
||||
* @param image The terminal image
|
||||
* @param lines The number of lines in the terminal image
|
||||
* @param columns The number of columns in the terminal image
|
||||
*/
|
||||
void setImage(const Character* const image , int lines , int columns,
|
||||
const QVector<LineProperty>& lineProperties);
|
||||
|
||||
private:
|
||||
QString* _buffer;
|
||||
QList<int>* _linePositions;
|
||||
};
|
||||
|
||||
}
|
||||
#endif //FILTER_H
|
@ -0,0 +1,698 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "History.h"
|
||||
|
||||
// System
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
// Reasonable line size
|
||||
#define LINE_SIZE 1024
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
/*
|
||||
An arbitrary long scroll.
|
||||
|
||||
One can modify the scroll only by adding either cells
|
||||
or newlines, but access it randomly.
|
||||
|
||||
The model is that of an arbitrary wide typewriter scroll
|
||||
in that the scroll is a serie of lines and each line is
|
||||
a serie of cells with no overwriting permitted.
|
||||
|
||||
The implementation provides arbitrary length and numbers
|
||||
of cells and line/column indexed read access to the scroll
|
||||
at constant costs.
|
||||
|
||||
KDE4: Can we use QTemporaryFile here, instead of KTempFile?
|
||||
|
||||
FIXME: some complain about the history buffer comsuming the
|
||||
memory of their machines. This problem is critical
|
||||
since the history does not behave gracefully in cases
|
||||
where the memory is used up completely.
|
||||
|
||||
I put in a workaround that should handle it problem
|
||||
now gracefully. I'm not satisfied with the solution.
|
||||
|
||||
FIXME: Terminating the history is not properly indicated
|
||||
in the menu. We should throw a signal.
|
||||
|
||||
FIXME: There is noticeable decrease in speed, also. Perhaps,
|
||||
there whole feature needs to be revisited therefore.
|
||||
Disadvantage of a more elaborated, say block-oriented
|
||||
scheme with wrap around would be it's complexity.
|
||||
*/
|
||||
|
||||
//FIXME: tempory replacement for tmpfile
|
||||
// this is here one for debugging purpose.
|
||||
|
||||
//#define tmpfile xTmpFile
|
||||
|
||||
// History File ///////////////////////////////////////////
|
||||
|
||||
/*
|
||||
A Row(X) data type which allows adding elements to the end.
|
||||
*/
|
||||
|
||||
HistoryFile::HistoryFile()
|
||||
: ion(-1),
|
||||
length(0),
|
||||
fileMap(0)
|
||||
{
|
||||
if (tmpFile.open())
|
||||
{
|
||||
tmpFile.setAutoRemove(true);
|
||||
ion = tmpFile.handle();
|
||||
}
|
||||
}
|
||||
|
||||
HistoryFile::~HistoryFile()
|
||||
{
|
||||
if (fileMap)
|
||||
unmap();
|
||||
}
|
||||
|
||||
//TODO: Mapping the entire file in will cause problems if the history file becomes exceedingly large,
|
||||
//(ie. larger than available memory). HistoryFile::map() should only map in sections of the file at a time,
|
||||
//to avoid this.
|
||||
void HistoryFile::map()
|
||||
{
|
||||
assert( fileMap == 0 );
|
||||
|
||||
fileMap = (char*)mmap( 0 , length , PROT_READ , MAP_PRIVATE , ion , 0 );
|
||||
|
||||
//if mmap'ing fails, fall back to the read-lseek combination
|
||||
if ( fileMap == MAP_FAILED )
|
||||
{
|
||||
readWriteBalance = 0;
|
||||
fileMap = 0;
|
||||
qDebug() << ": mmap'ing history failed. errno = " << errno;
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryFile::unmap()
|
||||
{
|
||||
int result = munmap( fileMap , length );
|
||||
assert( result == 0 );
|
||||
|
||||
fileMap = 0;
|
||||
}
|
||||
|
||||
bool HistoryFile::isMapped()
|
||||
{
|
||||
return (fileMap != 0);
|
||||
}
|
||||
|
||||
void HistoryFile::add(const unsigned char* bytes, int len)
|
||||
{
|
||||
if ( fileMap )
|
||||
unmap();
|
||||
|
||||
readWriteBalance++;
|
||||
|
||||
int rc = 0;
|
||||
|
||||
rc = lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryFile::add.seek"); return; }
|
||||
rc = write(ion,bytes,len); if (rc < 0) { perror("HistoryFile::add.write"); return; }
|
||||
length += rc;
|
||||
}
|
||||
|
||||
void HistoryFile::get(unsigned char* bytes, int len, int loc)
|
||||
{
|
||||
//count number of get() calls vs. number of add() calls.
|
||||
//If there are many more get() calls compared with add()
|
||||
//calls (decided by using MAP_THRESHOLD) then mmap the log
|
||||
//file to improve performance.
|
||||
readWriteBalance--;
|
||||
if ( !fileMap && readWriteBalance < MAP_THRESHOLD )
|
||||
map();
|
||||
|
||||
if ( fileMap )
|
||||
{
|
||||
for (int i=0;i<len;i++)
|
||||
bytes[i]=fileMap[loc+i];
|
||||
}
|
||||
else
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (loc < 0 || len < 0 || loc + len > length)
|
||||
fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc);
|
||||
rc = lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryFile::get.seek"); return; }
|
||||
rc = read(ion,bytes,len); if (rc < 0) { perror("HistoryFile::get.read"); return; }
|
||||
}
|
||||
}
|
||||
|
||||
int HistoryFile::len()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
// History Scroll abstract base class //////////////////////////////////////
|
||||
|
||||
|
||||
HistoryScroll::HistoryScroll(HistoryType* t)
|
||||
: m_histType(t)
|
||||
{
|
||||
}
|
||||
|
||||
HistoryScroll::~HistoryScroll()
|
||||
{
|
||||
delete m_histType;
|
||||
}
|
||||
|
||||
bool HistoryScroll::hasScroll()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// History Scroll File //////////////////////////////////////
|
||||
|
||||
/*
|
||||
The history scroll makes a Row(Row(Cell)) from
|
||||
two history buffers. The index buffer contains
|
||||
start of line positions which refere to the cells
|
||||
buffer.
|
||||
|
||||
Note that index[0] addresses the second line
|
||||
(line #1), while the first line (line #0) starts
|
||||
at 0 in cells.
|
||||
*/
|
||||
|
||||
HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
|
||||
: HistoryScroll(new HistoryTypeFile(logFileName)),
|
||||
m_logFileName(logFileName)
|
||||
{
|
||||
}
|
||||
|
||||
HistoryScrollFile::~HistoryScrollFile()
|
||||
{
|
||||
}
|
||||
|
||||
int HistoryScrollFile::getLines()
|
||||
{
|
||||
return index.len() / sizeof(int);
|
||||
}
|
||||
|
||||
int HistoryScrollFile::getLineLen(int lineno)
|
||||
{
|
||||
return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character);
|
||||
}
|
||||
|
||||
bool HistoryScrollFile::isWrappedLine(int lineno)
|
||||
{
|
||||
if (lineno>=0 && lineno <= getLines()) {
|
||||
unsigned char flag;
|
||||
lineflags.get((unsigned char*)&flag,sizeof(unsigned char),(lineno)*sizeof(unsigned char));
|
||||
return flag;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int HistoryScrollFile::startOfLine(int lineno)
|
||||
{
|
||||
if (lineno <= 0) return 0;
|
||||
if (lineno <= getLines())
|
||||
{
|
||||
|
||||
if (!index.isMapped())
|
||||
index.map();
|
||||
|
||||
int res;
|
||||
index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int));
|
||||
return res;
|
||||
}
|
||||
return cells.len();
|
||||
}
|
||||
|
||||
void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[])
|
||||
{
|
||||
cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character));
|
||||
}
|
||||
|
||||
void HistoryScrollFile::addCells(const Character text[], int count)
|
||||
{
|
||||
cells.add((unsigned char*)text,count*sizeof(Character));
|
||||
}
|
||||
|
||||
void HistoryScrollFile::addLine(bool previousWrapped)
|
||||
{
|
||||
if (index.isMapped())
|
||||
index.unmap();
|
||||
|
||||
int locn = cells.len();
|
||||
index.add((unsigned char*)&locn,sizeof(int));
|
||||
unsigned char flags = previousWrapped ? 0x01 : 0x00;
|
||||
lineflags.add((unsigned char*)&flags,sizeof(unsigned char));
|
||||
}
|
||||
|
||||
|
||||
// History Scroll Buffer //////////////////////////////////////
|
||||
HistoryScrollBuffer::HistoryScrollBuffer(unsigned int maxLineCount)
|
||||
: HistoryScroll(new HistoryTypeBuffer(maxLineCount))
|
||||
,_historyBuffer()
|
||||
,_maxLineCount(0)
|
||||
,_usedLines(0)
|
||||
,_head(0)
|
||||
{
|
||||
setMaxNbLines(maxLineCount);
|
||||
}
|
||||
|
||||
HistoryScrollBuffer::~HistoryScrollBuffer()
|
||||
{
|
||||
delete[] _historyBuffer;
|
||||
}
|
||||
|
||||
void HistoryScrollBuffer::addCellsVector(const QVector<Character>& cells)
|
||||
{
|
||||
_head++;
|
||||
if ( _usedLines < _maxLineCount )
|
||||
_usedLines++;
|
||||
|
||||
if ( _head >= _maxLineCount )
|
||||
{
|
||||
_head = 0;
|
||||
}
|
||||
|
||||
_historyBuffer[bufferIndex(_usedLines-1)] = cells;
|
||||
_wrappedLine[bufferIndex(_usedLines-1)] = false;
|
||||
}
|
||||
void HistoryScrollBuffer::addCells(const Character a[], int count)
|
||||
{
|
||||
HistoryLine newLine(count);
|
||||
qCopy(a,a+count,newLine.begin());
|
||||
|
||||
addCellsVector(newLine);
|
||||
}
|
||||
|
||||
void HistoryScrollBuffer::addLine(bool previousWrapped)
|
||||
{
|
||||
_wrappedLine[bufferIndex(_usedLines-1)] = previousWrapped;
|
||||
}
|
||||
|
||||
int HistoryScrollBuffer::getLines()
|
||||
{
|
||||
return _usedLines;
|
||||
}
|
||||
|
||||
int HistoryScrollBuffer::getLineLen(int lineNumber)
|
||||
{
|
||||
Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
|
||||
|
||||
if ( lineNumber < _usedLines )
|
||||
{
|
||||
return _historyBuffer[bufferIndex(lineNumber)].size();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool HistoryScrollBuffer::isWrappedLine(int lineNumber)
|
||||
{
|
||||
Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount );
|
||||
|
||||
if (lineNumber < _usedLines)
|
||||
{
|
||||
//kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
|
||||
return _wrappedLine[bufferIndex(lineNumber)];
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, Character* buffer)
|
||||
{
|
||||
if ( count == 0 ) return;
|
||||
|
||||
Q_ASSERT( lineNumber < _maxLineCount );
|
||||
|
||||
if (lineNumber >= _usedLines)
|
||||
{
|
||||
memset(buffer, 0, count * sizeof(Character));
|
||||
return;
|
||||
}
|
||||
|
||||
const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)];
|
||||
|
||||
//kDebug() << "startCol " << startColumn;
|
||||
//kDebug() << "line.size() " << line.size();
|
||||
//kDebug() << "count " << count;
|
||||
|
||||
Q_ASSERT( startColumn <= line.size() - count );
|
||||
|
||||
memcpy(buffer, line.constData() + startColumn , count * sizeof(Character));
|
||||
}
|
||||
|
||||
void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
|
||||
{
|
||||
HistoryLine* oldBuffer = _historyBuffer;
|
||||
HistoryLine* newBuffer = new HistoryLine[lineCount];
|
||||
|
||||
for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ )
|
||||
{
|
||||
newBuffer[i] = oldBuffer[bufferIndex(i)];
|
||||
}
|
||||
|
||||
_usedLines = qMin(_usedLines,(int)lineCount);
|
||||
_maxLineCount = lineCount;
|
||||
_head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1;
|
||||
|
||||
_historyBuffer = newBuffer;
|
||||
delete[] oldBuffer;
|
||||
|
||||
_wrappedLine.resize(lineCount);
|
||||
}
|
||||
|
||||
int HistoryScrollBuffer::bufferIndex(int lineNumber)
|
||||
{
|
||||
Q_ASSERT( lineNumber >= 0 );
|
||||
Q_ASSERT( lineNumber < _maxLineCount );
|
||||
Q_ASSERT( (_usedLines == _maxLineCount) || lineNumber <= _head );
|
||||
|
||||
if ( _usedLines == _maxLineCount )
|
||||
{
|
||||
return (_head+lineNumber+1) % _maxLineCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
return lineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// History Scroll None //////////////////////////////////////
|
||||
|
||||
HistoryScrollNone::HistoryScrollNone()
|
||||
: HistoryScroll(new HistoryTypeNone())
|
||||
{
|
||||
}
|
||||
|
||||
HistoryScrollNone::~HistoryScrollNone()
|
||||
{
|
||||
}
|
||||
|
||||
bool HistoryScrollNone::hasScroll()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int HistoryScrollNone::getLines()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HistoryScrollNone::getLineLen(int)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HistoryScrollNone::isWrappedLine(int /*lineno*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void HistoryScrollNone::getCells(int, int, int, Character [])
|
||||
{
|
||||
}
|
||||
|
||||
void HistoryScrollNone::addCells(const Character [], int)
|
||||
{
|
||||
}
|
||||
|
||||
void HistoryScrollNone::addLine(bool)
|
||||
{
|
||||
}
|
||||
|
||||
// History Scroll BlockArray //////////////////////////////////////
|
||||
|
||||
HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
|
||||
: HistoryScroll(new HistoryTypeBlockArray(size))
|
||||
{
|
||||
m_blockArray.setHistorySize(size); // nb. of lines.
|
||||
}
|
||||
|
||||
HistoryScrollBlockArray::~HistoryScrollBlockArray()
|
||||
{
|
||||
}
|
||||
|
||||
int HistoryScrollBlockArray::getLines()
|
||||
{
|
||||
return m_lineLengths.count();
|
||||
}
|
||||
|
||||
int HistoryScrollBlockArray::getLineLen(int lineno)
|
||||
{
|
||||
if ( m_lineLengths.contains(lineno) )
|
||||
return m_lineLengths[lineno];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void HistoryScrollBlockArray::getCells(int lineno, int colno,
|
||||
int count, Character res[])
|
||||
{
|
||||
if (!count) return;
|
||||
|
||||
const Block *b = m_blockArray.at(lineno);
|
||||
|
||||
if (!b) {
|
||||
memset(res, 0, count * sizeof(Character)); // still better than random data
|
||||
return;
|
||||
}
|
||||
|
||||
assert(((colno + count) * sizeof(Character)) < ENTRIES);
|
||||
memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character));
|
||||
}
|
||||
|
||||
void HistoryScrollBlockArray::addCells(const Character a[], int count)
|
||||
{
|
||||
Block *b = m_blockArray.lastBlock();
|
||||
|
||||
if (!b) return;
|
||||
|
||||
// put cells in block's data
|
||||
assert((count * sizeof(Character)) < ENTRIES);
|
||||
|
||||
memset(b->data, 0, ENTRIES);
|
||||
|
||||
memcpy(b->data, a, count * sizeof(Character));
|
||||
b->size = count * sizeof(Character);
|
||||
|
||||
size_t res = m_blockArray.newBlock();
|
||||
assert (res > 0);
|
||||
Q_UNUSED( res );
|
||||
|
||||
m_lineLengths.insert(m_blockArray.getCurrent(), count);
|
||||
}
|
||||
|
||||
void HistoryScrollBlockArray::addLine(bool)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// History Types
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
HistoryType::HistoryType()
|
||||
{
|
||||
}
|
||||
|
||||
HistoryType::~HistoryType()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
HistoryTypeNone::HistoryTypeNone()
|
||||
{
|
||||
}
|
||||
|
||||
bool HistoryTypeNone::isEnabled() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HistoryScroll* HistoryTypeNone::scroll(HistoryScroll *old) const
|
||||
{
|
||||
delete old;
|
||||
return new HistoryScrollNone();
|
||||
}
|
||||
|
||||
int HistoryTypeNone::maximumLineCount() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
|
||||
: m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
bool HistoryTypeBlockArray::isEnabled() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int HistoryTypeBlockArray::maximumLineCount() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
HistoryScroll* HistoryTypeBlockArray::scroll(HistoryScroll *old) const
|
||||
{
|
||||
delete old;
|
||||
return new HistoryScrollBlockArray(m_size);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
|
||||
: m_nbLines(nbLines)
|
||||
{
|
||||
}
|
||||
|
||||
bool HistoryTypeBuffer::isEnabled() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int HistoryTypeBuffer::maximumLineCount() const
|
||||
{
|
||||
return m_nbLines;
|
||||
}
|
||||
|
||||
HistoryScroll* HistoryTypeBuffer::scroll(HistoryScroll *old) const
|
||||
{
|
||||
if (old)
|
||||
{
|
||||
HistoryScrollBuffer *oldBuffer = dynamic_cast<HistoryScrollBuffer*>(old);
|
||||
if (oldBuffer)
|
||||
{
|
||||
oldBuffer->setMaxNbLines(m_nbLines);
|
||||
return oldBuffer;
|
||||
}
|
||||
|
||||
HistoryScroll *newScroll = new HistoryScrollBuffer(m_nbLines);
|
||||
int lines = old->getLines();
|
||||
int startLine = 0;
|
||||
if (lines > (int) m_nbLines)
|
||||
startLine = lines - m_nbLines;
|
||||
|
||||
Character line[LINE_SIZE];
|
||||
for(int i = startLine; i < lines; i++)
|
||||
{
|
||||
int size = old->getLineLen(i);
|
||||
if (size > LINE_SIZE)
|
||||
{
|
||||
Character *tmp_line = new Character[size];
|
||||
old->getCells(i, 0, size, tmp_line);
|
||||
newScroll->addCells(tmp_line, size);
|
||||
newScroll->addLine(old->isWrappedLine(i));
|
||||
delete [] tmp_line;
|
||||
}
|
||||
else
|
||||
{
|
||||
old->getCells(i, 0, size, line);
|
||||
newScroll->addCells(line, size);
|
||||
newScroll->addLine(old->isWrappedLine(i));
|
||||
}
|
||||
}
|
||||
delete old;
|
||||
return newScroll;
|
||||
}
|
||||
return new HistoryScrollBuffer(m_nbLines);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
|
||||
HistoryTypeFile::HistoryTypeFile(const QString& fileName)
|
||||
: m_fileName(fileName)
|
||||
{
|
||||
}
|
||||
|
||||
bool HistoryTypeFile::isEnabled() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString& HistoryTypeFile::getFileName() const
|
||||
{
|
||||
return m_fileName;
|
||||
}
|
||||
|
||||
HistoryScroll* HistoryTypeFile::scroll(HistoryScroll *old) const
|
||||
{
|
||||
if (dynamic_cast<HistoryFile *>(old))
|
||||
return old; // Unchanged.
|
||||
|
||||
HistoryScroll *newScroll = new HistoryScrollFile(m_fileName);
|
||||
|
||||
Character line[LINE_SIZE];
|
||||
int lines = (old != 0) ? old->getLines() : 0;
|
||||
for(int i = 0; i < lines; i++)
|
||||
{
|
||||
int size = old->getLineLen(i);
|
||||
if (size > LINE_SIZE)
|
||||
{
|
||||
Character *tmp_line = new Character[size];
|
||||
old->getCells(i, 0, size, tmp_line);
|
||||
newScroll->addCells(tmp_line, size);
|
||||
newScroll->addLine(old->isWrappedLine(i));
|
||||
delete [] tmp_line;
|
||||
}
|
||||
else
|
||||
{
|
||||
old->getCells(i, 0, size, line);
|
||||
newScroll->addCells(line, size);
|
||||
newScroll->addLine(old->isWrappedLine(i));
|
||||
}
|
||||
}
|
||||
|
||||
delete old;
|
||||
return newScroll;
|
||||
}
|
||||
|
||||
int HistoryTypeFile::maximumLineCount() const
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,344 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef TEHISTORY_H
|
||||
#define TEHISTORY_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QBitRef>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore>
|
||||
|
||||
// Konsole
|
||||
#include "BlockArray.h"
|
||||
#include "Character.h"
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
#if 1
|
||||
/*
|
||||
An extendable tmpfile(1) based buffer.
|
||||
*/
|
||||
|
||||
class HistoryFile
|
||||
{
|
||||
public:
|
||||
HistoryFile();
|
||||
virtual ~HistoryFile();
|
||||
|
||||
virtual void add(const unsigned char* bytes, int len);
|
||||
virtual void get(unsigned char* bytes, int len, int loc);
|
||||
virtual int len();
|
||||
|
||||
//mmaps the file in read-only mode
|
||||
void map();
|
||||
//un-mmaps the file
|
||||
void unmap();
|
||||
//returns true if the file is mmap'ed
|
||||
bool isMapped();
|
||||
|
||||
|
||||
private:
|
||||
int ion;
|
||||
int length;
|
||||
QTemporaryFile tmpFile;
|
||||
|
||||
//pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed
|
||||
char* fileMap;
|
||||
|
||||
//incremented whenver 'add' is called and decremented whenever
|
||||
//'get' is called.
|
||||
//this is used to detect when a large number of lines are being read and processed from the history
|
||||
//and automatically mmap the file for better performance (saves the overhead of many lseek-read calls).
|
||||
int readWriteBalance;
|
||||
|
||||
//when readWriteBalance goes below this threshold, the file will be mmap'ed automatically
|
||||
static const int MAP_THRESHOLD = -1000;
|
||||
};
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Abstract base class for file and buffer versions
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class HistoryType;
|
||||
|
||||
class HistoryScroll
|
||||
{
|
||||
public:
|
||||
HistoryScroll(HistoryType*);
|
||||
virtual ~HistoryScroll();
|
||||
|
||||
virtual bool hasScroll();
|
||||
|
||||
// access to history
|
||||
virtual int getLines() = 0;
|
||||
virtual int getLineLen(int lineno) = 0;
|
||||
virtual void getCells(int lineno, int colno, int count, Character res[]) = 0;
|
||||
virtual bool isWrappedLine(int lineno) = 0;
|
||||
|
||||
// backward compatibility (obsolete)
|
||||
Character getCell(int lineno, int colno) { Character res; getCells(lineno,colno,1,&res); return res; }
|
||||
|
||||
// adding lines.
|
||||
virtual void addCells(const Character a[], int count) = 0;
|
||||
// convenience method - this is virtual so that subclasses can take advantage
|
||||
// of QVector's implicit copying
|
||||
virtual void addCellsVector(const QVector<Character>& cells)
|
||||
{
|
||||
addCells(cells.data(),cells.size());
|
||||
}
|
||||
|
||||
virtual void addLine(bool previousWrapped=false) = 0;
|
||||
|
||||
//
|
||||
// FIXME: Passing around constant references to HistoryType instances
|
||||
// is very unsafe, because those references will no longer
|
||||
// be valid if the history scroll is deleted.
|
||||
//
|
||||
const HistoryType& getType() { return *m_histType; }
|
||||
|
||||
protected:
|
||||
HistoryType* m_histType;
|
||||
|
||||
};
|
||||
|
||||
#if 1
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// File-based history (e.g. file log, no limitation in length)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HistoryScrollFile : public HistoryScroll
|
||||
{
|
||||
public:
|
||||
HistoryScrollFile(const QString &logFileName);
|
||||
virtual ~HistoryScrollFile();
|
||||
|
||||
virtual int getLines();
|
||||
virtual int getLineLen(int lineno);
|
||||
virtual void getCells(int lineno, int colno, int count, Character res[]);
|
||||
virtual bool isWrappedLine(int lineno);
|
||||
|
||||
virtual void addCells(const Character a[], int count);
|
||||
virtual void addLine(bool previousWrapped=false);
|
||||
|
||||
private:
|
||||
int startOfLine(int lineno);
|
||||
|
||||
QString m_logFileName;
|
||||
HistoryFile index; // lines Row(int)
|
||||
HistoryFile cells; // text Row(Character)
|
||||
HistoryFile lineflags; // flags Row(unsigned char)
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Buffer-based history (limited to a fixed nb of lines)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class HistoryScrollBuffer : public HistoryScroll
|
||||
{
|
||||
public:
|
||||
typedef QVector<Character> HistoryLine;
|
||||
|
||||
HistoryScrollBuffer(unsigned int maxNbLines = 1000);
|
||||
virtual ~HistoryScrollBuffer();
|
||||
|
||||
virtual int getLines();
|
||||
virtual int getLineLen(int lineno);
|
||||
virtual void getCells(int lineno, int colno, int count, Character res[]);
|
||||
virtual bool isWrappedLine(int lineno);
|
||||
|
||||
virtual void addCells(const Character a[], int count);
|
||||
virtual void addCellsVector(const QVector<Character>& cells);
|
||||
virtual void addLine(bool previousWrapped=false);
|
||||
|
||||
void setMaxNbLines(unsigned int nbLines);
|
||||
unsigned int maxNbLines() { return _maxLineCount; }
|
||||
|
||||
|
||||
private:
|
||||
int bufferIndex(int lineNumber);
|
||||
|
||||
HistoryLine* _historyBuffer;
|
||||
QBitArray _wrappedLine;
|
||||
int _maxLineCount;
|
||||
int _usedLines;
|
||||
int _head;
|
||||
|
||||
//QVector<histline*> m_histBuffer;
|
||||
//QBitArray m_wrappedLine;
|
||||
//unsigned int m_maxNbLines;
|
||||
//unsigned int m_nbLines;
|
||||
//unsigned int m_arrayIndex;
|
||||
//bool m_buffFilled;
|
||||
};
|
||||
|
||||
/*class HistoryScrollBufferV2 : public HistoryScroll
|
||||
{
|
||||
public:
|
||||
virtual int getLines();
|
||||
virtual int getLineLen(int lineno);
|
||||
virtual void getCells(int lineno, int colno, int count, Character res[]);
|
||||
virtual bool isWrappedLine(int lineno);
|
||||
|
||||
virtual void addCells(const Character a[], int count);
|
||||
virtual void addCells(const QVector<Character>& cells);
|
||||
virtual void addLine(bool previousWrapped=false);
|
||||
|
||||
};*/
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Nothing-based history (no history :-)
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class HistoryScrollNone : public HistoryScroll
|
||||
{
|
||||
public:
|
||||
HistoryScrollNone();
|
||||
virtual ~HistoryScrollNone();
|
||||
|
||||
virtual bool hasScroll();
|
||||
|
||||
virtual int getLines();
|
||||
virtual int getLineLen(int lineno);
|
||||
virtual void getCells(int lineno, int colno, int count, Character res[]);
|
||||
virtual bool isWrappedLine(int lineno);
|
||||
|
||||
virtual void addCells(const Character a[], int count);
|
||||
virtual void addLine(bool previousWrapped=false);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// BlockArray-based history
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class HistoryScrollBlockArray : public HistoryScroll
|
||||
{
|
||||
public:
|
||||
HistoryScrollBlockArray(size_t size);
|
||||
virtual ~HistoryScrollBlockArray();
|
||||
|
||||
virtual int getLines();
|
||||
virtual int getLineLen(int lineno);
|
||||
virtual void getCells(int lineno, int colno, int count, Character res[]);
|
||||
virtual bool isWrappedLine(int lineno);
|
||||
|
||||
virtual void addCells(const Character a[], int count);
|
||||
virtual void addLine(bool previousWrapped=false);
|
||||
|
||||
protected:
|
||||
BlockArray m_blockArray;
|
||||
QHash<int,size_t> m_lineLengths;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// History type
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class HistoryType
|
||||
{
|
||||
public:
|
||||
HistoryType();
|
||||
virtual ~HistoryType();
|
||||
|
||||
/**
|
||||
* Returns true if the history is enabled ( can store lines of output )
|
||||
* or false otherwise.
|
||||
*/
|
||||
virtual bool isEnabled() const = 0;
|
||||
/**
|
||||
* Returns true if the history size is unlimited.
|
||||
*/
|
||||
bool isUnlimited() const { return maximumLineCount() == 0; }
|
||||
/**
|
||||
* Returns the maximum number of lines which this history type
|
||||
* can store or 0 if the history can store an unlimited number of lines.
|
||||
*/
|
||||
virtual int maximumLineCount() const = 0;
|
||||
|
||||
virtual HistoryScroll* scroll(HistoryScroll *) const = 0;
|
||||
};
|
||||
|
||||
class HistoryTypeNone : public HistoryType
|
||||
{
|
||||
public:
|
||||
HistoryTypeNone();
|
||||
|
||||
virtual bool isEnabled() const;
|
||||
virtual int maximumLineCount() const;
|
||||
|
||||
virtual HistoryScroll* scroll(HistoryScroll *) const;
|
||||
};
|
||||
|
||||
class HistoryTypeBlockArray : public HistoryType
|
||||
{
|
||||
public:
|
||||
HistoryTypeBlockArray(size_t size);
|
||||
|
||||
virtual bool isEnabled() const;
|
||||
virtual int maximumLineCount() const;
|
||||
|
||||
virtual HistoryScroll* scroll(HistoryScroll *) const;
|
||||
|
||||
protected:
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
#if 1
|
||||
class HistoryTypeFile : public HistoryType
|
||||
{
|
||||
public:
|
||||
HistoryTypeFile(const QString& fileName=QString());
|
||||
|
||||
virtual bool isEnabled() const;
|
||||
virtual const QString& getFileName() const;
|
||||
virtual int maximumLineCount() const;
|
||||
|
||||
virtual HistoryScroll* scroll(HistoryScroll *) const;
|
||||
|
||||
protected:
|
||||
QString m_fileName;
|
||||
};
|
||||
|
||||
|
||||
class HistoryTypeBuffer : public HistoryType
|
||||
{
|
||||
public:
|
||||
HistoryTypeBuffer(unsigned int nbLines);
|
||||
|
||||
virtual bool isEnabled() const;
|
||||
virtual int maximumLineCount() const;
|
||||
|
||||
virtual HistoryScroll* scroll(HistoryScroll *) const;
|
||||
|
||||
protected:
|
||||
unsigned int m_nbLines;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // TEHISTORY_H
|
@ -0,0 +1,903 @@
|
||||
/*
|
||||
This source file was part of Konsole, a terminal emulator.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "KeyboardTranslator.h"
|
||||
|
||||
// System
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QBuffer>
|
||||
//#include <KDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore>
|
||||
#include <QtGui>
|
||||
|
||||
// KDE
|
||||
//#include <KDebug>
|
||||
//#include <KLocale>
|
||||
//#include <KStandardDirs>
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
//this is for default REALLY fallback translator.
|
||||
|
||||
//const char* KeyboardTranslatorManager::defaultTranslatorText =
|
||||
//#include "DefaultTranslatorText.h"
|
||||
//;
|
||||
|
||||
//and this is default now translator - default.keytab from original Konsole
|
||||
const char* KeyboardTranslatorManager::defaultTranslatorText =
|
||||
#include "ExtendedDefaultTranslator.h"
|
||||
;
|
||||
|
||||
KeyboardTranslatorManager::KeyboardTranslatorManager()
|
||||
: _haveLoadedAll(false)
|
||||
{
|
||||
}
|
||||
KeyboardTranslatorManager::~KeyboardTranslatorManager()
|
||||
{
|
||||
qDeleteAll(_translators.values());
|
||||
}
|
||||
QString KeyboardTranslatorManager::findTranslatorPath(const QString& name)
|
||||
{
|
||||
return QString("kb-layouts/" + name + ".keytab");
|
||||
}
|
||||
void KeyboardTranslatorManager::findTranslators()
|
||||
{
|
||||
QDir dir("kb-layouts/");
|
||||
QStringList filters;
|
||||
filters << "*.keytab";
|
||||
dir.setNameFilters(filters);
|
||||
QStringList list = dir.entryList(filters); //(".keytab"); // = KGlobal::dirs()->findAllResources("data",
|
||||
// "konsole/*.keytab",
|
||||
// KStandardDirs::NoDuplicates);
|
||||
list = dir.entryList(filters);
|
||||
// add the name of each translator to the list and associated
|
||||
// the name with a null pointer to indicate that the translator
|
||||
// has not yet been loaded from disk
|
||||
QStringListIterator listIter(list);
|
||||
while (listIter.hasNext())
|
||||
{
|
||||
QString translatorPath = listIter.next();
|
||||
|
||||
QString name = QFileInfo(translatorPath).baseName();
|
||||
|
||||
if ( !_translators.contains(name) ) {
|
||||
_translators.insert(name,0);
|
||||
}
|
||||
}
|
||||
_haveLoadedAll = true;
|
||||
}
|
||||
|
||||
const KeyboardTranslator* KeyboardTranslatorManager::findTranslator(const QString& name)
|
||||
{
|
||||
if ( name.isEmpty() )
|
||||
return defaultTranslator();
|
||||
|
||||
//here was smth wrong in original Konsole source
|
||||
findTranslators();
|
||||
|
||||
if ( _translators.contains(name) && _translators[name] != 0 ) {
|
||||
return _translators[name];
|
||||
}
|
||||
|
||||
KeyboardTranslator* translator = loadTranslator(name);
|
||||
|
||||
if ( translator != 0 )
|
||||
_translators[name] = translator;
|
||||
else if ( !name.isEmpty() )
|
||||
qWarning() << "Unable to load translator" << name;
|
||||
|
||||
return translator;
|
||||
}
|
||||
|
||||
bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator* translator)
|
||||
{
|
||||
const QString path = ".keytab";// = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name()
|
||||
// +".keytab";
|
||||
|
||||
qDebug() << "Saving translator to" << path;
|
||||
|
||||
QFile destination(path);
|
||||
|
||||
if (!destination.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
qWarning() << "Unable to save keyboard translation:"
|
||||
<< destination.errorString();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
KeyboardTranslatorWriter writer(&destination);
|
||||
writer.writeHeader(translator->description());
|
||||
|
||||
QListIterator<KeyboardTranslator::Entry> iter(translator->entries());
|
||||
while ( iter.hasNext() )
|
||||
writer.writeEntry(iter.next());
|
||||
}
|
||||
|
||||
destination.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(const QString& name)
|
||||
{
|
||||
const QString& path = findTranslatorPath(name);
|
||||
|
||||
QFile source(path);
|
||||
|
||||
if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
return 0;
|
||||
|
||||
return loadTranslator(&source,name);
|
||||
}
|
||||
|
||||
const KeyboardTranslator* KeyboardTranslatorManager::defaultTranslator()
|
||||
{
|
||||
qDebug() << "Loading default translator from text";
|
||||
QBuffer textBuffer;
|
||||
textBuffer.setData(defaultTranslatorText,strlen(defaultTranslatorText));
|
||||
|
||||
if (!textBuffer.open(QIODevice::ReadOnly))
|
||||
return 0;
|
||||
|
||||
return loadTranslator(&textBuffer,"fallback");
|
||||
}
|
||||
|
||||
KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(QIODevice* source,const QString& name)
|
||||
{
|
||||
KeyboardTranslator* translator = new KeyboardTranslator(name);
|
||||
KeyboardTranslatorReader reader(source);
|
||||
translator->setDescription( reader.description() );
|
||||
|
||||
while ( reader.hasNextEntry() ) {
|
||||
translator->addEntry(reader.nextEntry());
|
||||
}
|
||||
|
||||
source->close();
|
||||
|
||||
if ( !reader.parseError() )
|
||||
{
|
||||
return translator;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete translator;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
KeyboardTranslatorWriter::KeyboardTranslatorWriter(QIODevice* destination)
|
||||
: _destination(destination)
|
||||
{
|
||||
Q_ASSERT( destination && destination->isWritable() );
|
||||
|
||||
_writer = new QTextStream(_destination);
|
||||
}
|
||||
KeyboardTranslatorWriter::~KeyboardTranslatorWriter()
|
||||
{
|
||||
delete _writer;
|
||||
}
|
||||
void KeyboardTranslatorWriter::writeHeader( const QString& description )
|
||||
{
|
||||
*_writer << "keyboard \"" << description << '\"' << '\n';
|
||||
}
|
||||
void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry& entry )
|
||||
{
|
||||
QString result;
|
||||
|
||||
if ( entry.command() != KeyboardTranslator::NoCommand )
|
||||
result = entry.resultToString();
|
||||
else
|
||||
result = '\"' + entry.resultToString() + '\"';
|
||||
|
||||
*_writer << "key " << entry.conditionToString() << " : " << result << '\n';
|
||||
}
|
||||
|
||||
|
||||
// each line of the keyboard translation file is one of:
|
||||
//
|
||||
// - keyboard "name"
|
||||
// - key KeySequence : "characters"
|
||||
// - key KeySequence : CommandName
|
||||
//
|
||||
// KeySequence begins with the name of the key ( taken from the Qt::Key enum )
|
||||
// and is followed by the keyboard modifiers and state flags ( with + or - in front
|
||||
// of each modifier or flag to indicate whether it is required ). All keyboard modifiers
|
||||
// and flags are optional, if a particular modifier or state is not specified it is
|
||||
// assumed not to be a part of the sequence. The key sequence may contain whitespace
|
||||
//
|
||||
// eg: "key Up+Shift : scrollLineUp"
|
||||
// "key Next-Shift : "\E[6~"
|
||||
//
|
||||
// (lines containing only whitespace are ignored, parseLine assumes that comments have
|
||||
// already been removed)
|
||||
//
|
||||
|
||||
KeyboardTranslatorReader::KeyboardTranslatorReader( QIODevice* source )
|
||||
: _source(source)
|
||||
, _hasNext(false)
|
||||
{
|
||||
// read input until we find the description
|
||||
while ( _description.isEmpty() && !source->atEnd() )
|
||||
{
|
||||
const QList<Token>& tokens = tokenize( QString(source->readLine()) );
|
||||
|
||||
if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword )
|
||||
{
|
||||
_description = (tokens[1].text.toUtf8());
|
||||
}
|
||||
}
|
||||
|
||||
readNext();
|
||||
}
|
||||
void KeyboardTranslatorReader::readNext()
|
||||
{
|
||||
// find next entry
|
||||
while ( !_source->atEnd() )
|
||||
{
|
||||
const QList<Token>& tokens = tokenize( QString(_source->readLine()) );
|
||||
if ( !tokens.isEmpty() && tokens.first().type == Token::KeyKeyword )
|
||||
{
|
||||
KeyboardTranslator::States flags = KeyboardTranslator::NoState;
|
||||
KeyboardTranslator::States flagMask = KeyboardTranslator::NoState;
|
||||
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
|
||||
Qt::KeyboardModifiers modifierMask = Qt::NoModifier;
|
||||
|
||||
int keyCode = Qt::Key_unknown;
|
||||
|
||||
decodeSequence(tokens[1].text.toLower(),
|
||||
keyCode,
|
||||
modifiers,
|
||||
modifierMask,
|
||||
flags,
|
||||
flagMask);
|
||||
|
||||
KeyboardTranslator::Command command = KeyboardTranslator::NoCommand;
|
||||
QByteArray text;
|
||||
|
||||
// get text or command
|
||||
if ( tokens[2].type == Token::OutputText )
|
||||
{
|
||||
text = tokens[2].text.toLocal8Bit();
|
||||
}
|
||||
else if ( tokens[2].type == Token::Command )
|
||||
{
|
||||
// identify command
|
||||
if (!parseAsCommand(tokens[2].text,command))
|
||||
qWarning() << "Command" << tokens[2].text << "not understood.";
|
||||
}
|
||||
|
||||
KeyboardTranslator::Entry newEntry;
|
||||
newEntry.setKeyCode( keyCode );
|
||||
newEntry.setState( flags );
|
||||
newEntry.setStateMask( flagMask );
|
||||
newEntry.setModifiers( modifiers );
|
||||
newEntry.setModifierMask( modifierMask );
|
||||
newEntry.setText( text );
|
||||
newEntry.setCommand( command );
|
||||
|
||||
_nextEntry = newEntry;
|
||||
|
||||
_hasNext = true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_hasNext = false;
|
||||
}
|
||||
|
||||
bool KeyboardTranslatorReader::parseAsCommand(const QString& text,KeyboardTranslator::Command& command)
|
||||
{
|
||||
if ( text.compare("erase",Qt::CaseInsensitive) == 0 )
|
||||
command = KeyboardTranslator::EraseCommand;
|
||||
else if ( text.compare("scrollpageup",Qt::CaseInsensitive) == 0 )
|
||||
command = KeyboardTranslator::ScrollPageUpCommand;
|
||||
else if ( text.compare("scrollpagedown",Qt::CaseInsensitive) == 0 )
|
||||
command = KeyboardTranslator::ScrollPageDownCommand;
|
||||
else if ( text.compare("scrolllineup",Qt::CaseInsensitive) == 0 )
|
||||
command = KeyboardTranslator::ScrollLineUpCommand;
|
||||
else if ( text.compare("scrolllinedown",Qt::CaseInsensitive) == 0 )
|
||||
command = KeyboardTranslator::ScrollLineDownCommand;
|
||||
else if ( text.compare("scrolllock",Qt::CaseInsensitive) == 0 )
|
||||
command = KeyboardTranslator::ScrollLockCommand;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyboardTranslatorReader::decodeSequence(const QString& text,
|
||||
int& keyCode,
|
||||
Qt::KeyboardModifiers& modifiers,
|
||||
Qt::KeyboardModifiers& modifierMask,
|
||||
KeyboardTranslator::States& flags,
|
||||
KeyboardTranslator::States& flagMask)
|
||||
{
|
||||
bool isWanted = true;
|
||||
bool endOfItem = false;
|
||||
QString buffer;
|
||||
|
||||
Qt::KeyboardModifiers tempModifiers = modifiers;
|
||||
Qt::KeyboardModifiers tempModifierMask = modifierMask;
|
||||
KeyboardTranslator::States tempFlags = flags;
|
||||
KeyboardTranslator::States tempFlagMask = flagMask;
|
||||
|
||||
for ( int i = 0 ; i < text.count() ; i++ )
|
||||
{
|
||||
const QChar& ch = text[i];
|
||||
bool isLastLetter = ( i == text.count()-1 );
|
||||
|
||||
endOfItem = true;
|
||||
if ( ch.isLetterOrNumber() )
|
||||
{
|
||||
endOfItem = false;
|
||||
buffer.append(ch);
|
||||
}
|
||||
|
||||
if ( (endOfItem || isLastLetter) && !buffer.isEmpty() )
|
||||
{
|
||||
Qt::KeyboardModifier itemModifier = Qt::NoModifier;
|
||||
int itemKeyCode = 0;
|
||||
KeyboardTranslator::State itemFlag = KeyboardTranslator::NoState;
|
||||
|
||||
if ( parseAsModifier(buffer,itemModifier) )
|
||||
{
|
||||
tempModifierMask |= itemModifier;
|
||||
|
||||
if ( isWanted )
|
||||
tempModifiers |= itemModifier;
|
||||
}
|
||||
else if ( parseAsStateFlag(buffer,itemFlag) )
|
||||
{
|
||||
tempFlagMask |= itemFlag;
|
||||
|
||||
if ( isWanted )
|
||||
tempFlags |= itemFlag;
|
||||
}
|
||||
else if ( parseAsKeyCode(buffer,itemKeyCode) )
|
||||
keyCode = itemKeyCode;
|
||||
else
|
||||
qDebug() << "Unable to parse key binding item:" << buffer;
|
||||
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
// check if this is a wanted / not-wanted flag and update the
|
||||
// state ready for the next item
|
||||
if ( ch == '+' )
|
||||
isWanted = true;
|
||||
else if ( ch == '-' )
|
||||
isWanted = false;
|
||||
}
|
||||
|
||||
modifiers = tempModifiers;
|
||||
modifierMask = tempModifierMask;
|
||||
flags = tempFlags;
|
||||
flagMask = tempFlagMask;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeyboardTranslatorReader::parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier)
|
||||
{
|
||||
if ( item == "shift" )
|
||||
modifier = Qt::ShiftModifier;
|
||||
else if ( item == "ctrl" || item == "control" )
|
||||
modifier = Qt::ControlModifier;
|
||||
else if ( item == "alt" )
|
||||
modifier = Qt::AltModifier;
|
||||
else if ( item == "meta" )
|
||||
modifier = Qt::MetaModifier;
|
||||
else if ( item == "keypad" )
|
||||
modifier = Qt::KeypadModifier;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool KeyboardTranslatorReader::parseAsStateFlag(const QString& item , KeyboardTranslator::State& flag)
|
||||
{
|
||||
if ( item == "appcukeys" )
|
||||
flag = KeyboardTranslator::CursorKeysState;
|
||||
else if ( item == "ansi" )
|
||||
flag = KeyboardTranslator::AnsiState;
|
||||
else if ( item == "newline" )
|
||||
flag = KeyboardTranslator::NewLineState;
|
||||
else if ( item == "appscreen" )
|
||||
flag = KeyboardTranslator::AlternateScreenState;
|
||||
else if ( item == "anymod" )
|
||||
flag = KeyboardTranslator::AnyModifierState;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool KeyboardTranslatorReader::parseAsKeyCode(const QString& item , int& keyCode)
|
||||
{
|
||||
QKeySequence sequence = QKeySequence::fromString(item);
|
||||
if ( !sequence.isEmpty() )
|
||||
{
|
||||
keyCode = sequence[0];
|
||||
|
||||
if ( sequence.count() > 1 )
|
||||
{
|
||||
qDebug() << "Unhandled key codes in sequence: " << item;
|
||||
}
|
||||
}
|
||||
// additional cases implemented for backwards compatibility with KDE 3
|
||||
else if ( item == "prior" )
|
||||
keyCode = Qt::Key_PageUp;
|
||||
else if ( item == "next" )
|
||||
keyCode = Qt::Key_PageDown;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString KeyboardTranslatorReader::description() const
|
||||
{
|
||||
return _description;
|
||||
}
|
||||
bool KeyboardTranslatorReader::hasNextEntry()
|
||||
{
|
||||
return _hasNext;
|
||||
}
|
||||
KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& condition ,
|
||||
const QString& result )
|
||||
{
|
||||
QString entryString("keyboard \"temporary\"\nkey ");
|
||||
entryString.append(condition);
|
||||
entryString.append(" : ");
|
||||
|
||||
// if 'result' is the name of a command then the entry result will be that command,
|
||||
// otherwise the result will be treated as a string to echo when the key sequence
|
||||
// specified by 'condition' is pressed
|
||||
KeyboardTranslator::Command command;
|
||||
if (parseAsCommand(result,command))
|
||||
entryString.append(result);
|
||||
else
|
||||
entryString.append('\"' + result + '\"');
|
||||
|
||||
QByteArray array = entryString.toUtf8();
|
||||
|
||||
KeyboardTranslator::Entry entry;
|
||||
|
||||
QBuffer buffer(&array);
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
KeyboardTranslatorReader reader(&buffer);
|
||||
|
||||
if ( reader.hasNextEntry() )
|
||||
entry = reader.nextEntry();
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry()
|
||||
{
|
||||
Q_ASSERT( _hasNext );
|
||||
|
||||
|
||||
KeyboardTranslator::Entry entry = _nextEntry;
|
||||
|
||||
readNext();
|
||||
|
||||
return entry;
|
||||
}
|
||||
bool KeyboardTranslatorReader::parseError()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
QList<KeyboardTranslatorReader::Token> KeyboardTranslatorReader::tokenize(const QString& line)
|
||||
{
|
||||
QString text = line.simplified();
|
||||
|
||||
// comment line: # comment
|
||||
static QRegExp comment("\\#.*");
|
||||
// title line: keyboard "title"
|
||||
static QRegExp title("keyboard\\s+\"(.*)\"");
|
||||
// key line: key KeySequence : "output"
|
||||
// key line: key KeySequence : command
|
||||
static QRegExp key("key\\s+([\\w\\+\\s\\-]+)\\s*:\\s*(\"(.*)\"|\\w+)");
|
||||
|
||||
QList<Token> list;
|
||||
|
||||
if ( text.isEmpty() || comment.exactMatch(text) )
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
if ( title.exactMatch(text) )
|
||||
{
|
||||
Token titleToken = { Token::TitleKeyword , QString() };
|
||||
Token textToken = { Token::TitleText , title.capturedTexts()[1] };
|
||||
|
||||
list << titleToken << textToken;
|
||||
}
|
||||
else if ( key.exactMatch(text) )
|
||||
{
|
||||
Token keyToken = { Token::KeyKeyword , QString() };
|
||||
Token sequenceToken = { Token::KeySequence , key.capturedTexts()[1].remove(' ') };
|
||||
|
||||
list << keyToken << sequenceToken;
|
||||
|
||||
if ( key.capturedTexts()[3].isEmpty() )
|
||||
{
|
||||
// capturedTexts()[2] is a command
|
||||
Token commandToken = { Token::Command , key.capturedTexts()[2] };
|
||||
list << commandToken;
|
||||
}
|
||||
else
|
||||
{
|
||||
// capturedTexts()[3] is the output string
|
||||
Token outputToken = { Token::OutputText , key.capturedTexts()[3] };
|
||||
list << outputToken;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Line in keyboard translator file could not be understood:" << text;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
QList<QString> KeyboardTranslatorManager::allTranslators()
|
||||
{
|
||||
if ( !_haveLoadedAll )
|
||||
{
|
||||
findTranslators();
|
||||
}
|
||||
|
||||
return _translators.keys();
|
||||
}
|
||||
|
||||
KeyboardTranslator::Entry::Entry()
|
||||
: _keyCode(0)
|
||||
, _modifiers(Qt::NoModifier)
|
||||
, _modifierMask(Qt::NoModifier)
|
||||
, _state(NoState)
|
||||
, _stateMask(NoState)
|
||||
, _command(NoCommand)
|
||||
{
|
||||
}
|
||||
|
||||
bool KeyboardTranslator::Entry::operator==(const Entry& rhs) const
|
||||
{
|
||||
return _keyCode == rhs._keyCode &&
|
||||
_modifiers == rhs._modifiers &&
|
||||
_modifierMask == rhs._modifierMask &&
|
||||
_state == rhs._state &&
|
||||
_stateMask == rhs._stateMask &&
|
||||
_command == rhs._command &&
|
||||
_text == rhs._text;
|
||||
}
|
||||
|
||||
bool KeyboardTranslator::Entry::matches(int keyCode ,
|
||||
Qt::KeyboardModifiers modifiers,
|
||||
States state) const
|
||||
{
|
||||
if ( _keyCode != keyCode )
|
||||
return false;
|
||||
|
||||
if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) )
|
||||
return false;
|
||||
|
||||
// if modifiers is non-zero, the 'any modifier' state is implicit
|
||||
if ( modifiers != 0 )
|
||||
state |= AnyModifierState;
|
||||
|
||||
if ( (state & _stateMask) != (_state & _stateMask) )
|
||||
return false;
|
||||
|
||||
// special handling for the 'Any Modifier' state, which checks for the presence of
|
||||
// any or no modifiers. In this context, the 'keypad' modifier does not count.
|
||||
bool anyModifiersSet = modifiers != 0 && modifiers != Qt::KeypadModifier;
|
||||
if ( _stateMask & KeyboardTranslator::AnyModifierState )
|
||||
{
|
||||
// test fails if any modifier is required but none are set
|
||||
if ( (_state & KeyboardTranslator::AnyModifierState) && !anyModifiersSet )
|
||||
return false;
|
||||
|
||||
// test fails if no modifier is allowed but one or more are set
|
||||
if ( !(_state & KeyboardTranslator::AnyModifierState) && anyModifiersSet )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
|
||||
{
|
||||
QByteArray result(text(expandWildCards,modifiers));
|
||||
|
||||
for ( int i = 0 ; i < result.count() ; i++ )
|
||||
{
|
||||
char ch = result[i];
|
||||
char replacement = 0;
|
||||
|
||||
switch ( ch )
|
||||
{
|
||||
case 27 : replacement = 'E'; break;
|
||||
case 8 : replacement = 'b'; break;
|
||||
case 12 : replacement = 'f'; break;
|
||||
case 9 : replacement = 't'; break;
|
||||
case 13 : replacement = 'r'; break;
|
||||
case 10 : replacement = 'n'; break;
|
||||
default:
|
||||
// any character which is not printable is replaced by an equivalent
|
||||
// \xhh escape sequence (where 'hh' are the corresponding hex digits)
|
||||
if ( !QChar(ch).isPrint() )
|
||||
replacement = 'x';
|
||||
}
|
||||
|
||||
if ( replacement == 'x' )
|
||||
{
|
||||
result.replace(i,1,"\\x"+QByteArray(1,ch).toInt(0, 16));
|
||||
} else if ( replacement != 0 )
|
||||
{
|
||||
result.remove(i,1);
|
||||
result.insert(i,'\\');
|
||||
result.insert(i+1,replacement);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
QByteArray KeyboardTranslator::Entry::unescape(const QByteArray& input) const
|
||||
{
|
||||
QByteArray result(input);
|
||||
|
||||
for ( int i = 0 ; i < result.count()-1 ; i++ )
|
||||
{
|
||||
|
||||
QByteRef ch = result[i];
|
||||
if ( ch == '\\' )
|
||||
{
|
||||
char replacement[2] = {0,0};
|
||||
int charsToRemove = 2;
|
||||
bool escapedChar = true;
|
||||
|
||||
switch ( result[i+1] )
|
||||
{
|
||||
case 'E' : replacement[0] = 27; break;
|
||||
case 'b' : replacement[0] = 8 ; break;
|
||||
case 'f' : replacement[0] = 12; break;
|
||||
case 't' : replacement[0] = 9 ; break;
|
||||
case 'r' : replacement[0] = 13; break;
|
||||
case 'n' : replacement[0] = 10; break;
|
||||
case 'x' :
|
||||
{
|
||||
// format is \xh or \xhh where 'h' is a hexadecimal
|
||||
// digit from 0-9 or A-F which should be replaced
|
||||
// with the corresponding character value
|
||||
char hexDigits[3] = {0};
|
||||
|
||||
if ( (i < result.count()-2) && isxdigit(result[i+2]) )
|
||||
hexDigits[0] = result[i+2];
|
||||
if ( (i < result.count()-3) && isxdigit(result[i+3]) )
|
||||
hexDigits[1] = result[i+3];
|
||||
|
||||
int charValue = 0;
|
||||
sscanf(hexDigits,"%x",&charValue);
|
||||
|
||||
replacement[0] = (char)charValue;
|
||||
|
||||
charsToRemove = 2 + strlen(hexDigits);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
escapedChar = false;
|
||||
}
|
||||
|
||||
if ( escapedChar )
|
||||
result.replace(i,charsToRemove,replacement);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void KeyboardTranslator::Entry::insertModifier( QString& item , int modifier ) const
|
||||
{
|
||||
if ( !(modifier & _modifierMask) )
|
||||
return;
|
||||
|
||||
if ( modifier & _modifiers )
|
||||
item += '+';
|
||||
else
|
||||
item += '-';
|
||||
|
||||
if ( modifier == Qt::ShiftModifier )
|
||||
item += "Shift";
|
||||
else if ( modifier == Qt::ControlModifier )
|
||||
item += "Ctrl";
|
||||
else if ( modifier == Qt::AltModifier )
|
||||
item += "Alt";
|
||||
else if ( modifier == Qt::MetaModifier )
|
||||
item += "Meta";
|
||||
else if ( modifier == Qt::KeypadModifier )
|
||||
item += "KeyPad";
|
||||
}
|
||||
void KeyboardTranslator::Entry::insertState( QString& item , int state ) const
|
||||
{
|
||||
if ( !(state & _stateMask) )
|
||||
return;
|
||||
|
||||
if ( state & _state )
|
||||
item += '+' ;
|
||||
else
|
||||
item += '-' ;
|
||||
|
||||
if ( state == KeyboardTranslator::AlternateScreenState )
|
||||
item += "AppScreen";
|
||||
else if ( state == KeyboardTranslator::NewLineState )
|
||||
item += "NewLine";
|
||||
else if ( state == KeyboardTranslator::AnsiState )
|
||||
item += "Ansi";
|
||||
else if ( state == KeyboardTranslator::CursorKeysState )
|
||||
item += "AppCuKeys";
|
||||
else if ( state == KeyboardTranslator::AnyModifierState )
|
||||
item += "AnyMod";
|
||||
}
|
||||
QString KeyboardTranslator::Entry::resultToString(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
|
||||
{
|
||||
if ( !_text.isEmpty() )
|
||||
return escapedText(expandWildCards,modifiers);
|
||||
else if ( _command == EraseCommand )
|
||||
return "Erase";
|
||||
else if ( _command == ScrollPageUpCommand )
|
||||
return "ScrollPageUp";
|
||||
else if ( _command == ScrollPageDownCommand )
|
||||
return "ScrollPageDown";
|
||||
else if ( _command == ScrollLineUpCommand )
|
||||
return "ScrollLineUp";
|
||||
else if ( _command == ScrollLineDownCommand )
|
||||
return "ScrollLineDown";
|
||||
else if ( _command == ScrollLockCommand )
|
||||
return "ScrollLock";
|
||||
|
||||
return QString();
|
||||
}
|
||||
QString KeyboardTranslator::Entry::conditionToString() const
|
||||
{
|
||||
QString result = QKeySequence(_keyCode).toString();
|
||||
|
||||
// add modifiers
|
||||
insertModifier( result , Qt::ShiftModifier );
|
||||
insertModifier( result , Qt::ControlModifier );
|
||||
insertModifier( result , Qt::AltModifier );
|
||||
insertModifier( result , Qt::MetaModifier );
|
||||
|
||||
// add states
|
||||
insertState( result , KeyboardTranslator::AlternateScreenState );
|
||||
insertState( result , KeyboardTranslator::NewLineState );
|
||||
insertState( result , KeyboardTranslator::AnsiState );
|
||||
insertState( result , KeyboardTranslator::CursorKeysState );
|
||||
insertState( result , KeyboardTranslator::AnyModifierState );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
KeyboardTranslator::KeyboardTranslator(const QString& name)
|
||||
: _name(name)
|
||||
{
|
||||
}
|
||||
|
||||
void KeyboardTranslator::setDescription(const QString& description)
|
||||
{
|
||||
_description = description;
|
||||
}
|
||||
QString KeyboardTranslator::description() const
|
||||
{
|
||||
return _description;
|
||||
}
|
||||
void KeyboardTranslator::setName(const QString& name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
QString KeyboardTranslator::name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
QList<KeyboardTranslator::Entry> KeyboardTranslator::entries() const
|
||||
{
|
||||
return _entries.values();
|
||||
}
|
||||
|
||||
void KeyboardTranslator::addEntry(const Entry& entry)
|
||||
{
|
||||
const int keyCode = entry.keyCode();
|
||||
_entries.insertMulti(keyCode,entry);
|
||||
}
|
||||
void KeyboardTranslator::replaceEntry(const Entry& existing , const Entry& replacement)
|
||||
{
|
||||
if ( !existing.isNull() )
|
||||
_entries.remove(existing.keyCode());
|
||||
_entries.insertMulti(replacement.keyCode(),replacement);
|
||||
}
|
||||
void KeyboardTranslator::removeEntry(const Entry& entry)
|
||||
{
|
||||
_entries.remove(entry.keyCode());
|
||||
}
|
||||
KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const
|
||||
{
|
||||
if ( _entries.contains(keyCode) )
|
||||
{
|
||||
QList<Entry> entriesForKey = _entries.values(keyCode);
|
||||
|
||||
QListIterator<Entry> iter(entriesForKey);
|
||||
|
||||
while (iter.hasNext())
|
||||
{
|
||||
const Entry& next = iter.next();
|
||||
if ( next.matches(keyCode,modifiers,state) )
|
||||
return next;
|
||||
}
|
||||
|
||||
return Entry(); // entry not found
|
||||
}
|
||||
else
|
||||
{
|
||||
return Entry();
|
||||
}
|
||||
|
||||
}
|
||||
void KeyboardTranslatorManager::addTranslator(KeyboardTranslator* translator)
|
||||
{
|
||||
_translators.insert(translator->name(),translator);
|
||||
|
||||
if ( !saveTranslator(translator) )
|
||||
qWarning() << "Unable to save translator" << translator->name()
|
||||
<< "to disk.";
|
||||
}
|
||||
bool KeyboardTranslatorManager::deleteTranslator(const QString& name)
|
||||
{
|
||||
Q_ASSERT( _translators.contains(name) );
|
||||
|
||||
// locate and delete
|
||||
QString path = findTranslatorPath(name);
|
||||
if ( QFile::remove(path) )
|
||||
{
|
||||
_translators.remove(name);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Failed to remove translator - " << path;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager )
|
||||
KeyboardTranslatorManager* KeyboardTranslatorManager::instance()
|
||||
{
|
||||
return theKeyboardTranslatorManager;
|
||||
}
|
@ -0,0 +1,657 @@
|
||||
/*
|
||||
This source file is part of Konsole, a terminal emulator.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef KEYBOARDTRANSLATOR_H
|
||||
#define KEYBOARDTRANSLATOR_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QList>
|
||||
#include <QtGui/QKeySequence>
|
||||
#include <QtCore/QMetaType>
|
||||
#include <QtCore/QVarLengthArray>
|
||||
#include <QtCore>
|
||||
|
||||
typedef void (*CleanUpFunction)();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Helper class for K_GLOBAL_STATIC to clean up the object on library unload or application
|
||||
* shutdown.
|
||||
*/
|
||||
class CleanUpGlobalStatic
|
||||
{
|
||||
public:
|
||||
CleanUpFunction func;
|
||||
|
||||
inline ~CleanUpGlobalStatic() { func(); }
|
||||
};
|
||||
|
||||
|
||||
//these directives are taken from the heart of kdecore
|
||||
|
||||
# define K_GLOBAL_STATIC_STRUCT_NAME(NAME)
|
||||
|
||||
#if QT_VERSION < 0x040400
|
||||
# define Q_BASIC_ATOMIC_INITIALIZER Q_ATOMIC_INIT
|
||||
# define testAndSetOrdered testAndSet
|
||||
#endif
|
||||
|
||||
#define K_GLOBAL_STATIC(TYPE, NAME) K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
|
||||
|
||||
#define K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
|
||||
static QBasicAtomicPointer<TYPE > _k_static_##NAME = Q_BASIC_ATOMIC_INITIALIZER(0); \
|
||||
static bool _k_static_##NAME##_destroyed; \
|
||||
static struct K_GLOBAL_STATIC_STRUCT_NAME(NAME) \
|
||||
{ \
|
||||
bool isDestroyed() \
|
||||
{ \
|
||||
return _k_static_##NAME##_destroyed; \
|
||||
} \
|
||||
inline operator TYPE*() \
|
||||
{ \
|
||||
return operator->(); \
|
||||
} \
|
||||
inline TYPE *operator->() \
|
||||
{ \
|
||||
if (!_k_static_##NAME) { \
|
||||
if (isDestroyed()) { \
|
||||
qFatal("Fatal Error: Accessed global static '%s *%s()' after destruction. " \
|
||||
"Defined at %s:%d", #TYPE, #NAME, __FILE__, __LINE__); \
|
||||
} \
|
||||
TYPE *x = new TYPE ARGS; \
|
||||
if (!_k_static_##NAME.testAndSetOrdered(0, x) \
|
||||
&& _k_static_##NAME != x ) { \
|
||||
delete x; \
|
||||
} else { \
|
||||
static CleanUpGlobalStatic cleanUpObject = { destroy }; \
|
||||
} \
|
||||
} \
|
||||
return _k_static_##NAME; \
|
||||
} \
|
||||
inline TYPE &operator*() \
|
||||
{ \
|
||||
return *operator->(); \
|
||||
} \
|
||||
static void destroy() \
|
||||
{ \
|
||||
_k_static_##NAME##_destroyed = true; \
|
||||
TYPE *x = _k_static_##NAME; \
|
||||
_k_static_##NAME = 0; \
|
||||
delete x; \
|
||||
} \
|
||||
} NAME;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QIODevice;
|
||||
class QTextStream;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
/**
|
||||
* A convertor which maps between key sequences pressed by the user and the
|
||||
* character strings which should be sent to the terminal and commands
|
||||
* which should be invoked when those character sequences are pressed.
|
||||
*
|
||||
* Konsole supports multiple keyboard translators, allowing the user to
|
||||
* specify the character sequences which are sent to the terminal
|
||||
* when particular key sequences are pressed.
|
||||
*
|
||||
* A key sequence is defined as a key code, associated keyboard modifiers
|
||||
* (Shift,Ctrl,Alt,Meta etc.) and state flags which indicate the state
|
||||
* which the terminal must be in for the key sequence to apply.
|
||||
*/
|
||||
class KeyboardTranslator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The meaning of a particular key sequence may depend upon the state which
|
||||
* the terminal emulation is in. Therefore findEntry() may return a different
|
||||
* Entry depending upon the state flags supplied.
|
||||
*
|
||||
* This enum describes the states which may be associated with with a particular
|
||||
* entry in the keyboard translation entry.
|
||||
*/
|
||||
enum State
|
||||
{
|
||||
/** Indicates that no special state is active */
|
||||
NoState = 0,
|
||||
/**
|
||||
* TODO More documentation
|
||||
*/
|
||||
NewLineState = 1,
|
||||
/**
|
||||
* Indicates that the terminal is in 'Ansi' mode.
|
||||
* TODO: More documentation
|
||||
*/
|
||||
AnsiState = 2,
|
||||
/**
|
||||
* TODO More documentation
|
||||
*/
|
||||
CursorKeysState = 4,
|
||||
/**
|
||||
* Indicates that the alternate screen ( typically used by interactive programs
|
||||
* such as screen or vim ) is active
|
||||
*/
|
||||
AlternateScreenState = 8,
|
||||
/** Indicates that any of the modifier keys is active. */
|
||||
AnyModifierState = 16
|
||||
};
|
||||
Q_DECLARE_FLAGS(States,State)
|
||||
|
||||
/**
|
||||
* This enum describes commands which are associated with particular key sequences.
|
||||
*/
|
||||
enum Command
|
||||
{
|
||||
/** Indicates that no command is associated with this command sequence */
|
||||
NoCommand = 0,
|
||||
/** TODO Document me */
|
||||
SendCommand = 1,
|
||||
/** Scroll the terminal display up one page */
|
||||
ScrollPageUpCommand = 2,
|
||||
/** Scroll the terminal display down one page */
|
||||
ScrollPageDownCommand = 4,
|
||||
/** Scroll the terminal display up one line */
|
||||
ScrollLineUpCommand = 8,
|
||||
/** Scroll the terminal display down one line */
|
||||
ScrollLineDownCommand = 16,
|
||||
/** Toggles scroll lock mode */
|
||||
ScrollLockCommand = 32,
|
||||
/** Echos the operating system specific erase character. */
|
||||
EraseCommand = 64
|
||||
};
|
||||
Q_DECLARE_FLAGS(Commands,Command)
|
||||
|
||||
/**
|
||||
* Represents an association between a key sequence pressed by the user
|
||||
* and the character sequence and commands associated with it for a particular
|
||||
* KeyboardTranslator.
|
||||
*/
|
||||
class Entry
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new entry for a keyboard translator.
|
||||
*/
|
||||
Entry();
|
||||
|
||||
/**
|
||||
* Returns true if this entry is null.
|
||||
* This is true for newly constructed entries which have no properties set.
|
||||
*/
|
||||
bool isNull() const;
|
||||
|
||||
/** Returns the commands associated with this entry */
|
||||
Command command() const;
|
||||
/** Sets the command associated with this entry. */
|
||||
void setCommand(Command command);
|
||||
|
||||
/**
|
||||
* Returns the character sequence associated with this entry, optionally replacing
|
||||
* wildcard '*' characters with numbers to indicate the keyboard modifiers being pressed.
|
||||
*
|
||||
* TODO: The numbers used to replace '*' characters are taken from the Konsole/KDE 3 code.
|
||||
* Document them.
|
||||
*
|
||||
* @param expandWildCards Specifies whether wild cards (occurrences of the '*' character) in
|
||||
* the entry should be replaced with a number to indicate the modifier keys being pressed.
|
||||
*
|
||||
* @param modifiers The keyboard modifiers being pressed.
|
||||
*/
|
||||
QByteArray text(bool expandWildCards = false,
|
||||
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
|
||||
|
||||
/** Sets the character sequence associated with this entry */
|
||||
void setText(const QByteArray& text);
|
||||
|
||||
/**
|
||||
* Returns the character sequence associated with this entry,
|
||||
* with any non-printable characters replaced with escape sequences.
|
||||
*
|
||||
* eg. \\E for Escape, \\t for tab, \\n for new line.
|
||||
*
|
||||
* @param expandWildCards See text()
|
||||
* @param modifiers See text()
|
||||
*/
|
||||
QByteArray escapedText(bool expandWildCards = false,
|
||||
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
|
||||
|
||||
/** Returns the character code ( from the Qt::Key enum ) associated with this entry */
|
||||
int keyCode() const;
|
||||
/** Sets the character code associated with this entry */
|
||||
void setKeyCode(int keyCode);
|
||||
|
||||
/**
|
||||
* Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry.
|
||||
* If a modifier is set in modifierMask() but not in modifiers(), this means that the entry
|
||||
* only matches when that modifier is NOT pressed.
|
||||
*
|
||||
* If a modifier is not set in modifierMask() then the entry matches whether the modifier
|
||||
* is pressed or not.
|
||||
*/
|
||||
Qt::KeyboardModifiers modifiers() const;
|
||||
|
||||
/** Returns the keyboard modifiers which are valid in this entry. See modifiers() */
|
||||
Qt::KeyboardModifiers modifierMask() const;
|
||||
|
||||
/** See modifiers() */
|
||||
void setModifiers( Qt::KeyboardModifiers modifiers );
|
||||
/** See modifierMask() and modifiers() */
|
||||
void setModifierMask( Qt::KeyboardModifiers modifiers );
|
||||
|
||||
/**
|
||||
* Returns a bitwise-OR of the enabled state flags associated with this entry.
|
||||
* If flag is set in stateMask() but not in state(), this means that the entry only
|
||||
* matches when the terminal is NOT in that state.
|
||||
*
|
||||
* If a state is not set in stateMask() then the entry matches whether the terminal
|
||||
* is in that state or not.
|
||||
*/
|
||||
States state() const;
|
||||
|
||||
/** Returns the state flags which are valid in this entry. See state() */
|
||||
States stateMask() const;
|
||||
|
||||
/** See state() */
|
||||
void setState( States state );
|
||||
/** See stateMask() */
|
||||
void setStateMask( States mask );
|
||||
|
||||
/**
|
||||
* Returns the key code and modifiers associated with this entry
|
||||
* as a QKeySequence
|
||||
*/
|
||||
//QKeySequence keySequence() const;
|
||||
|
||||
/**
|
||||
* Returns this entry's conditions ( ie. its key code, modifier and state criteria )
|
||||
* as a string.
|
||||
*/
|
||||
QString conditionToString() const;
|
||||
|
||||
/**
|
||||
* Returns this entry's result ( ie. its command or character sequence )
|
||||
* as a string.
|
||||
*
|
||||
* @param expandWildCards See text()
|
||||
* @param modifiers See text()
|
||||
*/
|
||||
QString resultToString(bool expandWildCards = false,
|
||||
Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
|
||||
|
||||
/**
|
||||
* Returns true if this entry matches the given key sequence, specified
|
||||
* as a combination of @p keyCode , @p modifiers and @p state.
|
||||
*/
|
||||
bool matches( int keyCode ,
|
||||
Qt::KeyboardModifiers modifiers ,
|
||||
States flags ) const;
|
||||
|
||||
bool operator==(const Entry& rhs) const;
|
||||
|
||||
private:
|
||||
void insertModifier( QString& item , int modifier ) const;
|
||||
void insertState( QString& item , int state ) const;
|
||||
QByteArray unescape(const QByteArray& text) const;
|
||||
|
||||
int _keyCode;
|
||||
Qt::KeyboardModifiers _modifiers;
|
||||
Qt::KeyboardModifiers _modifierMask;
|
||||
States _state;
|
||||
States _stateMask;
|
||||
|
||||
Command _command;
|
||||
QByteArray _text;
|
||||
};
|
||||
|
||||
/** Constructs a new keyboard translator with the given @p name */
|
||||
KeyboardTranslator(const QString& name);
|
||||
|
||||
//KeyboardTranslator(const KeyboardTranslator& other);
|
||||
|
||||
/** Returns the name of this keyboard translator */
|
||||
QString name() const;
|
||||
|
||||
/** Sets the name of this keyboard translator */
|
||||
void setName(const QString& name);
|
||||
|
||||
/** Returns the descriptive name of this keyboard translator */
|
||||
QString description() const;
|
||||
|
||||
/** Sets the descriptive name of this keyboard translator */
|
||||
void setDescription(const QString& description);
|
||||
|
||||
/**
|
||||
* Looks for an entry in this keyboard translator which matches the given
|
||||
* key code, keyboard modifiers and state flags.
|
||||
*
|
||||
* Returns the matching entry if found or a null Entry otherwise ( ie.
|
||||
* entry.isNull() will return true )
|
||||
*
|
||||
* @param keyCode A key code from the Qt::Key enum
|
||||
* @param modifiers A combination of modifiers
|
||||
* @param state Optional flags which specify the current state of the terminal
|
||||
*/
|
||||
Entry findEntry(int keyCode ,
|
||||
Qt::KeyboardModifiers modifiers ,
|
||||
States state = NoState) const;
|
||||
|
||||
/**
|
||||
* Adds an entry to this keyboard translator's table. Entries can be looked up according
|
||||
* to their key sequence using findEntry()
|
||||
*/
|
||||
void addEntry(const Entry& entry);
|
||||
|
||||
/**
|
||||
* Replaces an entry in the translator. If the @p existing entry is null,
|
||||
* then this is equivalent to calling addEntry(@p replacement)
|
||||
*/
|
||||
void replaceEntry(const Entry& existing , const Entry& replacement);
|
||||
|
||||
/**
|
||||
* Removes an entry from the table.
|
||||
*/
|
||||
void removeEntry(const Entry& entry);
|
||||
|
||||
/** Returns a list of all entries in the translator. */
|
||||
QList<Entry> entries() const;
|
||||
|
||||
private:
|
||||
|
||||
QHash<int,Entry> _entries; // entries in this keyboard translation,
|
||||
// entries are indexed according to
|
||||
// their keycode
|
||||
QString _name;
|
||||
QString _description;
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::States)
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands)
|
||||
|
||||
/**
|
||||
* Parses the contents of a Keyboard Translator (.keytab) file and
|
||||
* returns the entries found in it.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* @code
|
||||
* QFile source( "/path/to/keytab" );
|
||||
* source.open( QIODevice::ReadOnly );
|
||||
*
|
||||
* KeyboardTranslator* translator = new KeyboardTranslator( "name-of-translator" );
|
||||
*
|
||||
* KeyboardTranslatorReader reader(source);
|
||||
* while ( reader.hasNextEntry() )
|
||||
* translator->addEntry(reader.nextEntry());
|
||||
*
|
||||
* source.close();
|
||||
*
|
||||
* if ( !reader.parseError() )
|
||||
* {
|
||||
* // parsing succeeded, do something with the translator
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // parsing failed
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class KeyboardTranslatorReader
|
||||
{
|
||||
public:
|
||||
/** Constructs a new reader which parses the given @p source */
|
||||
KeyboardTranslatorReader( QIODevice* source );
|
||||
|
||||
/**
|
||||
* Returns the description text.
|
||||
* TODO: More documentation
|
||||
*/
|
||||
QString description() const;
|
||||
|
||||
/** Returns true if there is another entry in the source stream */
|
||||
bool hasNextEntry();
|
||||
/** Returns the next entry found in the source stream */
|
||||
KeyboardTranslator::Entry nextEntry();
|
||||
|
||||
/**
|
||||
* Returns true if an error occurred whilst parsing the input or
|
||||
* false if no error occurred.
|
||||
*/
|
||||
bool parseError();
|
||||
|
||||
/**
|
||||
* Parses a condition and result string for a translator entry
|
||||
* and produces a keyboard translator entry.
|
||||
*
|
||||
* The condition and result strings are in the same format as in
|
||||
*/
|
||||
static KeyboardTranslator::Entry createEntry( const QString& condition ,
|
||||
const QString& result );
|
||||
private:
|
||||
struct Token
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
TitleKeyword,
|
||||
TitleText,
|
||||
KeyKeyword,
|
||||
KeySequence,
|
||||
Command,
|
||||
OutputText
|
||||
};
|
||||
Type type;
|
||||
QString text;
|
||||
};
|
||||
QList<Token> tokenize(const QString&);
|
||||
void readNext();
|
||||
bool decodeSequence(const QString& ,
|
||||
int& keyCode,
|
||||
Qt::KeyboardModifiers& modifiers,
|
||||
Qt::KeyboardModifiers& modifierMask,
|
||||
KeyboardTranslator::States& state,
|
||||
KeyboardTranslator::States& stateFlags);
|
||||
|
||||
static bool parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier);
|
||||
static bool parseAsStateFlag(const QString& item , KeyboardTranslator::State& state);
|
||||
static bool parseAsKeyCode(const QString& item , int& keyCode);
|
||||
static bool parseAsCommand(const QString& text , KeyboardTranslator::Command& command);
|
||||
|
||||
QIODevice* _source;
|
||||
QString _description;
|
||||
KeyboardTranslator::Entry _nextEntry;
|
||||
bool _hasNext;
|
||||
};
|
||||
|
||||
/** Writes a keyboard translation to disk. */
|
||||
class KeyboardTranslatorWriter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new writer which saves data into @p destination.
|
||||
* The caller is responsible for closing the device when writing is complete.
|
||||
*/
|
||||
KeyboardTranslatorWriter(QIODevice* destination);
|
||||
~KeyboardTranslatorWriter();
|
||||
|
||||
/**
|
||||
* Writes the header for the keyboard translator.
|
||||
* @param description Description of the keyboard translator.
|
||||
*/
|
||||
void writeHeader( const QString& description );
|
||||
/** Writes a translator entry. */
|
||||
void writeEntry( const KeyboardTranslator::Entry& entry );
|
||||
|
||||
private:
|
||||
QIODevice* _destination;
|
||||
QTextStream* _writer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages the keyboard translations available for use by terminal sessions,
|
||||
* see KeyboardTranslator.
|
||||
*/
|
||||
class KeyboardTranslatorManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new KeyboardTranslatorManager and loads the list of
|
||||
* available keyboard translations.
|
||||
*
|
||||
* The keyboard translations themselves are not loaded until they are
|
||||
* first requested via a call to findTranslator()
|
||||
*/
|
||||
KeyboardTranslatorManager();
|
||||
~KeyboardTranslatorManager();
|
||||
|
||||
/**
|
||||
* Adds a new translator. If a translator with the same name
|
||||
* already exists, it will be replaced by the new translator.
|
||||
*
|
||||
* TODO: More documentation.
|
||||
*/
|
||||
void addTranslator(KeyboardTranslator* translator);
|
||||
|
||||
/**
|
||||
* Deletes a translator. Returns true on successful deletion or false otherwise.
|
||||
*
|
||||
* TODO: More documentation
|
||||
*/
|
||||
bool deleteTranslator(const QString& name);
|
||||
|
||||
/** Returns the default translator for Konsole. */
|
||||
const KeyboardTranslator* defaultTranslator();
|
||||
|
||||
/**
|
||||
* Returns the keyboard translator with the given name or 0 if no translator
|
||||
* with that name exists.
|
||||
*
|
||||
* The first time that a translator with a particular name is requested,
|
||||
* the on-disk .keyboard file is loaded and parsed.
|
||||
*/
|
||||
const KeyboardTranslator* findTranslator(const QString& name);
|
||||
/**
|
||||
* Returns a list of the names of available keyboard translators.
|
||||
*
|
||||
* The first time this is called, a search for available
|
||||
* translators is started.
|
||||
*/
|
||||
QList<QString> allTranslators();
|
||||
|
||||
/** Returns the global KeyboardTranslatorManager instance. */
|
||||
static KeyboardTranslatorManager* instance();
|
||||
|
||||
private:
|
||||
static const char* defaultTranslatorText;
|
||||
|
||||
void findTranslators(); // locate the available translators
|
||||
KeyboardTranslator* loadTranslator(const QString& name); // loads the translator
|
||||
// with the given name
|
||||
KeyboardTranslator* loadTranslator(QIODevice* device,const QString& name);
|
||||
|
||||
bool saveTranslator(const KeyboardTranslator* translator);
|
||||
QString findTranslatorPath(const QString& name);
|
||||
|
||||
QHash<QString,KeyboardTranslator*> _translators; // maps translator-name -> KeyboardTranslator
|
||||
// instance
|
||||
bool _haveLoadedAll;
|
||||
};
|
||||
|
||||
inline int KeyboardTranslator::Entry::keyCode() const { return _keyCode; }
|
||||
inline void KeyboardTranslator::Entry::setKeyCode(int keyCode) { _keyCode = keyCode; }
|
||||
|
||||
inline void KeyboardTranslator::Entry::setModifiers( Qt::KeyboardModifiers modifier )
|
||||
{
|
||||
_modifiers = modifier;
|
||||
}
|
||||
inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const { return _modifiers; }
|
||||
|
||||
inline void KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask )
|
||||
{
|
||||
_modifierMask = mask;
|
||||
}
|
||||
inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const { return _modifierMask; }
|
||||
|
||||
inline bool KeyboardTranslator::Entry::isNull() const
|
||||
{
|
||||
return ( *this == Entry() );
|
||||
}
|
||||
|
||||
inline void KeyboardTranslator::Entry::setCommand( Command command )
|
||||
{
|
||||
_command = command;
|
||||
}
|
||||
inline KeyboardTranslator::Command KeyboardTranslator::Entry::command() const { return _command; }
|
||||
|
||||
inline void KeyboardTranslator::Entry::setText( const QByteArray& text )
|
||||
{
|
||||
_text = unescape(text);
|
||||
}
|
||||
inline int oneOrZero(int value)
|
||||
{
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
|
||||
{
|
||||
QByteArray expandedText = _text;
|
||||
|
||||
if (expandWildCards)
|
||||
{
|
||||
int modifierValue = 1;
|
||||
modifierValue += oneOrZero(modifiers & Qt::ShiftModifier);
|
||||
modifierValue += oneOrZero(modifiers & Qt::AltModifier) << 1;
|
||||
modifierValue += oneOrZero(modifiers & Qt::ControlModifier) << 2;
|
||||
|
||||
for (int i=0;i<_text.length();i++)
|
||||
{
|
||||
if (expandedText[i] == '*')
|
||||
expandedText[i] = '0' + modifierValue;
|
||||
}
|
||||
}
|
||||
|
||||
return expandedText;
|
||||
}
|
||||
|
||||
inline void KeyboardTranslator::Entry::setState( States state )
|
||||
{
|
||||
_state = state;
|
||||
}
|
||||
inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const { return _state; }
|
||||
|
||||
inline void KeyboardTranslator::Entry::setStateMask( States stateMask )
|
||||
{
|
||||
_stateMask = stateMask;
|
||||
}
|
||||
inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const { return _stateMask; }
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(Konsole::KeyboardTranslator::Entry)
|
||||
Q_DECLARE_METATYPE(const Konsole::KeyboardTranslator*)
|
||||
|
||||
#endif // KEYBOARDTRANSLATOR_H
|
||||
|
@ -0,0 +1,21 @@
|
||||
// WARNING: Autogenerated by "fontembedder ./linefont.src".
|
||||
// You probably do not want to hand-edit this!
|
||||
|
||||
static const quint32 LineChars[] = {
|
||||
0x00007c00, 0x000fffe0, 0x00421084, 0x00e739ce, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00427000, 0x004e7380, 0x00e77800, 0x00ef7bc0,
|
||||
0x00421c00, 0x00439ce0, 0x00e73c00, 0x00e7bde0, 0x00007084, 0x000e7384, 0x000079ce, 0x000f7bce,
|
||||
0x00001c84, 0x00039ce4, 0x00003dce, 0x0007bdee, 0x00427084, 0x004e7384, 0x004279ce, 0x00e77884,
|
||||
0x00e779ce, 0x004f7bce, 0x00ef7bc4, 0x00ef7bce, 0x00421c84, 0x00439ce4, 0x00423dce, 0x00e73c84,
|
||||
0x00e73dce, 0x0047bdee, 0x00e7bde4, 0x00e7bdee, 0x00427c00, 0x0043fce0, 0x004e7f80, 0x004fffe0,
|
||||
0x004fffe0, 0x00e7fde0, 0x006f7fc0, 0x00efffe0, 0x00007c84, 0x0003fce4, 0x000e7f84, 0x000fffe4,
|
||||
0x00007dce, 0x0007fdee, 0x000f7fce, 0x000fffee, 0x00427c84, 0x0043fce4, 0x004e7f84, 0x004fffe4,
|
||||
0x00427dce, 0x00e77c84, 0x00e77dce, 0x0047fdee, 0x004e7fce, 0x00e7fde4, 0x00ef7f84, 0x004fffee,
|
||||
0x00efffe4, 0x00e7fdee, 0x00ef7fce, 0x00efffee, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x000f83e0, 0x00a5294a, 0x004e1380, 0x00a57800, 0x00ad0bc0, 0x004390e0, 0x00a53c00, 0x00a5a1e0,
|
||||
0x000e1384, 0x0000794a, 0x000f0b4a, 0x000390e4, 0x00003d4a, 0x0007a16a, 0x004e1384, 0x00a5694a,
|
||||
0x00ad2b4a, 0x004390e4, 0x00a52d4a, 0x00a5a16a, 0x004f83e0, 0x00a57c00, 0x00ad83e0, 0x000f83e4,
|
||||
0x00007d4a, 0x000f836a, 0x004f93e4, 0x00a57d4a, 0x00ad836a, 0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00001c00, 0x00001084, 0x00007000, 0x00421000,
|
||||
0x00039ce0, 0x000039ce, 0x000e7380, 0x00e73800, 0x000e7f80, 0x00e73884, 0x0003fce0, 0x004239ce
|
||||
};
|
@ -0,0 +1,786 @@
|
||||
#2500: single horizontal line
|
||||
2500
|
||||
|
||||
|
||||
-----
|
||||
|
||||
|
||||
|
||||
#2501: triple horizontal line
|
||||
2501
|
||||
|
||||
-----
|
||||
-----
|
||||
-----
|
||||
|
||||
|
||||
#2502: single vertical line
|
||||
2502
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
||||
#2503: triple vertical line
|
||||
2503
|
||||
|||
|
||||
|||
|
||||
|||
|
||||
|||
|
||||
|||
|
||||
|
||||
#2504-250B are dashed - not handled
|
||||
|
||||
#250C: top-left corner (lines on bottom + right)
|
||||
250C
|
||||
|
||||
|
||||
.--
|
||||
|
|
||||
|
|
||||
|
||||
#250D: as above, but top line triple-width
|
||||
250D
|
||||
|
||||
.--
|
||||
.--
|
||||
|--
|
||||
|
|
||||
|
||||
#250E: now the vert line triple-width
|
||||
250E
|
||||
|
||||
|
||||
..--
|
||||
|||
|
||||
|||
|
||||
|
||||
#250F: and now both lines triple-width
|
||||
250F
|
||||
|
||||
.___
|
||||
|.--
|
||||
||._
|
||||
|||
|
||||
|
||||
#2510: top-right corner
|
||||
2510
|
||||
|
||||
|
||||
--.
|
||||
|
|
||||
|
|
||||
|
||||
2511
|
||||
|
||||
==.
|
||||
==.
|
||||
==|
|
||||
|
|
||||
|
||||
2512
|
||||
|
||||
|
||||
==..
|
||||
|||
|
||||
|||
|
||||
|
||||
2513
|
||||
|
||||
===.
|
||||
==.|
|
||||
=.||
|
||||
|||
|
||||
|
||||
#2514: bottom-left corner
|
||||
2514
|
||||
|
|
||||
|
|
||||
.==
|
||||
|
||||
|
||||
|
||||
2515
|
||||
|
|
||||
|==
|
||||
|==
|
||||
===
|
||||
|
||||
|
||||
|
||||
2516
|
||||
|||
|
||||
|||
|
||||
|.==
|
||||
|
||||
|
||||
|
||||
2517
|
||||
|||
|
||||
||.=
|
||||
|.==
|
||||
.===
|
||||
|
||||
|
||||
#2518: bottm-right corner
|
||||
2518
|
||||
|
|
||||
|
|
||||
==.
|
||||
|
||||
|
||||
|
||||
2519
|
||||
|
|
||||
==|
|
||||
==|
|
||||
===
|
||||
|
||||
|
||||
|
||||
251A
|
||||
|||
|
||||
|||
|
||||
====
|
||||
|
||||
|
||||
|
||||
251B
|
||||
|||
|
||||
=.||
|
||||
==.|
|
||||
===.
|
||||
|
||||
|
||||
#251C: Join of vertical line and one from the right
|
||||
251C
|
||||
|
|
||||
|
|
||||
|==
|
||||
|
|
||||
|
|
||||
|
||||
251D
|
||||
|
|
||||
|==
|
||||
|==
|
||||
|==
|
||||
|
|
||||
|
||||
251E
|
||||
|||
|
||||
|||
|
||||
||==
|
||||
|
|
||||
|
|
||||
|
||||
251F
|
||||
|
|
||||
|
|
||||
||==
|
||||
|||
|
||||
|||
|
||||
|
||||
|
||||
2520
|
||||
|||
|
||||
|||
|
||||
||==
|
||||
|||
|
||||
|||
|
||||
|
||||
2521
|
||||
|||
|
||||
|||=
|
||||
||==
|
||||
.|==
|
||||
|
|
||||
|
||||
2522
|
||||
|
|
||||
.|==
|
||||
||==
|
||||
|||=
|
||||
|||
|
||||
|
||||
2523
|
||||
|||
|
||||
||.=
|
||||
||==
|
||||
||.=
|
||||
|||
|
||||
|
||||
#2524: Join of vertical line and one from the left
|
||||
2524
|
||||
|
|
||||
|
|
||||
==|
|
||||
|
|
||||
|
|
||||
|
||||
2525
|
||||
|
|
||||
==|
|
||||
==|
|
||||
==|
|
||||
|
|
||||
|
||||
2526
|
||||
|||
|
||||
|||
|
||||
==+|
|
||||
|
|
||||
|
|
||||
|
||||
2527
|
||||
|
|
||||
|
|
||||
==+|
|
||||
|||
|
||||
|||
|
||||
|
||||
2528
|
||||
|||
|
||||
|||
|
||||
==+|
|
||||
|||
|
||||
|||
|
||||
|
||||
2529
|
||||
|||
|
||||
=+||
|
||||
==+|
|
||||
===+
|
||||
|
|
||||
|
||||
252A
|
||||
|
|
||||
=+||
|
||||
==+|
|
||||
===+
|
||||
|||
|
||||
|
||||
252B
|
||||
|||
|
||||
=+||
|
||||
==+|
|
||||
=+||
|
||||
|||
|
||||
|
||||
#252C: horizontal line joined to from below
|
||||
252C
|
||||
|
||||
|
||||
=====
|
||||
|
|
||||
|
|
||||
|
||||
252D
|
||||
|
||||
===
|
||||
==|==
|
||||
==|
|
||||
|
|
||||
|
||||
252E
|
||||
|
||||
===
|
||||
==|==
|
||||
|==
|
||||
|
|
||||
|
||||
252F
|
||||
|
||||
==+==
|
||||
==|==
|
||||
==|==
|
||||
|
|
||||
|
||||
2530
|
||||
|
||||
=====
|
||||
=====
|
||||
==|==
|
||||
|
|
||||
|
||||
2531
|
||||
|
||||
===|
|
||||
==||=
|
||||
=|||
|
||||
|||
|
||||
|
||||
2532
|
||||
|
||||
|===
|
||||
=||==
|
||||
||==
|
||||
||
|
||||
|
||||
2533
|
||||
|
||||
=====
|
||||
==|==
|
||||
=+|+=
|
||||
|||
|
||||
|
||||
#2534: bottom line, connected to from top
|
||||
2534
|
||||
|
|
||||
|
|
||||
=====
|
||||
|
||||
|
||||
|
||||
2535
|
||||
|
|
||||
==|
|
||||
=====
|
||||
===
|
||||
|
||||
|
||||
2536
|
||||
|
|
||||
|==
|
||||
=====
|
||||
===
|
||||
|
||||
|
||||
2537
|
||||
|
|
||||
==|==
|
||||
=====
|
||||
=====
|
||||
|
||||
|
||||
2538
|
||||
|||
|
||||
|||
|
||||
=====
|
||||
|
||||
|
||||
|
||||
2539
|
||||
|||
|
||||
==||
|
||||
=====
|
||||
===|
|
||||
|
||||
|
||||
|
||||
253A
|
||||
|||
|
||||
||==
|
||||
=|===
|
||||
|===
|
||||
|
||||
|
||||
253B
|
||||
|||
|
||||
==|==
|
||||
=====
|
||||
=====
|
||||
|
||||
|
||||
#253C: vertical + horizontal lines intersecting
|
||||
253C
|
||||
|
|
||||
|
|
||||
=====
|
||||
|
|
||||
|
|
||||
|
||||
253D
|
||||
|
|
||||
==|
|
||||
=====
|
||||
==|
|
||||
|
|
||||
|
||||
253E
|
||||
|
|
||||
|==
|
||||
=====
|
||||
|==
|
||||
|
|
||||
|
||||
253F
|
||||
|
|
||||
==|==
|
||||
=====
|
||||
==|==
|
||||
|
|
||||
|
||||
2540
|
||||
|||
|
||||
|||
|
||||
=====
|
||||
|
|
||||
|
|
||||
|
||||
2541
|
||||
|
|
||||
|
|
||||
=====
|
||||
|||
|
||||
|||
|
||||
|
||||
2542
|
||||
|||
|
||||
|||
|
||||
=====
|
||||
|||
|
||||
|||
|
||||
|
||||
2543
|
||||
|||
|
||||
=|||
|
||||
=====
|
||||
==|+
|
||||
|
|
||||
|
||||
2544
|
||||
|||
|
||||
||==
|
||||
=====
|
||||
|==
|
||||
|
|
||||
|
||||
2545
|
||||
|
|
||||
==|+
|
||||
=====
|
||||
=|||
|
||||
|||
|
||||
|
||||
2546
|
||||
|
|
||||
|==
|
||||
=====
|
||||
||==
|
||||
|||
|
||||
|
||||
2547
|
||||
|||
|
||||
=|||=
|
||||
=====
|
||||
=|||=
|
||||
|
|
||||
|
||||
2548
|
||||
|
|
||||
=|||=
|
||||
=====
|
||||
=|||=
|
||||
|||
|
||||
|
||||
2549
|
||||
|||
|
||||
=|||
|
||||
=====
|
||||
=|||
|
||||
|||
|
||||
|
||||
254A
|
||||
|||
|
||||
|||=
|
||||
=====
|
||||
|||=
|
||||
|||
|
||||
|
||||
254B
|
||||
|||
|
||||
=|||=
|
||||
=====
|
||||
=|||=
|
||||
|||
|
||||
|
||||
#254C-254F are dashed
|
||||
2550
|
||||
|
||||
_____
|
||||
|
||||
_____
|
||||
|
||||
|
||||
2551
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
|
||||
2552
|
||||
|
||||
|--
|
||||
|
|
||||
|--
|
||||
|
|
||||
|
||||
2553
|
||||
|
||||
|
||||
----
|
||||
| |
|
||||
| |
|
||||
|
||||
2554
|
||||
|
||||
+---
|
||||
|
|
||||
+ +-
|
||||
| |
|
||||
|
||||
2555
|
||||
|
||||
--+
|
||||
|
|
||||
--+
|
||||
|
|
||||
|
||||
2556
|
||||
|
||||
|
||||
-+-+
|
||||
| |
|
||||
| |
|
||||
|
||||
2557
|
||||
|
||||
---+
|
||||
|
|
||||
-+ |
|
||||
| |
|
||||
|
||||
2558
|
||||
|
|
||||
+--
|
||||
|
|
||||
+--
|
||||
|
||||
2559
|
||||
| |
|
||||
| |
|
||||
+-+-
|
||||
|
||||
|
||||
|
||||
255A
|
||||
| |
|
||||
| +-
|
||||
|
|
||||
+---
|
||||
|
||||
|
||||
255B
|
||||
|
|
||||
--+
|
||||
|
|
||||
--+
|
||||
|
||||
|
||||
255C
|
||||
| |
|
||||
| |
|
||||
-+-+
|
||||
|
||||
|
||||
255D
|
||||
| |
|
||||
-+ |
|
||||
|
|
||||
---+
|
||||
|
||||
|
||||
255E
|
||||
|
|
||||
+--
|
||||
|
|
||||
+--
|
||||
|
|
||||
|
||||
255F
|
||||
| |
|
||||
| |
|
||||
| +-
|
||||
| |
|
||||
| |
|
||||
|
||||
2560
|
||||
| |
|
||||
| +-
|
||||
| |
|
||||
| +-
|
||||
| |
|
||||
|
||||
2561
|
||||
|
|
||||
--+
|
||||
|
|
||||
--+
|
||||
|
|
||||
|
||||
2562
|
||||
| |
|
||||
| |
|
||||
-+ +
|
||||
| |
|
||||
| |
|
||||
|
||||
2563
|
||||
| |
|
||||
-+ |
|
||||
|
|
||||
-+ |
|
||||
| |
|
||||
|
||||
2564
|
||||
|
||||
-----
|
||||
|
||||
--+--
|
||||
|
|
||||
|
||||
2565
|
||||
|
||||
|
||||
-+-+-
|
||||
| |
|
||||
| |
|
||||
|
||||
2566
|
||||
|
||||
-----
|
||||
|
||||
-+ +-
|
||||
| |
|
||||
|
||||
2567
|
||||
|
|
||||
--+--
|
||||
|
||||
-----
|
||||
|
||||
|
||||
2568
|
||||
| |
|
||||
| |
|
||||
-+-+-
|
||||
|
||||
|
||||
|
||||
2569
|
||||
| |
|
||||
-+ +-
|
||||
|
||||
-----
|
||||
|
||||
|
||||
256A
|
||||
|
|
||||
--+--
|
||||
|
|
||||
--+--
|
||||
|
|
||||
|
||||
256B
|
||||
| |
|
||||
| |
|
||||
-+-+-
|
||||
| |
|
||||
| |
|
||||
|
||||
256C
|
||||
| |
|
||||
-+ +-
|
||||
|
||||
-+ +-
|
||||
| |
|
||||
|
||||
#256F-2570 are curly,
|
||||
#2571-2573 are slashes and X
|
||||
|
||||
2574
|
||||
|
||||
|
||||
___
|
||||
|
||||
|
||||
|
||||
2575
|
||||
|
|
||||
|
|
||||
|
|
||||
|
||||
|
||||
|
||||
2576
|
||||
|
||||
|
||||
___
|
||||
|
||||
|
||||
|
||||
2577
|
||||
|
||||
|
||||
|
|
||||
|
|
||||
|
|
||||
|
||||
2578
|
||||
|
||||
___
|
||||
___
|
||||
___
|
||||
|
||||
|
||||
2579
|
||||
|||
|
||||
|||
|
||||
|||
|
||||
|
||||
|
||||
|
||||
257A
|
||||
|
||||
___
|
||||
___
|
||||
___
|
||||
|
||||
|
||||
257B
|
||||
|
||||
|
||||
|||
|
||||
|||
|
||||
|||
|
||||
|
||||
257C
|
||||
|
||||
___
|
||||
_____
|
||||
___
|
||||
|
||||
|
||||
257D
|
||||
|
|
||||
|
|
||||
|||
|
||||
|||
|
||||
|||
|
||||
|
||||
257E
|
||||
|
||||
___
|
||||
_____
|
||||
___
|
||||
|
||||
|
||||
257F
|
||||
|||
|
||||
|||
|
||||
|||
|
||||
|
|
||||
|
|
@ -0,0 +1,320 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "Pty.h"
|
||||
|
||||
// System
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
|
||||
// Qt
|
||||
#include <QtCore>
|
||||
|
||||
// KDE
|
||||
//#include <KStandardDirs>
|
||||
//#include <KLocale>
|
||||
//#include <KDebug>
|
||||
#include "kpty.h"
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
void Pty::donePty()
|
||||
{
|
||||
emit done(exitStatus());
|
||||
}
|
||||
|
||||
void Pty::setWindowSize(int lines, int cols)
|
||||
{
|
||||
_windowColumns = cols;
|
||||
_windowLines = lines;
|
||||
|
||||
if (pty()->masterFd() >= 0)
|
||||
pty()->setWinSize(lines, cols);
|
||||
}
|
||||
QSize Pty::windowSize() const
|
||||
{
|
||||
return QSize(_windowColumns,_windowLines);
|
||||
}
|
||||
|
||||
void Pty::setXonXoff(bool enable)
|
||||
{
|
||||
_xonXoff = enable;
|
||||
|
||||
if (pty()->masterFd() >= 0)
|
||||
{
|
||||
struct ::termios ttmode;
|
||||
pty()->tcGetAttr(&ttmode);
|
||||
if (!enable)
|
||||
ttmode.c_iflag &= ~(IXOFF | IXON);
|
||||
else
|
||||
ttmode.c_iflag |= (IXOFF | IXON);
|
||||
if (!pty()->tcSetAttr(&ttmode))
|
||||
qWarning("Unable to set terminal attributes.");
|
||||
}
|
||||
}
|
||||
|
||||
void Pty::setUtf8Mode(bool enable)
|
||||
{
|
||||
#ifdef IUTF8 // XXX not a reasonable place to check it.
|
||||
_utf8 = enable;
|
||||
|
||||
if (pty()->masterFd() >= 0)
|
||||
{
|
||||
struct ::termios ttmode;
|
||||
pty()->tcGetAttr(&ttmode);
|
||||
if (!enable)
|
||||
ttmode.c_iflag &= ~IUTF8;
|
||||
else
|
||||
ttmode.c_iflag |= IUTF8;
|
||||
if (!pty()->tcSetAttr(&ttmode))
|
||||
qWarning("Unable to set terminal attributes.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Pty::setErase(char erase)
|
||||
{
|
||||
_eraseChar = erase;
|
||||
|
||||
if (pty()->masterFd() >= 0)
|
||||
{
|
||||
struct ::termios ttmode;
|
||||
|
||||
pty()->tcGetAttr(&ttmode);
|
||||
|
||||
ttmode.c_cc[VERASE] = erase;
|
||||
|
||||
if (!pty()->tcSetAttr(&ttmode))
|
||||
qWarning("Unable to set terminal attributes.");
|
||||
}
|
||||
}
|
||||
|
||||
char Pty::erase() const
|
||||
{
|
||||
if (pty()->masterFd() >= 0)
|
||||
{
|
||||
qDebug() << "Getting erase char";
|
||||
struct ::termios ttyAttributes;
|
||||
pty()->tcGetAttr(&ttyAttributes);
|
||||
return ttyAttributes.c_cc[VERASE];
|
||||
}
|
||||
|
||||
return _eraseChar;
|
||||
}
|
||||
|
||||
void Pty::addEnvironmentVariables(const QStringList& environment)
|
||||
{
|
||||
QListIterator<QString> iter(environment);
|
||||
while (iter.hasNext())
|
||||
{
|
||||
QString pair = iter.next();
|
||||
|
||||
// split on the first '=' character
|
||||
int pos = pair.indexOf('=');
|
||||
|
||||
if ( pos >= 0 )
|
||||
{
|
||||
QString variable = pair.left(pos);
|
||||
QString value = pair.mid(pos+1);
|
||||
|
||||
//kDebug() << "Setting environment pair" << variable <<
|
||||
// " set to " << value;
|
||||
|
||||
setEnvironment(variable,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Pty::start(const QString& program,
|
||||
const QStringList& programArguments,
|
||||
const QStringList& environment,
|
||||
ulong winid,
|
||||
bool addToUtmp
|
||||
// const QString& dbusService,
|
||||
// const QString& dbusSession)
|
||||
)
|
||||
{
|
||||
clearArguments();
|
||||
|
||||
setBinaryExecutable(program.toLatin1());
|
||||
|
||||
addEnvironmentVariables(environment);
|
||||
|
||||
QStringListIterator it( programArguments );
|
||||
while (it.hasNext())
|
||||
arguments.append( it.next().toUtf8() );
|
||||
|
||||
// if ( !dbusService.isEmpty() )
|
||||
// setEnvironment("KONSOLE_DBUS_SERVICE",dbusService);
|
||||
// if ( !dbusSession.isEmpty() )
|
||||
// setEnvironment("KONSOLE_DBUS_SESSION", dbusSession);
|
||||
|
||||
setEnvironment("WINDOWID", QString::number(winid));
|
||||
|
||||
// unless the LANGUAGE environment variable has been set explicitly
|
||||
// set it to a null string
|
||||
// this fixes the problem where KCatalog sets the LANGUAGE environment
|
||||
// variable during the application's startup to something which
|
||||
// differs from LANG,LC_* etc. and causes programs run from
|
||||
// the terminal to display mesages in the wrong language
|
||||
//
|
||||
// this can happen if LANG contains a language which KDE
|
||||
// does not have a translation for
|
||||
//
|
||||
// BR:149300
|
||||
if (!environment.contains("LANGUAGE"))
|
||||
setEnvironment("LANGUAGE",QString());
|
||||
|
||||
setUsePty(All, addToUtmp);
|
||||
|
||||
pty()->open();
|
||||
|
||||
struct ::termios ttmode;
|
||||
pty()->tcGetAttr(&ttmode);
|
||||
if (!_xonXoff)
|
||||
ttmode.c_iflag &= ~(IXOFF | IXON);
|
||||
else
|
||||
ttmode.c_iflag |= (IXOFF | IXON);
|
||||
#ifdef IUTF8 // XXX not a reasonable place to check it.
|
||||
if (!_utf8)
|
||||
ttmode.c_iflag &= ~IUTF8;
|
||||
else
|
||||
ttmode.c_iflag |= IUTF8;
|
||||
#endif
|
||||
|
||||
if (_eraseChar != 0)
|
||||
ttmode.c_cc[VERASE] = _eraseChar;
|
||||
|
||||
if (!pty()->tcSetAttr(&ttmode))
|
||||
qWarning("Unable to set terminal attributes.");
|
||||
|
||||
pty()->setWinSize(_windowLines, _windowColumns);
|
||||
|
||||
if ( K3Process::start(NotifyOnExit, (Communication) (Stdin | Stdout)) == false )
|
||||
return -1;
|
||||
|
||||
resume(); // Start...
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void Pty::setWriteable(bool writeable)
|
||||
{
|
||||
struct stat sbuf;
|
||||
stat(pty()->ttyName(), &sbuf);
|
||||
if (writeable)
|
||||
chmod(pty()->ttyName(), sbuf.st_mode | S_IWGRP);
|
||||
else
|
||||
chmod(pty()->ttyName(), sbuf.st_mode & ~(S_IWGRP|S_IWOTH));
|
||||
}
|
||||
|
||||
Pty::Pty()
|
||||
: _bufferFull(false),
|
||||
_windowColumns(0),
|
||||
_windowLines(0),
|
||||
_eraseChar(0),
|
||||
_xonXoff(true),
|
||||
_utf8(true)
|
||||
{
|
||||
connect(this, SIGNAL(receivedStdout(K3Process *, char *, int )),
|
||||
this, SLOT(dataReceived(K3Process *,char *, int)));
|
||||
connect(this, SIGNAL(processExited(K3Process *)),
|
||||
this, SLOT(donePty()));
|
||||
connect(this, SIGNAL(wroteStdin(K3Process *)),
|
||||
this, SLOT(writeReady()));
|
||||
_pty = new KPty;
|
||||
|
||||
setUsePty(All, false); // utmp will be overridden later
|
||||
}
|
||||
|
||||
Pty::~Pty()
|
||||
{
|
||||
delete _pty;
|
||||
}
|
||||
|
||||
void Pty::writeReady()
|
||||
{
|
||||
_pendingSendJobs.erase(_pendingSendJobs.begin());
|
||||
_bufferFull = false;
|
||||
doSendJobs();
|
||||
}
|
||||
|
||||
void Pty::doSendJobs() {
|
||||
if(_pendingSendJobs.isEmpty())
|
||||
{
|
||||
emit bufferEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
SendJob& job = _pendingSendJobs.first();
|
||||
|
||||
|
||||
if (!writeStdin( job.data(), job.length() ))
|
||||
{
|
||||
qWarning("Pty::doSendJobs - Could not send input data to terminal process.");
|
||||
return;
|
||||
}
|
||||
_bufferFull = true;
|
||||
}
|
||||
|
||||
void Pty::appendSendJob(const char* s, int len)
|
||||
{
|
||||
_pendingSendJobs.append(SendJob(s,len));
|
||||
}
|
||||
|
||||
void Pty::sendData(const char* s, int len)
|
||||
{
|
||||
appendSendJob(s,len);
|
||||
if (!_bufferFull)
|
||||
doSendJobs();
|
||||
}
|
||||
|
||||
void Pty::dataReceived(K3Process *,char *buf, int len)
|
||||
{
|
||||
emit receivedData(buf,len);
|
||||
}
|
||||
|
||||
void Pty::lockPty(bool lock)
|
||||
{
|
||||
if (lock)
|
||||
suspend();
|
||||
else
|
||||
resume();
|
||||
}
|
||||
|
||||
int Pty::foregroundProcessGroup() const
|
||||
{
|
||||
int pid = tcgetpgrp(pty()->masterFd());
|
||||
|
||||
if ( pid != -1 )
|
||||
{
|
||||
return pid;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//#include "moc_Pty.cpp"
|
@ -0,0 +1,243 @@
|
||||
/*
|
||||
This file is part of Konsole, KDE's terminal emulator.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef PTY_H
|
||||
#define PTY_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore>
|
||||
|
||||
#include "k3process.h"
|
||||
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
/**
|
||||
* The Pty class is used to start the terminal process,
|
||||
* send data to it, receive data from it and manipulate
|
||||
* various properties of the pseudo-teletype interface
|
||||
* used to communicate with the process.
|
||||
*
|
||||
* To use this class, construct an instance and connect
|
||||
* to the sendData slot and receivedData signal to
|
||||
* send data to or receive data from the process.
|
||||
*
|
||||
* To start the terminal process, call the start() method
|
||||
* with the program name and appropriate arguments.
|
||||
*/
|
||||
class Pty: public K3Process
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructs a new Pty.
|
||||
*
|
||||
* Connect to the sendData() slot and receivedData() signal to prepare
|
||||
* for sending and receiving data from the terminal process.
|
||||
*
|
||||
* To start the terminal process, call the run() method with the
|
||||
* name of the program to start and appropriate arguments.
|
||||
*/
|
||||
Pty();
|
||||
~Pty();
|
||||
|
||||
/**
|
||||
* Starts the terminal process.
|
||||
*
|
||||
* Returns 0 if the process was started successfully or non-zero
|
||||
* otherwise.
|
||||
*
|
||||
* @param program Path to the program to start
|
||||
* @param arguments Arguments to pass to the program being started
|
||||
* @param environment A list of key=value pairs which will be added
|
||||
* to the environment for the new process. At the very least this
|
||||
* should include an assignment for the TERM environment variable.
|
||||
* @param winid Specifies the value of the WINDOWID environment variable
|
||||
* in the process's environment.
|
||||
* @param addToUtmp Specifies whether a utmp entry should be created for
|
||||
* the pty used. See K3Process::setUsePty()
|
||||
* @param dbusService Specifies the value of the KONSOLE_DBUS_SERVICE
|
||||
* environment variable in the process's environment.
|
||||
* @param dbusSession Specifies the value of the KONSOLE_DBUS_SESSION
|
||||
* environment variable in the process's environment.
|
||||
*/
|
||||
int start( const QString& program,
|
||||
const QStringList& arguments,
|
||||
const QStringList& environment,
|
||||
ulong winid,
|
||||
bool addToUtmp
|
||||
// const QString& dbusService,
|
||||
// const QString& dbusSession
|
||||
);
|
||||
|
||||
/** TODO: Document me */
|
||||
void setWriteable(bool writeable);
|
||||
|
||||
/**
|
||||
* Enables or disables Xon/Xoff flow control.
|
||||
*/
|
||||
void setXonXoff(bool on);
|
||||
|
||||
/**
|
||||
* Sets the size of the window (in lines and columns of characters)
|
||||
* used by this teletype.
|
||||
*/
|
||||
void setWindowSize(int lines, int cols);
|
||||
|
||||
/** Returns the size of the window used by this teletype. See setWindowSize() */
|
||||
QSize windowSize() const;
|
||||
|
||||
/** TODO Document me */
|
||||
void setErase(char erase);
|
||||
|
||||
/** */
|
||||
char erase() const;
|
||||
|
||||
/**
|
||||
* Returns the process id of the teletype's current foreground
|
||||
* process. This is the process which is currently reading
|
||||
* input sent to the terminal via. sendData()
|
||||
*
|
||||
* If there is a problem reading the foreground process group,
|
||||
* 0 will be returned.
|
||||
*/
|
||||
int foregroundProcessGroup() const;
|
||||
|
||||
/**
|
||||
* Returns whether the buffer used to send data to the
|
||||
* terminal process is full.
|
||||
*/
|
||||
bool bufferFull() const { return _bufferFull; }
|
||||
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Put the pty into UTF-8 mode on systems which support it.
|
||||
*/
|
||||
void setUtf8Mode(bool on);
|
||||
|
||||
/**
|
||||
* Suspend or resume processing of data from the standard
|
||||
* output of the terminal process.
|
||||
*
|
||||
* See K3Process::suspend() and K3Process::resume()
|
||||
*
|
||||
* @param lock If true, processing of output is suspended,
|
||||
* otherwise processing is resumed.
|
||||
*/
|
||||
void lockPty(bool lock);
|
||||
|
||||
/**
|
||||
* Sends data to the process currently controlling the
|
||||
* teletype ( whose id is returned by foregroundProcessGroup() )
|
||||
*
|
||||
* @param buffer Pointer to the data to send.
|
||||
* @param length Length of @p buffer.
|
||||
*/
|
||||
void sendData(const char* buffer, int length);
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted when the terminal process terminates.
|
||||
*
|
||||
* @param exitCode The status code which the process exited with.
|
||||
*/
|
||||
void done(int exitCode);
|
||||
|
||||
/**
|
||||
* Emitted when a new block of data is received from
|
||||
* the teletype.
|
||||
*
|
||||
* @param buffer Pointer to the data received.
|
||||
* @param length Length of @p buffer
|
||||
*/
|
||||
void receivedData(const char* buffer, int length);
|
||||
|
||||
/**
|
||||
* Emitted when the buffer used to send data to the terminal
|
||||
* process becomes empty, i.e. all data has been sent.
|
||||
*/
|
||||
void bufferEmpty();
|
||||
|
||||
|
||||
private slots:
|
||||
|
||||
// called when terminal process exits
|
||||
void donePty();
|
||||
// called when data is received from the terminal process
|
||||
void dataReceived(K3Process*, char* buffer, int length);
|
||||
// sends the first enqueued buffer of data to the
|
||||
// terminal process
|
||||
void doSendJobs();
|
||||
// called when the terminal process is ready to
|
||||
// receive more data
|
||||
void writeReady();
|
||||
|
||||
private:
|
||||
// takes a list of key=value pairs and adds them
|
||||
// to the environment for the process
|
||||
void addEnvironmentVariables(const QStringList& environment);
|
||||
|
||||
// enqueues a buffer of data to be sent to the
|
||||
// terminal process
|
||||
void appendSendJob(const char* buffer, int length);
|
||||
|
||||
// a buffer of data in the queue to be sent to the
|
||||
// terminal process
|
||||
class SendJob {
|
||||
public:
|
||||
SendJob() {}
|
||||
SendJob(const char* b, int len) : buffer(len)
|
||||
{
|
||||
memcpy( buffer.data() , b , len );
|
||||
}
|
||||
|
||||
const char* data() const { return buffer.constData(); }
|
||||
int length() const { return buffer.size(); }
|
||||
private:
|
||||
QVector<char> buffer;
|
||||
};
|
||||
|
||||
QList<SendJob> _pendingSendJobs;
|
||||
bool _bufferFull;
|
||||
|
||||
int _windowColumns;
|
||||
int _windowLines;
|
||||
char _eraseChar;
|
||||
bool _xonXoff;
|
||||
bool _utf8;
|
||||
KPty *_pty;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // PTY_H
|
@ -0,0 +1,7 @@
|
||||
lib.pro is a *.pro-file for qmake
|
||||
|
||||
It produces static lib (libqtermwidget.a) only.
|
||||
For creating shared lib (*.so) uncomment "dll" in "CONFIG" line in *.pro-file
|
||||
|
||||
Library was tested both with HAVE_POSIX_OPENPT and HAVE_GETPT precompiler directives,
|
||||
defined in "DEFINES" line. You should select variant which would be correct for your system.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,662 @@
|
||||
/*
|
||||
This file is part of Konsole, KDE's terminal.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SCREEN_H
|
||||
#define SCREEN_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QRect>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QVarLengthArray>
|
||||
|
||||
// Konsole
|
||||
#include "Character.h"
|
||||
#include "History.h"
|
||||
|
||||
#define MODE_Origin 0
|
||||
#define MODE_Wrap 1
|
||||
#define MODE_Insert 2
|
||||
#define MODE_Screen 3
|
||||
#define MODE_Cursor 4
|
||||
#define MODE_NewLine 5
|
||||
#define MODES_SCREEN 6
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
/*!
|
||||
*/
|
||||
struct ScreenParm
|
||||
{
|
||||
int mode[MODES_SCREEN];
|
||||
};
|
||||
|
||||
class TerminalCharacterDecoder;
|
||||
|
||||
/**
|
||||
\brief An image of characters with associated attributes.
|
||||
|
||||
The terminal emulation ( Emulation ) receives a serial stream of
|
||||
characters from the program currently running in the terminal.
|
||||
From this stream it creates an image of characters which is ultimately
|
||||
rendered by the display widget ( TerminalDisplay ). Some types of emulation
|
||||
may have more than one screen image.
|
||||
|
||||
getImage() is used to retrieve the currently visible image
|
||||
which is then used by the display widget to draw the output from the
|
||||
terminal.
|
||||
|
||||
The number of lines of output history which are kept in addition to the current
|
||||
screen image depends on the history scroll being used to store the output.
|
||||
The scroll is specified using setScroll()
|
||||
The output history can be retrieved using writeToStream()
|
||||
|
||||
The screen image has a selection associated with it, specified using
|
||||
setSelectionStart() and setSelectionEnd(). The selected text can be retrieved
|
||||
using selectedText(). When getImage() is used to retrieve the the visible image,
|
||||
characters which are part of the selection have their colours inverted.
|
||||
*/
|
||||
class Screen
|
||||
{
|
||||
public:
|
||||
/** Construct a new screen image of size @p lines by @p columns. */
|
||||
Screen(int lines, int columns);
|
||||
~Screen();
|
||||
|
||||
// VT100/2 Operations
|
||||
// Cursor Movement
|
||||
|
||||
/** Move the cursor up by @p n lines. */
|
||||
void cursorUp (int n);
|
||||
/** Move the cursor down by @p n lines. */
|
||||
void cursorDown (int n);
|
||||
/** Move the cursor to the left by @p n columns. */
|
||||
void cursorLeft (int n);
|
||||
/** Move the cursor to the right by @p n columns. */
|
||||
void cursorRight (int n);
|
||||
/** Position the cursor on line @p y. */
|
||||
void setCursorY (int y);
|
||||
/** Position the cursor at column @p x. */
|
||||
void setCursorX (int x);
|
||||
/** Position the cursor at line @p y, column @p x. */
|
||||
void setCursorYX (int y, int x);
|
||||
/**
|
||||
* Sets the margins for scrolling the screen.
|
||||
*
|
||||
* @param topLine The top line of the new scrolling margin.
|
||||
* @param bottomLine The bottom line of the new scrolling margin.
|
||||
*/
|
||||
void setMargins (int topLine , int bottomLine);
|
||||
/** Returns the top line of the scrolling region. */
|
||||
int topMargin() const;
|
||||
/** Returns the bottom line of the scrolling region. */
|
||||
int bottomMargin() const;
|
||||
|
||||
/**
|
||||
* Resets the scrolling margins back to the top and bottom lines
|
||||
* of the screen.
|
||||
*/
|
||||
void setDefaultMargins();
|
||||
|
||||
/**
|
||||
* Moves the cursor down one line, if the MODE_NewLine mode
|
||||
* flag is enabled then the cursor is returned to the leftmost
|
||||
* column first.
|
||||
*
|
||||
* Equivalent to NextLine() if the MODE_NewLine flag is set
|
||||
* or index() otherwise.
|
||||
*/
|
||||
void NewLine ();
|
||||
/**
|
||||
* Moves the cursor down one line and positions it at the beginning
|
||||
* of the line.
|
||||
*/
|
||||
void NextLine ();
|
||||
|
||||
/**
|
||||
* Move the cursor down one line. If the cursor is on the bottom
|
||||
* line of the scrolling region (as returned by bottomMargin()) the
|
||||
* scrolling region is scrolled up by one line instead.
|
||||
*/
|
||||
void index ();
|
||||
/**
|
||||
* Move the cursor up one line. If the cursor is on the top line
|
||||
* of the scrolling region (as returned by topMargin()) the scrolling
|
||||
* region is scrolled down by one line instead.
|
||||
*/
|
||||
void reverseIndex();
|
||||
|
||||
/**
|
||||
* Scroll the scrolling region of the screen up by @p n lines.
|
||||
* The scrolling region is initially the whole screen, but can be changed
|
||||
* using setMargins()
|
||||
*/
|
||||
void scrollUp(int n);
|
||||
/**
|
||||
* Scroll the scrolling region of the screen down by @p n lines.
|
||||
* The scrolling region is initially the whole screen, but can be changed
|
||||
* using setMargins()
|
||||
*/
|
||||
void scrollDown(int n);
|
||||
|
||||
/**
|
||||
* Moves the cursor to the beginning of the current line.
|
||||
* Equivalent to setCursorX(0)
|
||||
*/
|
||||
void Return ();
|
||||
/**
|
||||
* Moves the cursor one column to the left and erases the character
|
||||
* at the new cursor position.
|
||||
*/
|
||||
void BackSpace ();
|
||||
/**
|
||||
* Moves the cursor @p n tab-stops to the right.
|
||||
*/
|
||||
void Tabulate (int n = 1);
|
||||
/**
|
||||
* Moves the cursor @p n tab-stops to the left.
|
||||
*/
|
||||
void backTabulate(int n);
|
||||
|
||||
// Editing
|
||||
|
||||
/**
|
||||
* Erase @p n characters beginning from the current cursor position.
|
||||
* This is equivalent to over-writing @p n characters starting with the current
|
||||
* cursor position with spaces.
|
||||
* If @p n is 0 then one character is erased.
|
||||
*/
|
||||
void eraseChars (int n);
|
||||
/**
|
||||
* Delete @p n characters beginning from the current cursor position.
|
||||
* If @p n is 0 then one character is deleted.
|
||||
*/
|
||||
void deleteChars (int n);
|
||||
/**
|
||||
* Insert @p n blank characters beginning from the current cursor position.
|
||||
* The position of the cursor is not altered.
|
||||
* If @p n is 0 then one character is inserted.
|
||||
*/
|
||||
void insertChars (int n);
|
||||
/**
|
||||
* Removes @p n lines beginning from the current cursor position.
|
||||
* The position of the cursor is not altered.
|
||||
* If @p n is 0 then one line is removed.
|
||||
*/
|
||||
void deleteLines (int n);
|
||||
/**
|
||||
* Inserts @p lines beginning from the current cursor position.
|
||||
* The position of the cursor is not altered.
|
||||
* If @p n is 0 then one line is inserted.
|
||||
*/
|
||||
void insertLines (int n);
|
||||
/** Clears all the tab stops. */
|
||||
void clearTabStops();
|
||||
/** Sets or removes a tab stop at the cursor's current column. */
|
||||
void changeTabStop(bool set);
|
||||
|
||||
/** Resets (clears) the specified screen @p mode. */
|
||||
void resetMode (int mode);
|
||||
/** Sets (enables) the specified screen @p mode. */
|
||||
void setMode (int mode);
|
||||
/**
|
||||
* Saves the state of the specified screen @p mode. It can be restored
|
||||
* using restoreMode()
|
||||
*/
|
||||
void saveMode (int mode);
|
||||
/** Restores the state of a screen @p mode saved by calling saveMode() */
|
||||
void restoreMode (int mode);
|
||||
/** Returns whether the specified screen @p mode is enabled or not .*/
|
||||
bool getMode (int mode) const;
|
||||
|
||||
/**
|
||||
* Saves the current position and appearence (text color and style) of the cursor.
|
||||
* It can be restored by calling restoreCursor()
|
||||
*/
|
||||
void saveCursor ();
|
||||
/** Restores the position and appearence of the cursor. See saveCursor() */
|
||||
void restoreCursor();
|
||||
|
||||
/** Clear the whole screen, moving the current screen contents into the history first. */
|
||||
void clearEntireScreen();
|
||||
/**
|
||||
* Clear the area of the screen from the current cursor position to the end of
|
||||
* the screen.
|
||||
*/
|
||||
void clearToEndOfScreen();
|
||||
/**
|
||||
* Clear the area of the screen from the current cursor position to the start
|
||||
* of the screen.
|
||||
*/
|
||||
void clearToBeginOfScreen();
|
||||
/** Clears the whole of the line on which the cursor is currently positioned. */
|
||||
void clearEntireLine();
|
||||
/** Clears from the current cursor position to the end of the line. */
|
||||
void clearToEndOfLine();
|
||||
/** Clears from the current cursor position to the beginning of the line. */
|
||||
void clearToBeginOfLine();
|
||||
|
||||
/** Fills the entire screen with the letter 'E' */
|
||||
void helpAlign ();
|
||||
|
||||
/**
|
||||
* Enables the given @p rendition flag. Rendition flags control the appearence
|
||||
* of characters on the screen.
|
||||
*
|
||||
* @see Character::rendition
|
||||
*/
|
||||
void setRendition (int rendition);
|
||||
/**
|
||||
* Disables the given @p rendition flag. Rendition flags control the appearence
|
||||
* of characters on the screen.
|
||||
*
|
||||
* @see Character::rendition
|
||||
*/
|
||||
void resetRendition(int rendition);
|
||||
|
||||
/**
|
||||
* Sets the cursor's foreground color.
|
||||
* @param space The color space used by the @p color argument
|
||||
* @param color The new foreground color. The meaning of this depends on
|
||||
* the color @p space used.
|
||||
*
|
||||
* @see CharacterColor
|
||||
*/
|
||||
void setForeColor (int space, int color);
|
||||
/**
|
||||
* Sets the cursor's background color.
|
||||
* @param space The color space used by the @p color argumnet.
|
||||
* @param color The new background color. The meaning of this depends on
|
||||
* the color @p space used.
|
||||
*
|
||||
* @see CharacterColor
|
||||
*/
|
||||
void setBackColor (int space, int color);
|
||||
/**
|
||||
* Resets the cursor's color back to the default and sets the
|
||||
* character's rendition flags back to the default settings.
|
||||
*/
|
||||
void setDefaultRendition();
|
||||
|
||||
/** Returns the column which the cursor is positioned at. */
|
||||
int getCursorX() const;
|
||||
/** Returns the line which the cursor is positioned on. */
|
||||
int getCursorY() const;
|
||||
|
||||
/** TODO Document me */
|
||||
void clear();
|
||||
/**
|
||||
* Sets the position of the cursor to the 'home' position at the top-left
|
||||
* corner of the screen (0,0)
|
||||
*/
|
||||
void home();
|
||||
/**
|
||||
* Resets the state of the screen. This resets the various screen modes
|
||||
* back to their default states. The cursor style and colors are reset
|
||||
* (as if setDefaultRendition() had been called)
|
||||
*
|
||||
* <ul>
|
||||
* <li>Line wrapping is enabled.</li>
|
||||
* <li>Origin mode is disabled.</li>
|
||||
* <li>Insert mode is disabled.</li>
|
||||
* <li>Cursor mode is enabled. TODO Document me</li>
|
||||
* <li>Screen mode is disabled. TODO Document me</li>
|
||||
* <li>New line mode is disabled. TODO Document me</li>
|
||||
* </ul>
|
||||
*
|
||||
* If @p clearScreen is true then the screen contents are erased entirely,
|
||||
* otherwise they are unaltered.
|
||||
*/
|
||||
void reset(bool clearScreen = true);
|
||||
|
||||
/**
|
||||
* Displays a new character at the current cursor position.
|
||||
*
|
||||
* If the cursor is currently positioned at the right-edge of the screen and
|
||||
* line wrapping is enabled then the character is added at the start of a new
|
||||
* line below the current one.
|
||||
*
|
||||
* If the MODE_Insert screen mode is currently enabled then the character
|
||||
* is inserted at the current cursor position, otherwise it will replace the
|
||||
* character already at the current cursor position.
|
||||
*/
|
||||
void ShowCharacter(unsigned short c);
|
||||
|
||||
// Do composition with last shown character FIXME: Not implemented yet for KDE 4
|
||||
void compose(const QString& compose);
|
||||
|
||||
/**
|
||||
* Resizes the image to a new fixed size of @p new_lines by @p new_columns.
|
||||
* In the case that @p new_columns is smaller than the current number of columns,
|
||||
* existing lines are not truncated. This prevents characters from being lost
|
||||
* if the terminal display is resized smaller and then larger again.
|
||||
*
|
||||
* (note that in versions of Konsole prior to KDE 4, existing lines were
|
||||
* truncated when making the screen image smaller)
|
||||
*/
|
||||
void resizeImage(int new_lines, int new_columns);
|
||||
|
||||
/**
|
||||
* Returns the current screen image.
|
||||
* The result is an array of Characters of size [getLines()][getColumns()] which
|
||||
* must be freed by the caller after use.
|
||||
*
|
||||
* @param dest Buffer to copy the characters into
|
||||
* @param size Size of @p dest in Characters
|
||||
* @param startLine Index of first line to copy
|
||||
* @param endLine Index of last line to copy
|
||||
*/
|
||||
void getImage( Character* dest , int size , int startLine , int endLine ) const;
|
||||
|
||||
/**
|
||||
* Returns the additional attributes associated with lines in the image.
|
||||
* The most important attribute is LINE_WRAPPED which specifies that the
|
||||
* line is wrapped,
|
||||
* other attributes control the size of characters in the line.
|
||||
*/
|
||||
QVector<LineProperty> getLineProperties( int startLine , int endLine ) const;
|
||||
|
||||
|
||||
/** Return the number of lines. */
|
||||
int getLines() { return lines; }
|
||||
/** Return the number of columns. */
|
||||
int getColumns() { return columns; }
|
||||
/** Return the number of lines in the history buffer. */
|
||||
int getHistLines ();
|
||||
/**
|
||||
* Sets the type of storage used to keep lines in the history.
|
||||
* If @p copyPreviousScroll is true then the contents of the previous
|
||||
* history buffer are copied into the new scroll.
|
||||
*/
|
||||
void setScroll(const HistoryType& , bool copyPreviousScroll = true);
|
||||
/** Returns the type of storage used to keep lines in the history. */
|
||||
const HistoryType& getScroll();
|
||||
/**
|
||||
* Returns true if this screen keeps lines that are scrolled off the screen
|
||||
* in a history buffer.
|
||||
*/
|
||||
bool hasScroll();
|
||||
|
||||
/**
|
||||
* Sets the start of the selection.
|
||||
*
|
||||
* @param column The column index of the first character in the selection.
|
||||
* @param line The line index of the first character in the selection.
|
||||
* @param columnmode True if the selection is in column mode.
|
||||
*/
|
||||
void setSelectionStart(const int column, const int line, const bool columnmode);
|
||||
|
||||
/**
|
||||
* Sets the end of the current selection.
|
||||
*
|
||||
* @param column The column index of the last character in the selection.
|
||||
* @param line The line index of the last character in the selection.
|
||||
*/
|
||||
void setSelectionEnd(const int column, const int line);
|
||||
|
||||
/**
|
||||
* Retrieves the start of the selection or the cursor position if there
|
||||
* is no selection.
|
||||
*/
|
||||
void getSelectionStart(int& column , int& line);
|
||||
|
||||
/**
|
||||
* Retrieves the end of the selection or the cursor position if there
|
||||
* is no selection.
|
||||
*/
|
||||
void getSelectionEnd(int& column , int& line);
|
||||
|
||||
/** Clears the current selection */
|
||||
void clearSelection();
|
||||
|
||||
void setBusySelecting(bool busy) { sel_busy = busy; }
|
||||
|
||||
/**
|
||||
* Returns true if the character at (@p column, @p line) is part of the
|
||||
* current selection.
|
||||
*/
|
||||
bool isSelected(const int column,const int line) const;
|
||||
|
||||
/**
|
||||
* Convenience method. Returns the currently selected text.
|
||||
* @param preserveLineBreaks Specifies whether new line characters should
|
||||
* be inserted into the returned text at the end of each terminal line.
|
||||
*/
|
||||
QString selectedText(bool preserveLineBreaks);
|
||||
|
||||
/**
|
||||
* Copies part of the output to a stream.
|
||||
*
|
||||
* @param decoder A decoder which coverts terminal characters into text
|
||||
* @param from The first line in the history to retrieve
|
||||
* @param to The last line in the history to retrieve
|
||||
*/
|
||||
void writeToStream(TerminalCharacterDecoder* decoder, int from, int to);
|
||||
|
||||
/**
|
||||
* Sets the selection to line @p no in the history and returns
|
||||
* the text of that line from the history buffer.
|
||||
*/
|
||||
QString getHistoryLine(int no);
|
||||
|
||||
/**
|
||||
* Copies the selected characters, set using @see setSelBeginXY and @see setSelExtentXY
|
||||
* into a stream.
|
||||
*
|
||||
* @param decoder A decoder which converts terminal characters into text.
|
||||
* PlainTextDecoder is the most commonly used decoder which coverts characters
|
||||
* into plain text with no formatting.
|
||||
* @param preserveLineBreaks Specifies whether new line characters should
|
||||
* be inserted into the returned text at the end of each terminal line.
|
||||
*/
|
||||
void writeSelectionToStream(TerminalCharacterDecoder* decoder , bool
|
||||
preserveLineBreaks = true);
|
||||
|
||||
/** TODO Document me */
|
||||
void checkSelection(int from, int to);
|
||||
|
||||
/**
|
||||
* Sets or clears an attribute of the current line.
|
||||
*
|
||||
* @param property The attribute to set or clear
|
||||
* Possible properties are:
|
||||
* LINE_WRAPPED: Specifies that the line is wrapped.
|
||||
* LINE_DOUBLEWIDTH: Specifies that the characters in the current line should be double the normal width.
|
||||
* LINE_DOUBLEHEIGHT:Specifies that the characters in the current line should be double the normal height.
|
||||
* Double-height lines are formed of two lines containing the same characters,
|
||||
* with both having the LINE_DOUBLEHEIGHT attribute. This allows other parts of the
|
||||
* code to work on the assumption that all lines are the same height.
|
||||
*
|
||||
* @param enable true to apply the attribute to the current line or false to remove it
|
||||
*/
|
||||
void setLineProperty(LineProperty property , bool enable);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of lines that the image has been scrolled up or down by,
|
||||
* since the last call to resetScrolledLines().
|
||||
*
|
||||
* a positive return value indicates that the image has been scrolled up,
|
||||
* a negative return value indicates that the image has been scrolled down.
|
||||
*/
|
||||
int scrolledLines() const;
|
||||
|
||||
/**
|
||||
* Returns the region of the image which was last scrolled.
|
||||
*
|
||||
* This is the area of the image from the top margin to the
|
||||
* bottom margin when the last scroll occurred.
|
||||
*/
|
||||
QRect lastScrolledRegion() const;
|
||||
|
||||
/**
|
||||
* Resets the count of the number of lines that the image has been scrolled up or down by,
|
||||
* see scrolledLines()
|
||||
*/
|
||||
void resetScrolledLines();
|
||||
|
||||
/**
|
||||
* Returns the number of lines of output which have been
|
||||
* dropped from the history since the last call
|
||||
* to resetDroppedLines()
|
||||
*
|
||||
* If the history is not unlimited then it will drop
|
||||
* the oldest lines of output if new lines are added when
|
||||
* it is full.
|
||||
*/
|
||||
int droppedLines() const;
|
||||
|
||||
/**
|
||||
* Resets the count of the number of lines dropped from
|
||||
* the history.
|
||||
*/
|
||||
void resetDroppedLines();
|
||||
|
||||
/**
|
||||
* Fills the buffer @p dest with @p count instances of the default (ie. blank)
|
||||
* Character style.
|
||||
*/
|
||||
static void fillWithDefaultChar(Character* dest, int count);
|
||||
|
||||
private:
|
||||
|
||||
//copies a line of text from the screen or history into a stream using a
|
||||
//specified character decoder
|
||||
//line - the line number to copy, from 0 (the earliest line in the history) up to
|
||||
// hist->getLines() + lines - 1
|
||||
//start - the first column on the line to copy
|
||||
//count - the number of characters on the line to copy
|
||||
//decoder - a decoder which coverts terminal characters (an Character array) into text
|
||||
//appendNewLine - if true a new line character (\n) is appended to the end of the line
|
||||
void copyLineToStream(int line,
|
||||
int start,
|
||||
int count,
|
||||
TerminalCharacterDecoder* decoder,
|
||||
bool appendNewLine,
|
||||
bool preserveLineBreaks);
|
||||
|
||||
//fills a section of the screen image with the character 'c'
|
||||
//the parameters are specified as offsets from the start of the screen image.
|
||||
//the loc(x,y) macro can be used to generate these values from a column,line pair.
|
||||
void clearImage(int loca, int loce, char c);
|
||||
|
||||
//move screen image between 'sourceBegin' and 'sourceEnd' to 'dest'.
|
||||
//the parameters are specified as offsets from the start of the screen image.
|
||||
//the loc(x,y) macro can be used to generate these values from a column,line pair.
|
||||
void moveImage(int dest, int sourceBegin, int sourceEnd);
|
||||
|
||||
void scrollUp(int from, int i);
|
||||
void scrollDown(int from, int i);
|
||||
|
||||
void addHistLine();
|
||||
|
||||
void initTabStops();
|
||||
|
||||
void effectiveRendition();
|
||||
void reverseRendition(Character& p) const;
|
||||
|
||||
bool isSelectionValid() const;
|
||||
|
||||
// copies 'count' lines from the screen buffer into 'dest',
|
||||
// starting from 'startLine', where 0 is the first line in the screen buffer
|
||||
void copyFromScreen(Character* dest, int startLine, int count) const;
|
||||
// copies 'count' lines from the history buffer into 'dest',
|
||||
// starting from 'startLine', where 0 is the first line in the history
|
||||
void copyFromHistory(Character* dest, int startLine, int count) const;
|
||||
|
||||
|
||||
// screen image ----------------
|
||||
int lines;
|
||||
int columns;
|
||||
|
||||
typedef QVector<Character> ImageLine; // [0..columns]
|
||||
ImageLine* screenLines; // [lines]
|
||||
|
||||
int _scrolledLines;
|
||||
QRect _lastScrolledRegion;
|
||||
|
||||
int _droppedLines;
|
||||
|
||||
QVarLengthArray<LineProperty,64> lineProperties;
|
||||
|
||||
// history buffer ---------------
|
||||
HistoryScroll *hist;
|
||||
|
||||
// cursor location
|
||||
int cuX;
|
||||
int cuY;
|
||||
|
||||
// cursor color and rendition info
|
||||
CharacterColor cu_fg; // foreground
|
||||
CharacterColor cu_bg; // background
|
||||
quint8 cu_re; // rendition
|
||||
|
||||
// margins ----------------
|
||||
int tmargin; // top margin
|
||||
int bmargin; // bottom margin
|
||||
|
||||
// states ----------------
|
||||
ScreenParm currParm;
|
||||
|
||||
// ----------------------------
|
||||
|
||||
bool* tabstops;
|
||||
|
||||
// selection -------------------
|
||||
int sel_begin; // The first location selected.
|
||||
int sel_TL; // TopLeft Location.
|
||||
int sel_BR; // Bottom Right Location.
|
||||
bool sel_busy; // Busy making a selection.
|
||||
bool columnmode; // Column selection mode
|
||||
|
||||
// effective colors and rendition ------------
|
||||
CharacterColor ef_fg; // These are derived from
|
||||
CharacterColor ef_bg; // the cu_* variables above
|
||||
quint8 ef_re; // to speed up operation
|
||||
|
||||
//
|
||||
// save cursor, rendition & states ------------
|
||||
//
|
||||
|
||||
// cursor location
|
||||
int sa_cuX;
|
||||
int sa_cuY;
|
||||
|
||||
// rendition info
|
||||
quint8 sa_cu_re;
|
||||
CharacterColor sa_cu_fg;
|
||||
CharacterColor sa_cu_bg;
|
||||
|
||||
// last position where we added a character
|
||||
int lastPos;
|
||||
|
||||
// modes
|
||||
ScreenParm saveParm;
|
||||
|
||||
static Character defaultChar;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SCREEN_H
|
@ -0,0 +1,296 @@
|
||||
/*
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ScreenWindow.h"
|
||||
|
||||
// Qt
|
||||
#include <QtCore>
|
||||
|
||||
// Konsole
|
||||
#include "Screen.h"
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
ScreenWindow::ScreenWindow(QObject* parent)
|
||||
: QObject(parent)
|
||||
, _windowBuffer(0)
|
||||
, _windowBufferSize(0)
|
||||
, _bufferNeedsUpdate(true)
|
||||
, _windowLines(1)
|
||||
, _currentLine(0)
|
||||
, _trackOutput(true)
|
||||
, _scrollCount(0)
|
||||
{
|
||||
}
|
||||
ScreenWindow::~ScreenWindow()
|
||||
{
|
||||
delete[] _windowBuffer;
|
||||
}
|
||||
void ScreenWindow::setScreen(Screen* screen)
|
||||
{
|
||||
Q_ASSERT( screen );
|
||||
|
||||
_screen = screen;
|
||||
}
|
||||
|
||||
Screen* ScreenWindow::screen() const
|
||||
{
|
||||
return _screen;
|
||||
}
|
||||
|
||||
Character* ScreenWindow::getImage()
|
||||
{
|
||||
// reallocate internal buffer if the window size has changed
|
||||
int size = windowLines() * windowColumns();
|
||||
if (_windowBuffer == 0 || _windowBufferSize != size)
|
||||
{
|
||||
delete[] _windowBuffer;
|
||||
_windowBufferSize = size;
|
||||
_windowBuffer = new Character[size];
|
||||
_bufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
if (!_bufferNeedsUpdate)
|
||||
return _windowBuffer;
|
||||
|
||||
_screen->getImage(_windowBuffer,size,
|
||||
currentLine(),endWindowLine());
|
||||
|
||||
// this window may look beyond the end of the screen, in which
|
||||
// case there will be an unused area which needs to be filled
|
||||
// with blank characters
|
||||
fillUnusedArea();
|
||||
|
||||
_bufferNeedsUpdate = false;
|
||||
return _windowBuffer;
|
||||
}
|
||||
|
||||
void ScreenWindow::fillUnusedArea()
|
||||
{
|
||||
int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1;
|
||||
int windowEndLine = currentLine() + windowLines() - 1;
|
||||
|
||||
int unusedLines = windowEndLine - screenEndLine;
|
||||
int charsToFill = unusedLines * windowColumns();
|
||||
|
||||
Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill);
|
||||
}
|
||||
|
||||
// return the index of the line at the end of this window, or if this window
|
||||
// goes beyond the end of the screen, the index of the line at the end
|
||||
// of the screen.
|
||||
//
|
||||
// when passing a line number to a Screen method, the line number should
|
||||
// never be more than endWindowLine()
|
||||
//
|
||||
int ScreenWindow::endWindowLine() const
|
||||
{
|
||||
return qMin(currentLine() + windowLines() - 1,
|
||||
lineCount() - 1);
|
||||
}
|
||||
QVector<LineProperty> ScreenWindow::getLineProperties()
|
||||
{
|
||||
QVector<LineProperty> result = _screen->getLineProperties(currentLine(),endWindowLine());
|
||||
|
||||
if (result.count() != windowLines())
|
||||
result.resize(windowLines());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString ScreenWindow::selectedText( bool preserveLineBreaks ) const
|
||||
{
|
||||
return _screen->selectedText( preserveLineBreaks );
|
||||
}
|
||||
|
||||
void ScreenWindow::getSelectionStart( int& column , int& line )
|
||||
{
|
||||
_screen->getSelectionStart(column,line);
|
||||
line -= currentLine();
|
||||
}
|
||||
void ScreenWindow::getSelectionEnd( int& column , int& line )
|
||||
{
|
||||
_screen->getSelectionEnd(column,line);
|
||||
line -= currentLine();
|
||||
}
|
||||
void ScreenWindow::setSelectionStart( int column , int line , bool columnMode )
|
||||
{
|
||||
_screen->setSelectionStart( column , qMin(line + currentLine(),endWindowLine()) , columnMode);
|
||||
|
||||
_bufferNeedsUpdate = true;
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
void ScreenWindow::setSelectionEnd( int column , int line )
|
||||
{
|
||||
_screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) );
|
||||
|
||||
_bufferNeedsUpdate = true;
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
bool ScreenWindow::isSelected( int column , int line )
|
||||
{
|
||||
return _screen->isSelected( column , qMin(line + currentLine(),endWindowLine()) );
|
||||
}
|
||||
|
||||
void ScreenWindow::clearSelection()
|
||||
{
|
||||
_screen->clearSelection();
|
||||
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
void ScreenWindow::setWindowLines(int lines)
|
||||
{
|
||||
Q_ASSERT(lines > 0);
|
||||
_windowLines = lines;
|
||||
}
|
||||
int ScreenWindow::windowLines() const
|
||||
{
|
||||
return _windowLines;
|
||||
}
|
||||
|
||||
int ScreenWindow::windowColumns() const
|
||||
{
|
||||
return _screen->getColumns();
|
||||
}
|
||||
|
||||
int ScreenWindow::lineCount() const
|
||||
{
|
||||
return _screen->getHistLines() + _screen->getLines();
|
||||
}
|
||||
|
||||
int ScreenWindow::columnCount() const
|
||||
{
|
||||
return _screen->getColumns();
|
||||
}
|
||||
|
||||
QPoint ScreenWindow::cursorPosition() const
|
||||
{
|
||||
QPoint position;
|
||||
|
||||
position.setX( _screen->getCursorX() );
|
||||
position.setY( _screen->getCursorY() );
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
int ScreenWindow::currentLine() const
|
||||
{
|
||||
return qBound(0,_currentLine,lineCount()-windowLines());
|
||||
}
|
||||
|
||||
void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount )
|
||||
{
|
||||
if ( mode == ScrollLines )
|
||||
{
|
||||
scrollTo( currentLine() + amount );
|
||||
}
|
||||
else if ( mode == ScrollPages )
|
||||
{
|
||||
scrollTo( currentLine() + amount * ( windowLines() / 2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
bool ScreenWindow::atEndOfOutput() const
|
||||
{
|
||||
return currentLine() == (lineCount()-windowLines());
|
||||
}
|
||||
|
||||
void ScreenWindow::scrollTo( int line )
|
||||
{
|
||||
int maxCurrentLineNumber = lineCount() - windowLines();
|
||||
line = qBound(0,line,maxCurrentLineNumber);
|
||||
|
||||
const int delta = line - _currentLine;
|
||||
_currentLine = line;
|
||||
|
||||
// keep track of number of lines scrolled by,
|
||||
// this can be reset by calling resetScrollCount()
|
||||
_scrollCount += delta;
|
||||
|
||||
_bufferNeedsUpdate = true;
|
||||
|
||||
emit scrolled(_currentLine);
|
||||
}
|
||||
|
||||
void ScreenWindow::setTrackOutput(bool trackOutput)
|
||||
{
|
||||
_trackOutput = trackOutput;
|
||||
}
|
||||
|
||||
bool ScreenWindow::trackOutput() const
|
||||
{
|
||||
return _trackOutput;
|
||||
}
|
||||
|
||||
int ScreenWindow::scrollCount() const
|
||||
{
|
||||
return _scrollCount;
|
||||
}
|
||||
|
||||
void ScreenWindow::resetScrollCount()
|
||||
{
|
||||
_scrollCount = 0;
|
||||
}
|
||||
|
||||
QRect ScreenWindow::scrollRegion() const
|
||||
{
|
||||
bool equalToScreenSize = windowLines() == _screen->getLines();
|
||||
|
||||
if ( atEndOfOutput() && equalToScreenSize )
|
||||
return _screen->lastScrolledRegion();
|
||||
else
|
||||
return QRect(0,0,windowColumns(),windowLines());
|
||||
}
|
||||
|
||||
void ScreenWindow::notifyOutputChanged()
|
||||
{
|
||||
// move window to the bottom of the screen and update scroll count
|
||||
// if this window is currently tracking the bottom of the screen
|
||||
if ( _trackOutput )
|
||||
{
|
||||
_scrollCount -= _screen->scrolledLines();
|
||||
_currentLine = qMax(0,_screen->getHistLines() - (windowLines()-_screen->getLines()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the history is not unlimited then it may
|
||||
// have run out of space and dropped the oldest
|
||||
// lines of output - in this case the screen
|
||||
// window's current line number will need to
|
||||
// be adjusted - otherwise the output will scroll
|
||||
_currentLine = qMax(0,_currentLine -
|
||||
_screen->droppedLines());
|
||||
|
||||
// ensure that the screen window's current position does
|
||||
// not go beyond the bottom of the screen
|
||||
_currentLine = qMin( _currentLine , _screen->getHistLines() );
|
||||
}
|
||||
|
||||
_bufferNeedsUpdate = true;
|
||||
|
||||
emit outputChanged();
|
||||
}
|
||||
|
||||
//#include "moc_ScreenWindow.cpp"
|
@ -0,0 +1,256 @@
|
||||
/*
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SCREENWINDOW_H
|
||||
#define SCREENWINDOW_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QPoint>
|
||||
#include <QtCore/QRect>
|
||||
|
||||
// Konsole
|
||||
#include "Character.h"
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
class Screen;
|
||||
|
||||
/**
|
||||
* Provides a window onto a section of a terminal screen.
|
||||
* This window can then be rendered by a terminal display widget ( TerminalDisplay ).
|
||||
*
|
||||
* To use the screen window, create a new ScreenWindow() instance and associated it with
|
||||
* a terminal screen using setScreen().
|
||||
* Use the scrollTo() method to scroll the window up and down on the screen.
|
||||
* Call the getImage() method to retrieve the character image which is currently visible in the window.
|
||||
*
|
||||
* setTrackOutput() controls whether the window moves to the bottom of the associated screen when new
|
||||
* lines are added to it.
|
||||
*
|
||||
* Whenever the output from the underlying screen is changed, the notifyOutputChanged() slot should
|
||||
* be called. This in turn will update the window's position and emit the outputChanged() signal
|
||||
* if necessary.
|
||||
*/
|
||||
class ScreenWindow : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a new screen window with the given parent.
|
||||
* A screen must be specified by calling setScreen() before calling getImage() or getLineProperties().
|
||||
*
|
||||
* You should not call this constructor directly, instead use the Emulation::createWindow() method
|
||||
* to create a window on the emulation which you wish to view. This allows the emulation
|
||||
* to notify the window when the associated screen has changed and synchronize selection updates
|
||||
* between all views on a session.
|
||||
*/
|
||||
ScreenWindow(QObject* parent = 0);
|
||||
virtual ~ScreenWindow();
|
||||
|
||||
/** Sets the screen which this window looks onto */
|
||||
void setScreen(Screen* screen);
|
||||
/** Returns the screen which this window looks onto */
|
||||
Screen* screen() const;
|
||||
|
||||
/**
|
||||
* Returns the image of characters which are currently visible through this window
|
||||
* onto the screen.
|
||||
*
|
||||
* The buffer is managed by the ScreenWindow instance and does not need to be
|
||||
* deleted by the caller.
|
||||
*/
|
||||
Character* getImage();
|
||||
|
||||
/**
|
||||
* Returns the line attributes associated with the lines of characters which
|
||||
* are currently visible through this window
|
||||
*/
|
||||
QVector<LineProperty> getLineProperties();
|
||||
|
||||
/**
|
||||
* Returns the number of lines which the region of the window
|
||||
* specified by scrollRegion() has been scrolled by since the last call
|
||||
* to resetScrollCount(). scrollRegion() is in most cases the
|
||||
* whole window, but will be a smaller area in, for example, applications
|
||||
* which provide split-screen facilities.
|
||||
*
|
||||
* This is not guaranteed to be accurate, but allows views to optimise
|
||||
* rendering by reducing the amount of costly text rendering that
|
||||
* needs to be done when the output is scrolled.
|
||||
*/
|
||||
int scrollCount() const;
|
||||
|
||||
/**
|
||||
* Resets the count of scrolled lines returned by scrollCount()
|
||||
*/
|
||||
void resetScrollCount();
|
||||
|
||||
/**
|
||||
* Returns the area of the window which was last scrolled, this is
|
||||
* usually the whole window area.
|
||||
*
|
||||
* Like scrollCount(), this is not guaranteed to be accurate,
|
||||
* but allows views to optimise rendering.
|
||||
*/
|
||||
QRect scrollRegion() const;
|
||||
|
||||
/**
|
||||
* Sets the start of the selection to the given @p line and @p column within
|
||||
* the window.
|
||||
*/
|
||||
void setSelectionStart( int column , int line , bool columnMode );
|
||||
/**
|
||||
* Sets the end of the selection to the given @p line and @p column within
|
||||
* the window.
|
||||
*/
|
||||
void setSelectionEnd( int column , int line );
|
||||
/**
|
||||
* Retrieves the start of the selection within the window.
|
||||
*/
|
||||
void getSelectionStart( int& column , int& line );
|
||||
/**
|
||||
* Retrieves the end of the selection within the window.
|
||||
*/
|
||||
void getSelectionEnd( int& column , int& line );
|
||||
/**
|
||||
* Returns true if the character at @p line , @p column is part of the selection.
|
||||
*/
|
||||
bool isSelected( int column , int line );
|
||||
/**
|
||||
* Clears the current selection
|
||||
*/
|
||||
void clearSelection();
|
||||
|
||||
/** Sets the number of lines in the window */
|
||||
void setWindowLines(int lines);
|
||||
/** Returns the number of lines in the window */
|
||||
int windowLines() const;
|
||||
/** Returns the number of columns in the window */
|
||||
int windowColumns() const;
|
||||
|
||||
/** Returns the total number of lines in the screen */
|
||||
int lineCount() const;
|
||||
/** Returns the total number of columns in the screen */
|
||||
int columnCount() const;
|
||||
|
||||
/** Returns the index of the line which is currently at the top of this window */
|
||||
int currentLine() const;
|
||||
|
||||
/**
|
||||
* Returns the position of the cursor
|
||||
* within the window.
|
||||
*/
|
||||
QPoint cursorPosition() const;
|
||||
|
||||
/**
|
||||
* Convenience method. Returns true if the window is currently at the bottom
|
||||
* of the screen.
|
||||
*/
|
||||
bool atEndOfOutput() const;
|
||||
|
||||
/** Scrolls the window so that @p line is at the top of the window */
|
||||
void scrollTo( int line );
|
||||
|
||||
enum RelativeScrollMode
|
||||
{
|
||||
ScrollLines,
|
||||
ScrollPages
|
||||
};
|
||||
|
||||
/**
|
||||
* Scrolls the window relative to its current position on the screen.
|
||||
*
|
||||
* @param mode Specifies whether @p amount refers to the number of lines or the number
|
||||
* of pages to scroll.
|
||||
* @param amount The number of lines or pages ( depending on @p mode ) to scroll by. If
|
||||
* this number is positive, the view is scrolled down. If this number is negative, the view
|
||||
* is scrolled up.
|
||||
*/
|
||||
void scrollBy( RelativeScrollMode mode , int amount );
|
||||
|
||||
/**
|
||||
* Specifies whether the window should automatically move to the bottom
|
||||
* of the screen when new output is added.
|
||||
*
|
||||
* If this is set to true, the window will be moved to the bottom of the associated screen ( see
|
||||
* screen() ) when the notifyOutputChanged() method is called.
|
||||
*/
|
||||
void setTrackOutput(bool trackOutput);
|
||||
/**
|
||||
* Returns whether the window automatically moves to the bottom of the screen as
|
||||
* new output is added. See setTrackOutput()
|
||||
*/
|
||||
bool trackOutput() const;
|
||||
|
||||
/**
|
||||
* Returns the text which is currently selected.
|
||||
*
|
||||
* @param preserveLineBreaks See Screen::selectedText()
|
||||
*/
|
||||
QString selectedText( bool preserveLineBreaks ) const;
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* Notifies the window that the contents of the associated terminal screen have changed.
|
||||
* This moves the window to the bottom of the screen if trackOutput() is true and causes
|
||||
* the outputChanged() signal to be emitted.
|
||||
*/
|
||||
void notifyOutputChanged();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* Emitted when the contents of the associated terminal screen ( see screen() ) changes.
|
||||
*/
|
||||
void outputChanged();
|
||||
|
||||
/**
|
||||
* Emitted when the screen window is scrolled to a different position.
|
||||
*
|
||||
* @param line The line which is now at the top of the window.
|
||||
*/
|
||||
void scrolled(int line);
|
||||
|
||||
/**
|
||||
* Emitted when the selection is changed.
|
||||
*/
|
||||
void selectionChanged();
|
||||
|
||||
private:
|
||||
int endWindowLine() const;
|
||||
void fillUnusedArea();
|
||||
|
||||
Screen* _screen; // see setScreen() , screen()
|
||||
Character* _windowBuffer;
|
||||
int _windowBufferSize;
|
||||
bool _bufferNeedsUpdate;
|
||||
|
||||
int _windowLines;
|
||||
int _currentLine; // see scrollTo() , currentLine()
|
||||
bool _trackOutput; // see setTrackOutput() , trackOutput()
|
||||
int _scrollCount; // count of lines which the window has been scrolled by since
|
||||
// the last call to resetScrollCount()
|
||||
};
|
||||
|
||||
}
|
||||
#endif // SCREENWINDOW_H
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,621 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SESSION_H
|
||||
#define SESSION_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore>
|
||||
#include <QWidget>
|
||||
|
||||
// Konsole
|
||||
#include "History.h"
|
||||
|
||||
class KProcess;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
class Emulation;
|
||||
class Pty;
|
||||
class TerminalDisplay;
|
||||
//class ZModemDialog;
|
||||
|
||||
/**
|
||||
* Represents a terminal session consisting of a pseudo-teletype and a terminal emulation.
|
||||
* The pseudo-teletype (or PTY) handles I/O between the terminal process and Konsole.
|
||||
* The terminal emulation ( Emulation and subclasses ) processes the output stream from the
|
||||
* PTY and produces a character image which is then shown on views connected to the session.
|
||||
*
|
||||
* Each Session can be connected to one or more views by using the addView() method.
|
||||
* The attached views can then display output from the program running in the terminal
|
||||
* or send input to the program in the terminal in the form of keypresses and mouse
|
||||
* activity.
|
||||
*/
|
||||
class Session : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_PROPERTY(QString name READ nameTitle)
|
||||
Q_PROPERTY(int processId READ processId)
|
||||
Q_PROPERTY(QString keyBindings READ keyBindings WRITE setKeyBindings)
|
||||
Q_PROPERTY(QSize size READ size WRITE setSize)
|
||||
|
||||
/**
|
||||
* Constructs a new session.
|
||||
*
|
||||
* To start the terminal process, call the run() method,
|
||||
* after specifying the program and arguments
|
||||
* using setProgram() and setArguments()
|
||||
*
|
||||
* If no program or arguments are specified explicitly, the Session
|
||||
* falls back to using the program specified in the SHELL environment
|
||||
* variable.
|
||||
*/
|
||||
Session();
|
||||
~Session();
|
||||
|
||||
/**
|
||||
* Returns true if the session is currently running. This will be true
|
||||
* after run() has been called successfully.
|
||||
*/
|
||||
bool isRunning() const;
|
||||
|
||||
/**
|
||||
* Sets the profile associated with this session.
|
||||
*
|
||||
* @param profileKey A key which can be used to obtain the current
|
||||
* profile settings from the SessionManager
|
||||
*/
|
||||
void setProfileKey(const QString& profileKey);
|
||||
/**
|
||||
* Returns the profile key associated with this session.
|
||||
* This can be passed to the SessionManager to obtain the current
|
||||
* profile settings.
|
||||
*/
|
||||
QString profileKey() const;
|
||||
|
||||
/**
|
||||
* Adds a new view for this session.
|
||||
*
|
||||
* The viewing widget will display the output from the terminal and
|
||||
* input from the viewing widget (key presses, mouse activity etc.)
|
||||
* will be sent to the terminal.
|
||||
*
|
||||
* Views can be removed using removeView(). The session is automatically
|
||||
* closed when the last view is removed.
|
||||
*/
|
||||
void addView(TerminalDisplay* widget);
|
||||
/**
|
||||
* Removes a view from this session. When the last view is removed,
|
||||
* the session will be closed automatically.
|
||||
*
|
||||
* @p widget will no longer display output from or send input
|
||||
* to the terminal
|
||||
*/
|
||||
void removeView(TerminalDisplay* widget);
|
||||
|
||||
/**
|
||||
* Returns the views connected to this session
|
||||
*/
|
||||
QList<TerminalDisplay*> views() const;
|
||||
|
||||
/**
|
||||
* Returns the terminal emulation instance being used to encode / decode
|
||||
* characters to / from the process.
|
||||
*/
|
||||
Emulation* emulation() const;
|
||||
|
||||
/**
|
||||
* Returns the environment of this session as a list of strings like
|
||||
* VARIABLE=VALUE
|
||||
*/
|
||||
QStringList environment() const;
|
||||
/**
|
||||
* Sets the environment for this session.
|
||||
* @p environment should be a list of strings like
|
||||
* VARIABLE=VALUE
|
||||
*/
|
||||
void setEnvironment(const QStringList& environment);
|
||||
|
||||
/** Returns the unique ID for this session. */
|
||||
int sessionId() const;
|
||||
|
||||
/**
|
||||
* Return the session title set by the user (ie. the program running
|
||||
* in the terminal), or an empty string if the user has not set a custom title
|
||||
*/
|
||||
QString userTitle() const;
|
||||
|
||||
/**
|
||||
* This enum describes the contexts for which separate
|
||||
* tab title formats may be specified.
|
||||
*/
|
||||
enum TabTitleContext
|
||||
{
|
||||
/** Default tab title format */
|
||||
LocalTabTitle,
|
||||
/**
|
||||
* Tab title format used session currently contains
|
||||
* a connection to a remote computer (via SSH)
|
||||
*/
|
||||
RemoteTabTitle
|
||||
};
|
||||
/**
|
||||
* Sets the format used by this session for tab titles.
|
||||
*
|
||||
* @param context The context whoose format should be set.
|
||||
* @param format The tab title format. This may be a mixture
|
||||
* of plain text and dynamic elements denoted by a '%' character
|
||||
* followed by a letter. (eg. %d for directory). The dynamic
|
||||
* elements available depend on the @p context
|
||||
*/
|
||||
void setTabTitleFormat(TabTitleContext context , const QString& format);
|
||||
/** Returns the format used by this session for tab titles. */
|
||||
QString tabTitleFormat(TabTitleContext context) const;
|
||||
|
||||
|
||||
/** Returns the arguments passed to the shell process when run() is called. */
|
||||
QStringList arguments() const;
|
||||
/** Returns the program name of the shell process started when run() is called. */
|
||||
QString program() const;
|
||||
|
||||
/**
|
||||
* Sets the command line arguments which the session's program will be passed when
|
||||
* run() is called.
|
||||
*/
|
||||
void setArguments(const QStringList& arguments);
|
||||
/** Sets the program to be executed when run() is called. */
|
||||
void setProgram(const QString& program);
|
||||
|
||||
/** Returns the session's current working directory. */
|
||||
QString initialWorkingDirectory() { return _initialWorkingDir; }
|
||||
|
||||
/**
|
||||
* Sets the initial working directory for the session when it is run
|
||||
* This has no effect once the session has been started.
|
||||
*/
|
||||
void setInitialWorkingDirectory( const QString& dir );
|
||||
|
||||
/**
|
||||
* Sets the type of history store used by this session.
|
||||
* Lines of output produced by the terminal are added
|
||||
* to the history store. The type of history store
|
||||
* used affects the number of lines which can be
|
||||
* remembered before they are lost and the storage
|
||||
* (in memory, on-disk etc.) used.
|
||||
*/
|
||||
void setHistoryType(const HistoryType& type);
|
||||
/**
|
||||
* Returns the type of history store used by this session.
|
||||
*/
|
||||
const HistoryType& historyType() const;
|
||||
/**
|
||||
* Clears the history store used by this session.
|
||||
*/
|
||||
void clearHistory();
|
||||
|
||||
/**
|
||||
* Enables monitoring for activity in the session.
|
||||
* This will cause notifySessionState() to be emitted
|
||||
* with the NOTIFYACTIVITY state flag when output is
|
||||
* received from the terminal.
|
||||
*/
|
||||
void setMonitorActivity(bool);
|
||||
/** Returns true if monitoring for activity is enabled. */
|
||||
bool isMonitorActivity() const;
|
||||
|
||||
/**
|
||||
* Enables monitoring for silence in the session.
|
||||
* This will cause notifySessionState() to be emitted
|
||||
* with the NOTIFYSILENCE state flag when output is not
|
||||
* received from the terminal for a certain period of
|
||||
* time, specified with setMonitorSilenceSeconds()
|
||||
*/
|
||||
void setMonitorSilence(bool);
|
||||
/**
|
||||
* Returns true if monitoring for inactivity (silence)
|
||||
* in the session is enabled.
|
||||
*/
|
||||
bool isMonitorSilence() const;
|
||||
/** See setMonitorSilence() */
|
||||
void setMonitorSilenceSeconds(int seconds);
|
||||
|
||||
/**
|
||||
* Sets the key bindings used by this session. The bindings
|
||||
* specify how input key sequences are translated into
|
||||
* the character stream which is sent to the terminal.
|
||||
*
|
||||
* @param id The name of the key bindings to use. The
|
||||
* names of available key bindings can be determined using the
|
||||
* KeyboardTranslatorManager class.
|
||||
*/
|
||||
void setKeyBindings(const QString& id);
|
||||
/** Returns the name of the key bindings used by this session. */
|
||||
QString keyBindings() const;
|
||||
|
||||
/**
|
||||
* This enum describes the available title roles.
|
||||
*/
|
||||
enum TitleRole
|
||||
{
|
||||
/** The name of the session. */
|
||||
NameRole,
|
||||
/** The title of the session which is displayed in tabs etc. */
|
||||
DisplayedTitleRole
|
||||
};
|
||||
|
||||
/** Sets the session's title for the specified @p role to @p title. */
|
||||
void setTitle(TitleRole role , const QString& title);
|
||||
/** Returns the session's title for the specified @p role. */
|
||||
QString title(TitleRole role) const;
|
||||
/** Convenience method used to read the name property. Returns title(Session::NameRole). */
|
||||
QString nameTitle() const { return title(Session::NameRole); }
|
||||
|
||||
/** Sets the name of the icon associated with this session. */
|
||||
void setIconName(const QString& iconName);
|
||||
/** Returns the name of the icon associated with this session. */
|
||||
QString iconName() const;
|
||||
|
||||
/** Sets the text of the icon associated with this session. */
|
||||
void setIconText(const QString& iconText);
|
||||
/** Returns the text of the icon associated with this session. */
|
||||
QString iconText() const;
|
||||
|
||||
/** Specifies whether a utmp entry should be created for the pty used by this session. */
|
||||
void setAddToUtmp(bool);
|
||||
|
||||
/** Sends the specified @p signal to the terminal process. */
|
||||
bool sendSignal(int signal);
|
||||
|
||||
/**
|
||||
* Specifies whether to close the session automatically when the terminal
|
||||
* process terminates.
|
||||
*/
|
||||
void setAutoClose(bool b) { _autoClose = b; }
|
||||
|
||||
/**
|
||||
* Sets whether flow control is enabled for this terminal
|
||||
* session.
|
||||
*/
|
||||
void setFlowControlEnabled(bool enabled);
|
||||
|
||||
/** Returns whether flow control is enabled for this terminal session. */
|
||||
bool flowControlEnabled() const;
|
||||
|
||||
/**
|
||||
* Sends @p text to the current foreground terminal program.
|
||||
*/
|
||||
void sendText(const QString& text) const;
|
||||
|
||||
/**
|
||||
* Returns the process id of the terminal process.
|
||||
* This is the id used by the system API to refer to the process.
|
||||
*/
|
||||
int processId() const;
|
||||
|
||||
/**
|
||||
* Returns the process id of the terminal's foreground process.
|
||||
* This is initially the same as processId() but can change
|
||||
* as the user starts other programs inside the terminal.
|
||||
*/
|
||||
int foregroundProcessId() const;
|
||||
|
||||
/** Returns the terminal session's window size in lines and columns. */
|
||||
QSize size();
|
||||
/**
|
||||
* Emits a request to resize the session to accommodate
|
||||
* the specified window size.
|
||||
*
|
||||
* @param size The size in lines and columns to request.
|
||||
*/
|
||||
void setSize(const QSize& size);
|
||||
|
||||
/** Sets the text codec used by this session's terminal emulation. */
|
||||
void setCodec(QTextCodec* codec);
|
||||
|
||||
/**
|
||||
* Sets whether the session has a dark background or not. The session
|
||||
* uses this information to set the COLORFGBG variable in the process's
|
||||
* environment, which allows the programs running in the terminal to determine
|
||||
* whether the background is light or dark and use appropriate colors by default.
|
||||
*
|
||||
* This has no effect once the session is running.
|
||||
*/
|
||||
void setDarkBackground(bool darkBackground);
|
||||
/**
|
||||
* Returns true if the session has a dark background.
|
||||
* See setDarkBackground()
|
||||
*/
|
||||
bool hasDarkBackground() const;
|
||||
|
||||
/**
|
||||
* Attempts to get the shell program to redraw the current display area.
|
||||
* This can be used after clearing the screen, for example, to get the
|
||||
* shell to redraw the prompt line.
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
// void startZModem(const QString &rz, const QString &dir, const QStringList &list);
|
||||
// void cancelZModem();
|
||||
// bool isZModemBusy() { return _zmodemBusy; }
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Starts the terminal session.
|
||||
*
|
||||
* This creates the terminal process and connects the teletype to it.
|
||||
*/
|
||||
void run();
|
||||
|
||||
/**
|
||||
* Closes the terminal session. This sends a hangup signal
|
||||
* (SIGHUP) to the terminal process and causes the done(Session*)
|
||||
* signal to be emitted.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Changes the session title or other customizable aspects of the terminal
|
||||
* emulation display. For a list of what may be changed see the
|
||||
* Emulation::titleChanged() signal.
|
||||
*/
|
||||
void setUserTitle( int, const QString &caption );
|
||||
|
||||
signals:
|
||||
|
||||
/** Emitted when the terminal process starts. */
|
||||
void started();
|
||||
|
||||
/**
|
||||
* Emitted when the terminal process exits.
|
||||
*/
|
||||
void finished();
|
||||
|
||||
/**
|
||||
* Emitted when output is received from the terminal process.
|
||||
*/
|
||||
void receivedData( const QString& text );
|
||||
|
||||
/** Emitted when the session's title has changed. */
|
||||
void titleChanged();
|
||||
|
||||
/** Emitted when the session's profile has changed. */
|
||||
void profileChanged(const QString& profile);
|
||||
|
||||
/**
|
||||
* Emitted when the activity state of this session changes.
|
||||
*
|
||||
* @param state The new state of the session. This may be one
|
||||
* of NOTIFYNORMAL, NOTIFYSILENCE or NOTIFYACTIVITY
|
||||
*/
|
||||
void stateChanged(int state);
|
||||
|
||||
/** Emitted when a bell event occurs in the session. */
|
||||
void bellRequest( const QString& message );
|
||||
|
||||
/**
|
||||
* Requests that the color the text for any tabs associated with
|
||||
* this session should be changed;
|
||||
*
|
||||
* TODO: Document what the parameter does
|
||||
*/
|
||||
void changeTabTextColorRequest(int);
|
||||
|
||||
/**
|
||||
* Requests that the background color of views on this session
|
||||
* should be changed.
|
||||
*/
|
||||
void changeBackgroundColorRequest(const QColor&);
|
||||
|
||||
/** TODO: Document me. */
|
||||
void openUrlRequest(const QString& url);
|
||||
|
||||
/** TODO: Document me. */
|
||||
// void zmodemDetected();
|
||||
|
||||
/**
|
||||
* Emitted when the terminal process requests a change
|
||||
* in the size of the terminal window.
|
||||
*
|
||||
* @param size The requested window size in terms of lines and columns.
|
||||
*/
|
||||
void resizeRequest(const QSize& size);
|
||||
|
||||
/**
|
||||
* Emitted when a profile change command is received from the terminal.
|
||||
*
|
||||
* @param text The text of the command. This is a string of the form
|
||||
* "PropertyName=Value;PropertyName=Value ..."
|
||||
*/
|
||||
void profileChangeCommandReceived(const QString& text);
|
||||
|
||||
/**
|
||||
* Emitted when the flow control state changes.
|
||||
*
|
||||
* @param enabled True if flow control is enabled or false otherwise.
|
||||
*/
|
||||
void flowControlEnabledChanged(bool enabled);
|
||||
|
||||
private slots:
|
||||
void done(int);
|
||||
|
||||
// void fireZModemDetected();
|
||||
|
||||
void onReceiveBlock( const char* buffer, int len );
|
||||
void monitorTimerDone();
|
||||
|
||||
void onViewSizeChange(int height, int width);
|
||||
void onEmulationSizeChange(int lines , int columns);
|
||||
|
||||
void activityStateSet(int);
|
||||
|
||||
//automatically detach views from sessions when view is destroyed
|
||||
void viewDestroyed(QObject* view);
|
||||
|
||||
// void zmodemReadStatus();
|
||||
// void zmodemReadAndSendBlock();
|
||||
// void zmodemRcvBlock(const char *data, int len);
|
||||
// void zmodemFinished();
|
||||
|
||||
private:
|
||||
|
||||
void updateTerminalSize();
|
||||
WId windowId() const;
|
||||
|
||||
int _uniqueIdentifier;
|
||||
|
||||
Pty* _shellProcess;
|
||||
Emulation* _emulation;
|
||||
|
||||
QList<TerminalDisplay*> _views;
|
||||
|
||||
bool _monitorActivity;
|
||||
bool _monitorSilence;
|
||||
bool _notifiedActivity;
|
||||
bool _masterMode;
|
||||
bool _autoClose;
|
||||
bool _wantedClose;
|
||||
QTimer* _monitorTimer;
|
||||
|
||||
int _silenceSeconds;
|
||||
|
||||
QString _nameTitle;
|
||||
QString _displayTitle;
|
||||
QString _userTitle;
|
||||
|
||||
QString _localTabTitleFormat;
|
||||
QString _remoteTabTitleFormat;
|
||||
|
||||
QString _iconName;
|
||||
QString _iconText; // as set by: echo -en '\033]1;IconText\007
|
||||
bool _addToUtmp;
|
||||
bool _flowControl;
|
||||
bool _fullScripting;
|
||||
|
||||
QString _program;
|
||||
QStringList _arguments;
|
||||
|
||||
QStringList _environment;
|
||||
int _sessionId;
|
||||
|
||||
QString _initialWorkingDir;
|
||||
|
||||
// ZModem
|
||||
// bool _zmodemBusy;
|
||||
// KProcess* _zmodemProc;
|
||||
// ZModemDialog* _zmodemProgress;
|
||||
|
||||
// Color/Font Changes by ESC Sequences
|
||||
|
||||
QColor _modifiedBackground; // as set by: echo -en '\033]11;Color\007
|
||||
|
||||
QString _profileKey;
|
||||
|
||||
bool _hasDarkBackground;
|
||||
|
||||
static int lastSessionId;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides a group of sessions which is divided into master and slave sessions.
|
||||
* Activity in master sessions can be propagated to all sessions within the group.
|
||||
* The type of activity which is propagated and method of propagation is controlled
|
||||
* by the masterMode() flags.
|
||||
*/
|
||||
class SessionGroup : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Constructs an empty session group. */
|
||||
SessionGroup();
|
||||
/** Destroys the session group and removes all connections between master and slave sessions. */
|
||||
~SessionGroup();
|
||||
|
||||
/** Adds a session to the group. */
|
||||
void addSession( Session* session );
|
||||
/** Removes a session from the group. */
|
||||
void removeSession( Session* session );
|
||||
|
||||
/** Returns the list of sessions currently in the group. */
|
||||
QList<Session*> sessions() const;
|
||||
|
||||
/**
|
||||
* Sets whether a particular session is a master within the group.
|
||||
* Changes or activity in the group's master sessions may be propagated
|
||||
* to all the sessions in the group, depending on the current masterMode()
|
||||
*
|
||||
* @param session The session whoose master status should be changed.
|
||||
* @param master True to make this session a master or false otherwise
|
||||
*/
|
||||
void setMasterStatus( Session* session , bool master );
|
||||
/** Returns the master status of a session. See setMasterStatus() */
|
||||
bool masterStatus( Session* session ) const;
|
||||
|
||||
/**
|
||||
* This enum describes the options for propagating certain activity or
|
||||
* changes in the group's master sessions to all sessions in the group.
|
||||
*/
|
||||
enum MasterMode
|
||||
{
|
||||
/**
|
||||
* Any input key presses in the master sessions are sent to all
|
||||
* sessions in the group.
|
||||
*/
|
||||
CopyInputToAll = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies which activity in the group's master sessions is propagated
|
||||
* to all sessions in the group.
|
||||
*
|
||||
* @param mode A bitwise OR of MasterMode flags.
|
||||
*/
|
||||
void setMasterMode( int mode );
|
||||
/**
|
||||
* Returns a bitwise OR of the active MasterMode flags for this group.
|
||||
* See setMasterMode()
|
||||
*/
|
||||
int masterMode() const;
|
||||
|
||||
private:
|
||||
void connectPair(Session* master , Session* other);
|
||||
void disconnectPair(Session* master , Session* other);
|
||||
void connectAll(bool connect);
|
||||
QList<Session*> masters() const;
|
||||
|
||||
// maps sessions to their master status
|
||||
QHash<Session*,bool> _sessions;
|
||||
|
||||
int _masterMode;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "ShellCommand.h"
|
||||
|
||||
//some versions of gcc(4.3) require explicit include
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
// expands environment variables in 'text'
|
||||
// function copied from kdelibs/kio/kio/kurlcompletion.cpp
|
||||
static bool expandEnv(QString& text);
|
||||
|
||||
ShellCommand::ShellCommand(const QString& fullCommand)
|
||||
{
|
||||
bool inQuotes = false;
|
||||
|
||||
QString builder;
|
||||
|
||||
for ( int i = 0 ; i < fullCommand.count() ; i++ )
|
||||
{
|
||||
QChar ch = fullCommand[i];
|
||||
|
||||
const bool isLastChar = ( i == fullCommand.count() - 1 );
|
||||
const bool isQuote = ( ch == '\'' || ch == '\"' );
|
||||
|
||||
if ( !isLastChar && isQuote )
|
||||
inQuotes = !inQuotes;
|
||||
else
|
||||
{
|
||||
if ( (!ch.isSpace() || inQuotes) && !isQuote )
|
||||
builder.append(ch);
|
||||
|
||||
if ( (ch.isSpace() && !inQuotes) || ( i == fullCommand.count()-1 ) )
|
||||
{
|
||||
_arguments << builder;
|
||||
builder.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ShellCommand::ShellCommand(const QString& command , const QStringList& arguments)
|
||||
{
|
||||
_arguments = arguments;
|
||||
|
||||
if ( !_arguments.isEmpty() )
|
||||
_arguments[0] == command;
|
||||
}
|
||||
QString ShellCommand::fullCommand() const
|
||||
{
|
||||
return _arguments.join(QChar(' '));
|
||||
}
|
||||
QString ShellCommand::command() const
|
||||
{
|
||||
if ( !_arguments.isEmpty() )
|
||||
return _arguments[0];
|
||||
else
|
||||
return QString();
|
||||
}
|
||||
QStringList ShellCommand::arguments() const
|
||||
{
|
||||
return _arguments;
|
||||
}
|
||||
bool ShellCommand::isRootCommand() const
|
||||
{
|
||||
Q_ASSERT(0); // not implemented yet
|
||||
return false;
|
||||
}
|
||||
bool ShellCommand::isAvailable() const
|
||||
{
|
||||
Q_ASSERT(0); // not implemented yet
|
||||
return false;
|
||||
}
|
||||
QStringList ShellCommand::expand(const QStringList& items)
|
||||
{
|
||||
QStringList result;
|
||||
|
||||
foreach( QString item , items )
|
||||
result << expand(item);
|
||||
|
||||
return result;
|
||||
}
|
||||
QString ShellCommand::expand(const QString& text)
|
||||
{
|
||||
QString result = text;
|
||||
expandEnv(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* expandEnv
|
||||
*
|
||||
* Expand environment variables in text. Escaped '$' characters are ignored.
|
||||
* Return true if any variables were expanded
|
||||
*/
|
||||
static bool expandEnv( QString &text )
|
||||
{
|
||||
// Find all environment variables beginning with '$'
|
||||
//
|
||||
int pos = 0;
|
||||
|
||||
bool expanded = false;
|
||||
|
||||
while ( (pos = text.indexOf(QLatin1Char('$'), pos)) != -1 ) {
|
||||
|
||||
// Skip escaped '$'
|
||||
//
|
||||
if ( pos > 0 && text.at(pos-1) == QLatin1Char('\\') ) {
|
||||
pos++;
|
||||
}
|
||||
// Variable found => expand
|
||||
//
|
||||
else {
|
||||
// Find the end of the variable = next '/' or ' '
|
||||
//
|
||||
int pos2 = text.indexOf( QLatin1Char(' '), pos+1 );
|
||||
int pos_tmp = text.indexOf( QLatin1Char('/'), pos+1 );
|
||||
|
||||
if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) )
|
||||
pos2 = pos_tmp;
|
||||
|
||||
if ( pos2 == -1 )
|
||||
pos2 = text.length();
|
||||
|
||||
// Replace if the variable is terminated by '/' or ' '
|
||||
// and defined
|
||||
//
|
||||
if ( pos2 >= 0 ) {
|
||||
int len = pos2 - pos;
|
||||
QString key = text.mid( pos+1, len-1);
|
||||
QString value =
|
||||
QString::fromLocal8Bit( ::getenv(key.toLocal8Bit()) );
|
||||
|
||||
if ( !value.isEmpty() ) {
|
||||
expanded = true;
|
||||
text.replace( pos, len, value );
|
||||
pos = pos + value.length();
|
||||
}
|
||||
else {
|
||||
pos = pos2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return expanded;
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef SHELLCOMMAND_H
|
||||
#define SHELLCOMMAND_H
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
/**
|
||||
* A class to parse and extract information about shell commands.
|
||||
*
|
||||
* ShellCommand can be used to:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Take a command-line (eg "/bin/sh -c /path/to/my/script") and split it
|
||||
* into its component parts (eg. the command "/bin/sh" and the arguments
|
||||
* "-c","/path/to/my/script")
|
||||
* </li>
|
||||
* <li>Take a command and a list of arguments and combine them to
|
||||
* form a complete command line.
|
||||
* </li>
|
||||
* <li>Determine whether the binary specified by a command exists in the
|
||||
* user's PATH.
|
||||
* </li>
|
||||
* <li>Determine whether a command-line specifies the execution of
|
||||
* another command as the root user using su/sudo etc.
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
class ShellCommand
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a ShellCommand from a command line.
|
||||
*
|
||||
* @param fullCommand The command line to parse.
|
||||
*/
|
||||
ShellCommand(const QString& fullCommand);
|
||||
/**
|
||||
* Constructs a ShellCommand with the specified @p command and @p arguments.
|
||||
*/
|
||||
ShellCommand(const QString& command , const QStringList& arguments);
|
||||
|
||||
/** Returns the command. */
|
||||
QString command() const;
|
||||
/** Returns the arguments. */
|
||||
QStringList arguments() const;
|
||||
|
||||
/**
|
||||
* Returns the full command line.
|
||||
*/
|
||||
QString fullCommand() const;
|
||||
|
||||
/** Returns true if this is a root command. */
|
||||
bool isRootCommand() const;
|
||||
/** Returns true if the program specified by @p command() exists. */
|
||||
bool isAvailable() const;
|
||||
|
||||
/** Expands environment variables in @p text .*/
|
||||
static QString expand(const QString& text);
|
||||
|
||||
/** Expands environment variables in each string in @p list. */
|
||||
static QStringList expand(const QStringList& items);
|
||||
|
||||
private:
|
||||
QStringList _arguments;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SHELLCOMMAND_H
|
||||
|
@ -0,0 +1,227 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
|
||||
Copyright (C) 2006 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser 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.
|
||||
*/
|
||||
|
||||
// Own
|
||||
#include "TerminalCharacterDecoder.h"
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QTextStream>
|
||||
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
PlainTextDecoder::PlainTextDecoder()
|
||||
: _output(0)
|
||||
, _includeTrailingWhitespace(true)
|
||||
{
|
||||
|
||||
}
|
||||
void PlainTextDecoder::setTrailingWhitespace(bool enable)
|
||||
{
|
||||
_includeTrailingWhitespace = enable;
|
||||
}
|
||||
bool PlainTextDecoder::trailingWhitespace() const
|
||||
{
|
||||
return _includeTrailingWhitespace;
|
||||
}
|
||||
void PlainTextDecoder::begin(QTextStream* output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
void PlainTextDecoder::end()
|
||||
{
|
||||
_output = 0;
|
||||
}
|
||||
void PlainTextDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
|
||||
)
|
||||
{
|
||||
Q_ASSERT( _output );
|
||||
|
||||
//TODO should we ignore or respect the LINE_WRAPPED line property?
|
||||
|
||||
//note: we build up a QString and send it to the text stream rather writing into the text
|
||||
//stream a character at a time because it is more efficient.
|
||||
//(since QTextStream always deals with QStrings internally anyway)
|
||||
QString plainText;
|
||||
plainText.reserve(count);
|
||||
|
||||
int outputCount = count;
|
||||
|
||||
// if inclusion of trailing whitespace is disabled then find the end of the
|
||||
// line
|
||||
if ( !_includeTrailingWhitespace )
|
||||
{
|
||||
for (int i = count-1 ; i >= 0 ; i--)
|
||||
{
|
||||
if ( characters[i].character != ' ' )
|
||||
break;
|
||||
else
|
||||
outputCount--;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0;i<outputCount;i++)
|
||||
{
|
||||
plainText.append( QChar(characters[i].character) );
|
||||
}
|
||||
|
||||
*_output << plainText;
|
||||
}
|
||||
|
||||
HTMLDecoder::HTMLDecoder() :
|
||||
_output(0)
|
||||
,_colorTable(base_color_table)
|
||||
,_innerSpanOpen(false)
|
||||
,_lastRendition(DEFAULT_RENDITION)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void HTMLDecoder::begin(QTextStream* output)
|
||||
{
|
||||
_output = output;
|
||||
|
||||
QString text;
|
||||
|
||||
//open monospace span
|
||||
openSpan(text,"font-family:monospace");
|
||||
|
||||
*output << text;
|
||||
}
|
||||
|
||||
void HTMLDecoder::end()
|
||||
{
|
||||
Q_ASSERT( _output );
|
||||
|
||||
QString text;
|
||||
|
||||
closeSpan(text);
|
||||
|
||||
*_output << text;
|
||||
|
||||
_output = 0;
|
||||
|
||||
}
|
||||
|
||||
//TODO: Support for LineProperty (mainly double width , double height)
|
||||
void HTMLDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/
|
||||
)
|
||||
{
|
||||
Q_ASSERT( _output );
|
||||
|
||||
QString text;
|
||||
|
||||
int spaceCount = 0;
|
||||
|
||||
for (int i=0;i<count;i++)
|
||||
{
|
||||
QChar ch(characters[i].character);
|
||||
|
||||
//check if appearance of character is different from previous char
|
||||
if ( characters[i].rendition != _lastRendition ||
|
||||
characters[i].foregroundColor != _lastForeColor ||
|
||||
characters[i].backgroundColor != _lastBackColor )
|
||||
{
|
||||
if ( _innerSpanOpen )
|
||||
closeSpan(text);
|
||||
|
||||
_lastRendition = characters[i].rendition;
|
||||
_lastForeColor = characters[i].foregroundColor;
|
||||
_lastBackColor = characters[i].backgroundColor;
|
||||
|
||||
//build up style string
|
||||
QString style;
|
||||
|
||||
if ( _lastRendition & RE_BOLD ||
|
||||
(_colorTable && characters[i].isBold(_colorTable)) )
|
||||
style.append("font-weight:bold;");
|
||||
|
||||
|
||||
if ( _lastRendition & RE_UNDERLINE )
|
||||
style.append("font-decoration:underline;");
|
||||
|
||||
//colours - a colour table must have been defined first
|
||||
if ( _colorTable )
|
||||
{
|
||||
style.append( QString("color:%1;").arg(_lastForeColor.color(_colorTable).name() ) );
|
||||
|
||||
if (!characters[i].isTransparent(_colorTable))
|
||||
{
|
||||
style.append( QString("background-color:%1;").arg(_lastBackColor.color(_colorTable).name() ) );
|
||||
}
|
||||
}
|
||||
|
||||
//open the span with the current style
|
||||
openSpan(text,style);
|
||||
_innerSpanOpen = true;
|
||||
}
|
||||
|
||||
//handle whitespace
|
||||
if (ch.isSpace())
|
||||
spaceCount++;
|
||||
else
|
||||
spaceCount = 0;
|
||||
|
||||
|
||||
//output current character
|
||||
if (spaceCount < 2)
|
||||
{
|
||||
//escape HTML tag characters and just display others as they are
|
||||
if ( ch == '<' )
|
||||
text.append("<");
|
||||
else if (ch == '>')
|
||||
text.append(">");
|
||||
else
|
||||
text.append(ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
text.append(" "); //HTML truncates multiple spaces, so use a space marker instead
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//close any remaining open inner spans
|
||||
if ( _innerSpanOpen )
|
||||
closeSpan(text);
|
||||
|
||||
//start new line
|
||||
text.append("<br>");
|
||||
|
||||
*_output << text;
|
||||
}
|
||||
|
||||
void HTMLDecoder::openSpan(QString& text , const QString& style)
|
||||
{
|
||||
text.append( QString("<span style=\"%1\">").arg(style) );
|
||||
}
|
||||
|
||||
void HTMLDecoder::closeSpan(QString& text)
|
||||
{
|
||||
text.append("</span>");
|
||||
}
|
||||
|
||||
void HTMLDecoder::setColorTable(const ColorEntry* table)
|
||||
{
|
||||
_colorTable = table;
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
|
||||
Copyright (C) 2006-7 by Robert Knight <robertknight@gmail.com>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser 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 Lesser 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.
|
||||
*/
|
||||
|
||||
#ifndef TERMINAL_CHARACTER_DECODER_H
|
||||
#define TERMINAL_CHARACTER_DECODER_H
|
||||
|
||||
#include "Character.h"
|
||||
|
||||
class QTextStream;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
/**
|
||||
* Base class for terminal character decoders
|
||||
*
|
||||
* The decoder converts lines of terminal characters which consist of a unicode character, foreground
|
||||
* and background colours and other appearance-related properties into text strings.
|
||||
*
|
||||
* Derived classes may produce either plain text with no other colour or appearance information, or
|
||||
* they may produce text which incorporates these additional properties.
|
||||
*/
|
||||
class TerminalCharacterDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~TerminalCharacterDecoder() {}
|
||||
|
||||
/** Begin decoding characters. The resulting text is appended to @p output. */
|
||||
virtual void begin(QTextStream* output) = 0;
|
||||
/** End decoding. */
|
||||
virtual void end() = 0;
|
||||
|
||||
/**
|
||||
* Converts a line of terminal characters with associated properties into a text string
|
||||
* and writes the string into an output QTextStream.
|
||||
*
|
||||
* @param characters An array of characters of length @p count.
|
||||
* @param properties Additional properties which affect all characters in the line
|
||||
* @param output The output stream which receives the decoded text
|
||||
*/
|
||||
virtual void decodeLine(const Character* const characters,
|
||||
int count,
|
||||
LineProperty properties) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* A terminal character decoder which produces plain text, ignoring colours and other appearance-related
|
||||
* properties of the original characters.
|
||||
*/
|
||||
class PlainTextDecoder : public TerminalCharacterDecoder
|
||||
{
|
||||
public:
|
||||
PlainTextDecoder();
|
||||
|
||||
/**
|
||||
* Set whether trailing whitespace at the end of lines should be included
|
||||
* in the output.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void setTrailingWhitespace(bool enable);
|
||||
/**
|
||||
* Returns whether trailing whitespace at the end of lines is included
|
||||
* in the output.
|
||||
*/
|
||||
bool trailingWhitespace() const;
|
||||
|
||||
virtual void begin(QTextStream* output);
|
||||
virtual void end();
|
||||
|
||||
virtual void decodeLine(const Character* const characters,
|
||||
int count,
|
||||
LineProperty properties);
|
||||
|
||||
|
||||
private:
|
||||
QTextStream* _output;
|
||||
bool _includeTrailingWhitespace;
|
||||
};
|
||||
|
||||
/**
|
||||
* A terminal character decoder which produces pretty HTML markup
|
||||
*/
|
||||
class HTMLDecoder : public TerminalCharacterDecoder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs an HTML decoder using a default black-on-white color scheme.
|
||||
*/
|
||||
HTMLDecoder();
|
||||
|
||||
/**
|
||||
* Sets the colour table which the decoder uses to produce the HTML colour codes in its
|
||||
* output
|
||||
*/
|
||||
void setColorTable( const ColorEntry* table );
|
||||
|
||||
virtual void decodeLine(const Character* const characters,
|
||||
int count,
|
||||
LineProperty properties);
|
||||
|
||||
virtual void begin(QTextStream* output);
|
||||
virtual void end();
|
||||
|
||||
private:
|
||||
void openSpan(QString& text , const QString& style);
|
||||
void closeSpan(QString& text);
|
||||
|
||||
QTextStream* _output;
|
||||
const ColorEntry* _colorTable;
|
||||
bool _innerSpanOpen;
|
||||
quint8 _lastRendition;
|
||||
CharacterColor _lastForeColor;
|
||||
CharacterColor _lastBackColor;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,754 @@
|
||||
/*
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef TERMINALDISPLAY_H
|
||||
#define TERMINALDISPLAY_H
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QColor>
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
// Konsole
|
||||
#include "Filter.h"
|
||||
#include "Character.h"
|
||||
#include "ColorTables.h"
|
||||
|
||||
class QDrag;
|
||||
class QDragEnterEvent;
|
||||
class QDropEvent;
|
||||
class QLabel;
|
||||
class QTimer;
|
||||
class QEvent;
|
||||
class QFrame;
|
||||
class QGridLayout;
|
||||
class QKeyEvent;
|
||||
class QScrollBar;
|
||||
class QShowEvent;
|
||||
class QHideEvent;
|
||||
class QWidget;
|
||||
|
||||
//class KMenu;
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
extern unsigned short vt100_graphics[32];
|
||||
|
||||
class ScreenWindow;
|
||||
|
||||
/**
|
||||
* A widget which displays output from a terminal emulation and sends input keypresses and mouse activity
|
||||
* to the terminal.
|
||||
*
|
||||
* When the terminal emulation receives new output from the program running in the terminal,
|
||||
* it will update the display by calling updateImage().
|
||||
*
|
||||
* TODO More documentation
|
||||
*/
|
||||
class TerminalDisplay : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Constructs a new terminal display widget with the specified parent. */
|
||||
TerminalDisplay(QWidget *parent=0);
|
||||
virtual ~TerminalDisplay();
|
||||
|
||||
/** Returns the terminal color palette used by the display. */
|
||||
const ColorEntry* colorTable() const;
|
||||
/** Sets the terminal color palette used by the display. */
|
||||
void setColorTable(const ColorEntry table[]);
|
||||
/**
|
||||
* Sets the seed used to generate random colors for the display
|
||||
* (in color schemes that support them).
|
||||
*/
|
||||
void setRandomSeed(uint seed);
|
||||
/**
|
||||
* Returns the seed used to generate random colors for the display
|
||||
* (in color schemes that support them).
|
||||
*/
|
||||
uint randomSeed() const;
|
||||
|
||||
/** Sets the opacity of the terminal display. */
|
||||
void setOpacity(qreal opacity);
|
||||
|
||||
/**
|
||||
* This enum describes the location where the scroll bar is positioned in the display widget.
|
||||
*/
|
||||
enum ScrollBarPosition
|
||||
{
|
||||
/** Do not show the scroll bar. */
|
||||
NoScrollBar=0,
|
||||
/** Show the scroll bar on the left side of the display. */
|
||||
ScrollBarLeft=1,
|
||||
/** Show the scroll bar on the right side of the display. */
|
||||
ScrollBarRight=2
|
||||
};
|
||||
/**
|
||||
* Specifies whether the terminal display has a vertical scroll bar, and if so whether it
|
||||
* is shown on the left or right side of the display.
|
||||
*/
|
||||
void setScrollBarPosition(ScrollBarPosition position);
|
||||
|
||||
/**
|
||||
* Sets the current position and range of the display's scroll bar.
|
||||
*
|
||||
* @param cursor The position of the scroll bar's thumb.
|
||||
* @param lines The maximum value of the scroll bar.
|
||||
*/
|
||||
void setScroll(int cursor, int lines);
|
||||
|
||||
/**
|
||||
* Returns the display's filter chain. When the image for the display is updated,
|
||||
* the text is passed through each filter in the chain. Each filter can define
|
||||
* hotspots which correspond to certain strings (such as URLs or particular words).
|
||||
* Depending on the type of the hotspots created by the filter ( returned by Filter::Hotspot::type() )
|
||||
* the view will draw visual cues such as underlines on mouse-over for links or translucent
|
||||
* rectangles for markers.
|
||||
*
|
||||
* To add a new filter to the view, call:
|
||||
* viewWidget->filterChain()->addFilter( filterObject );
|
||||
*/
|
||||
FilterChain* filterChain() const;
|
||||
|
||||
/**
|
||||
* Updates the filters in the display's filter chain. This will cause
|
||||
* the hotspots to be updated to match the current image.
|
||||
*
|
||||
* WARNING: This function can be expensive depending on the
|
||||
* image size and number of filters in the filterChain()
|
||||
*
|
||||
* TODO - This API does not really allow efficient usage. Revise it so
|
||||
* that the processing can be done in a better way.
|
||||
*
|
||||
* eg:
|
||||
* - Area of interest may be known ( eg. mouse cursor hovering
|
||||
* over an area )
|
||||
*/
|
||||
void processFilters();
|
||||
|
||||
/**
|
||||
* Returns a list of menu actions created by the filters for the content
|
||||
* at the given @p position.
|
||||
*/
|
||||
QList<QAction*> filterActions(const QPoint& position);
|
||||
|
||||
/** Returns true if the cursor is set to blink or false otherwise. */
|
||||
bool blinkingCursor() { return _hasBlinkingCursor; }
|
||||
/** Specifies whether or not the cursor blinks. */
|
||||
void setBlinkingCursor(bool blink);
|
||||
|
||||
void setCtrlDrag(bool enable) { _ctrlDrag=enable; }
|
||||
bool ctrlDrag() { return _ctrlDrag; }
|
||||
|
||||
/**
|
||||
* This enum describes the methods for selecting text when
|
||||
* the user triple-clicks within the display.
|
||||
*/
|
||||
enum TripleClickMode
|
||||
{
|
||||
/** Select the whole line underneath the cursor. */
|
||||
SelectWholeLine,
|
||||
/** Select from the current cursor position to the end of the line. */
|
||||
SelectForwardsFromCursor
|
||||
};
|
||||
/** Sets how the text is selected when the user triple clicks within the display. */
|
||||
void setTripleClickMode(TripleClickMode mode) { _tripleClickMode = mode; }
|
||||
/** See setTripleClickSelectionMode() */
|
||||
TripleClickMode tripleClickMode() { return _tripleClickMode; }
|
||||
|
||||
void setLineSpacing(uint);
|
||||
uint lineSpacing() const;
|
||||
|
||||
void emitSelection(bool useXselection,bool appendReturn);
|
||||
|
||||
/**
|
||||
* This enum describes the available shapes for the keyboard cursor.
|
||||
* See setKeyboardCursorShape()
|
||||
*/
|
||||
enum KeyboardCursorShape
|
||||
{
|
||||
/** A rectangular block which covers the entire area of the cursor character. */
|
||||
BlockCursor,
|
||||
/**
|
||||
* A single flat line which occupies the space at the bottom of the cursor
|
||||
* character's area.
|
||||
*/
|
||||
UnderlineCursor,
|
||||
/**
|
||||
* An cursor shaped like the capital letter 'I', similar to the IBeam
|
||||
* cursor used in Qt/KDE text editors.
|
||||
*/
|
||||
IBeamCursor
|
||||
};
|
||||
/**
|
||||
* Sets the shape of the keyboard cursor. This is the cursor drawn
|
||||
* at the position in the terminal where keyboard input will appear.
|
||||
*
|
||||
* In addition the terminal display widget also has a cursor for
|
||||
* the mouse pointer, which can be set using the QWidget::setCursor()
|
||||
* method.
|
||||
*
|
||||
* Defaults to BlockCursor
|
||||
*/
|
||||
void setKeyboardCursorShape(KeyboardCursorShape shape);
|
||||
/**
|
||||
* Returns the shape of the keyboard cursor. See setKeyboardCursorShape()
|
||||
*/
|
||||
KeyboardCursorShape keyboardCursorShape() const;
|
||||
|
||||
/**
|
||||
* Sets the color used to draw the keyboard cursor.
|
||||
*
|
||||
* The keyboard cursor defaults to using the foreground color of the character
|
||||
* underneath it.
|
||||
*
|
||||
* @param useForegroundColor If true, the cursor color will change to match
|
||||
* the foreground color of the character underneath it as it is moved, in this
|
||||
* case, the @p color parameter is ignored and the color of the character
|
||||
* under the cursor is inverted to ensure that it is still readable.
|
||||
* @param color The color to use to draw the cursor. This is only taken into
|
||||
* account if @p useForegroundColor is false.
|
||||
*/
|
||||
void setKeyboardCursorColor(bool useForegroundColor , const QColor& color);
|
||||
|
||||
/**
|
||||
* Returns the color of the keyboard cursor, or an invalid color if the keyboard
|
||||
* cursor color is set to change according to the foreground color of the character
|
||||
* underneath it.
|
||||
*/
|
||||
QColor keyboardCursorColor() const;
|
||||
|
||||
/**
|
||||
* Returns the number of lines of text which can be displayed in the widget.
|
||||
*
|
||||
* This will depend upon the height of the widget and the current font.
|
||||
* See fontHeight()
|
||||
*/
|
||||
int lines() { return _lines; }
|
||||
/**
|
||||
* Returns the number of characters of text which can be displayed on
|
||||
* each line in the widget.
|
||||
*
|
||||
* This will depend upon the width of the widget and the current font.
|
||||
* See fontWidth()
|
||||
*/
|
||||
int columns() { return _columns; }
|
||||
|
||||
/**
|
||||
* Returns the height of the characters in the font used to draw the text in the display.
|
||||
*/
|
||||
int fontHeight() { return _fontHeight; }
|
||||
/**
|
||||
* Returns the width of the characters in the display.
|
||||
* This assumes the use of a fixed-width font.
|
||||
*/
|
||||
int fontWidth() { return _fontWidth; }
|
||||
|
||||
void setSize(int cols, int lins);
|
||||
void setFixedSize(int cols, int lins);
|
||||
|
||||
// reimplemented
|
||||
QSize sizeHint() const;
|
||||
|
||||
/**
|
||||
* Sets which characters, in addition to letters and numbers,
|
||||
* are regarded as being part of a word for the purposes
|
||||
* of selecting words in the display by double clicking on them.
|
||||
*
|
||||
* The word boundaries occur at the first and last characters which
|
||||
* are either a letter, number, or a character in @p wc
|
||||
*
|
||||
* @param wc An array of characters which are to be considered parts
|
||||
* of a word ( in addition to letters and numbers ).
|
||||
*/
|
||||
void setWordCharacters(const QString& wc);
|
||||
/**
|
||||
* Returns the characters which are considered part of a word for the
|
||||
* purpose of selecting words in the display with the mouse.
|
||||
*
|
||||
* @see setWordCharacters()
|
||||
*/
|
||||
QString wordCharacters() { return _wordCharacters; }
|
||||
|
||||
/**
|
||||
* Sets the type of effect used to alert the user when a 'bell' occurs in the
|
||||
* terminal session.
|
||||
*
|
||||
* The terminal session can trigger the bell effect by calling bell() with
|
||||
* the alert message.
|
||||
*/
|
||||
void setBellMode(int mode);
|
||||
/**
|
||||
* Returns the type of effect used to alert the user when a 'bell' occurs in
|
||||
* the terminal session.
|
||||
*
|
||||
* See setBellMode()
|
||||
*/
|
||||
int bellMode() { return _bellMode; }
|
||||
|
||||
/**
|
||||
* This enum describes the different types of sounds and visual effects which
|
||||
* can be used to alert the user when a 'bell' occurs in the terminal
|
||||
* session.
|
||||
*/
|
||||
enum BellMode
|
||||
{
|
||||
/** A system beep. */
|
||||
SystemBeepBell=0,
|
||||
/**
|
||||
* KDE notification. This may play a sound, show a passive popup
|
||||
* or perform some other action depending on the user's settings.
|
||||
*/
|
||||
NotifyBell=1,
|
||||
/** A silent, visual bell (eg. inverting the display's colors briefly) */
|
||||
VisualBell=2,
|
||||
/** No bell effects */
|
||||
NoBell=3
|
||||
};
|
||||
|
||||
void setSelection(const QString &t);
|
||||
|
||||
/**
|
||||
* Reimplemented. Has no effect. Use setVTFont() to change the font
|
||||
* used to draw characters in the display.
|
||||
*/
|
||||
virtual void setFont(const QFont &);
|
||||
|
||||
/** Returns the font used to draw characters in the display */
|
||||
QFont getVTFont() { return font(); }
|
||||
|
||||
/**
|
||||
* Sets the font used to draw the display. Has no effect if @p font
|
||||
* is larger than the size of the display itself.
|
||||
*/
|
||||
void setVTFont(const QFont& font);
|
||||
|
||||
/**
|
||||
* Specified whether anti-aliasing of text in the terminal display
|
||||
* is enabled or not. Defaults to enabled.
|
||||
*/
|
||||
static void setAntialias( bool antialias ) { _antialiasText = antialias; }
|
||||
/**
|
||||
* Returns true if anti-aliasing of text in the terminal is enabled.
|
||||
*/
|
||||
static bool antialias() { return _antialiasText; }
|
||||
|
||||
/**
|
||||
* Sets whether or not the current height and width of the
|
||||
* terminal in lines and columns is displayed whilst the widget
|
||||
* is being resized.
|
||||
*/
|
||||
void setTerminalSizeHint(bool on) { _terminalSizeHint=on; }
|
||||
/**
|
||||
* Returns whether or not the current height and width of
|
||||
* the terminal in lines and columns is displayed whilst the widget
|
||||
* is being resized.
|
||||
*/
|
||||
bool terminalSizeHint() { return _terminalSizeHint; }
|
||||
/**
|
||||
* Sets whether the terminal size display is shown briefly
|
||||
* after the widget is first shown.
|
||||
*
|
||||
* See setTerminalSizeHint() , isTerminalSizeHint()
|
||||
*/
|
||||
void setTerminalSizeStartup(bool on) { _terminalSizeStartup=on; }
|
||||
|
||||
void setBidiEnabled(bool set) { _bidiEnabled=set; }
|
||||
bool isBidiEnabled() { return _bidiEnabled; }
|
||||
|
||||
/**
|
||||
* Sets the terminal screen section which is displayed in this widget.
|
||||
* When updateImage() is called, the display fetches the latest character image from the
|
||||
* the associated terminal screen window.
|
||||
*
|
||||
* In terms of the model-view paradigm, the ScreenWindow is the model which is rendered
|
||||
* by the TerminalDisplay.
|
||||
*/
|
||||
void setScreenWindow( ScreenWindow* window );
|
||||
/** Returns the terminal screen section which is displayed in this widget. See setScreenWindow() */
|
||||
ScreenWindow* screenWindow() const;
|
||||
|
||||
static bool HAVE_TRANSPARENCY;
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Causes the terminal display to fetch the latest character image from the associated
|
||||
* terminal screen ( see setScreenWindow() ) and redraw the display.
|
||||
*/
|
||||
void updateImage();
|
||||
/**
|
||||
* Causes the terminal display to fetch the latest line status flags from the
|
||||
* associated terminal screen ( see setScreenWindow() ).
|
||||
*/
|
||||
void updateLineProperties();
|
||||
|
||||
/** Copies the selected text to the clipboard. */
|
||||
void copyClipboard();
|
||||
/**
|
||||
* Pastes the content of the clipboard into the
|
||||
* display.
|
||||
*/
|
||||
void pasteClipboard();
|
||||
/**
|
||||
* Pastes the content of the selection into the
|
||||
* display.
|
||||
*/
|
||||
void pasteSelection();
|
||||
|
||||
/**
|
||||
* Changes whether the flow control warning box should be shown when the flow control
|
||||
* stop key (Ctrl+S) are pressed.
|
||||
*/
|
||||
void setFlowControlWarningEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* Causes the widget to display or hide a message informing the user that terminal
|
||||
* output has been suspended (by using the flow control key combination Ctrl+S)
|
||||
*
|
||||
* @param suspended True if terminal output has been suspended and the warning message should
|
||||
* be shown or false to indicate that terminal output has been resumed and that
|
||||
* the warning message should disappear.
|
||||
*/
|
||||
void outputSuspended(bool suspended);
|
||||
|
||||
/**
|
||||
* Sets whether the program whoose output is being displayed in the view
|
||||
* is interested in mouse events.
|
||||
*
|
||||
* If this is set to true, mouse signals will be emitted by the view when the user clicks, drags
|
||||
* or otherwise moves the mouse inside the view.
|
||||
* The user interaction needed to create selections will also change, and the user will be required
|
||||
* to hold down the shift key to create a selection or perform other mouse activities inside the
|
||||
* view area - since the program running in the terminal is being allowed to handle normal mouse
|
||||
* events itself.
|
||||
*
|
||||
* @param usesMouse Set to true if the program running in the terminal is interested in mouse events
|
||||
* or false otherwise.
|
||||
*/
|
||||
void setUsesMouse(bool usesMouse);
|
||||
|
||||
/** See setUsesMouse() */
|
||||
bool usesMouse() const;
|
||||
|
||||
/**
|
||||
* Shows a notification that a bell event has occurred in the terminal.
|
||||
* TODO: More documentation here
|
||||
*/
|
||||
void bell(const QString& message);
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted when the user presses a key whilst the terminal widget has focus.
|
||||
*/
|
||||
void keyPressedSignal(QKeyEvent *e);
|
||||
|
||||
/**
|
||||
* Emitted when the user presses the suspend or resume flow control key combinations
|
||||
*
|
||||
* @param suspend true if the user pressed Ctrl+S (the suspend output key combination) or
|
||||
* false if the user pressed Ctrl+Q (the resume output key combination)
|
||||
*/
|
||||
void flowControlKeyPressed(bool suspend);
|
||||
|
||||
/**
|
||||
* A mouse event occurred.
|
||||
* @param button The mouse button (0 for left button, 1 for middle button, 2 for right button, 3 for release)
|
||||
* @param column The character column where the event occurred
|
||||
* @param line The character row where the event occurred
|
||||
* @param eventType The type of event. 0 for a mouse press / release or 1 for mouse motion
|
||||
*/
|
||||
void mouseSignal(int button, int column, int line, int eventType);
|
||||
void changedFontMetricSignal(int height, int width);
|
||||
void changedContentSizeSignal(int height, int width);
|
||||
|
||||
/**
|
||||
* Emitted when the user right clicks on the display, or right-clicks with the Shift
|
||||
* key held down if usesMouse() is true.
|
||||
*
|
||||
* This can be used to display a context menu.
|
||||
*/
|
||||
void configureRequest( TerminalDisplay*, int state, const QPoint& position );
|
||||
|
||||
void isBusySelecting(bool);
|
||||
void sendStringToEmu(const char*);
|
||||
|
||||
protected:
|
||||
virtual bool event( QEvent * );
|
||||
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
|
||||
virtual void showEvent(QShowEvent*);
|
||||
virtual void hideEvent(QHideEvent*);
|
||||
virtual void resizeEvent(QResizeEvent*);
|
||||
|
||||
virtual void fontChange(const QFont &font);
|
||||
|
||||
virtual void keyPressEvent(QKeyEvent* event);
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent* ev);
|
||||
virtual void mousePressEvent( QMouseEvent* );
|
||||
virtual void mouseReleaseEvent( QMouseEvent* );
|
||||
virtual void mouseMoveEvent( QMouseEvent* );
|
||||
virtual void extendSelection( const QPoint& pos );
|
||||
virtual void wheelEvent( QWheelEvent* );
|
||||
|
||||
virtual bool focusNextPrevChild( bool next );
|
||||
|
||||
// drag and drop
|
||||
virtual void dragEnterEvent(QDragEnterEvent* event);
|
||||
virtual void dropEvent(QDropEvent* event);
|
||||
void doDrag();
|
||||
enum DragState { diNone, diPending, diDragging };
|
||||
|
||||
struct _dragInfo {
|
||||
DragState state;
|
||||
QPoint start;
|
||||
QDrag *dragObject;
|
||||
} dragInfo;
|
||||
|
||||
virtual int charClass(quint16) const;
|
||||
|
||||
void clearImage();
|
||||
|
||||
void mouseTripleClickEvent(QMouseEvent* ev);
|
||||
|
||||
// reimplemented
|
||||
virtual void inputMethodEvent ( QInputMethodEvent* event );
|
||||
virtual QVariant inputMethodQuery( Qt::InputMethodQuery query ) const;
|
||||
|
||||
protected slots:
|
||||
|
||||
void scrollBarPositionChanged(int value);
|
||||
void blinkEvent();
|
||||
void blinkCursorEvent();
|
||||
|
||||
//Renables bell noises and visuals. Used to disable further bells for a short period of time
|
||||
//after emitting the first in a sequence of bell events.
|
||||
void enableBell();
|
||||
|
||||
private slots:
|
||||
|
||||
void swapColorTable();
|
||||
void tripleClickTimeout(); // resets possibleTripleClick
|
||||
|
||||
private:
|
||||
|
||||
// -- Drawing helpers --
|
||||
|
||||
// divides the part of the display specified by 'rect' into
|
||||
// fragments according to their colors and styles and calls
|
||||
// drawTextFragment() to draw the fragments
|
||||
void drawContents(QPainter &paint, const QRect &rect);
|
||||
// draws a section of text, all the text in this section
|
||||
// has a common color and style
|
||||
void drawTextFragment(QPainter& painter, const QRect& rect,
|
||||
const QString& text, const Character* style);
|
||||
// draws the background for a text fragment
|
||||
// if useOpacitySetting is true then the color's alpha value will be set to
|
||||
// the display's transparency (set with setOpacity()), otherwise the background
|
||||
// will be drawn fully opaque
|
||||
void drawBackground(QPainter& painter, const QRect& rect, const QColor& color,
|
||||
bool useOpacitySetting);
|
||||
// draws the cursor character
|
||||
void drawCursor(QPainter& painter, const QRect& rect , const QColor& foregroundColor,
|
||||
const QColor& backgroundColor , bool& invertColors);
|
||||
// draws the characters or line graphics in a text fragment
|
||||
void drawCharacters(QPainter& painter, const QRect& rect, const QString& text,
|
||||
const Character* style, bool invertCharacterColor);
|
||||
// draws a string of line graphics
|
||||
void drawLineCharString(QPainter& painter, int x, int y,
|
||||
const QString& str, const Character* attributes);
|
||||
|
||||
// draws the preedit string for input methods
|
||||
void drawInputMethodPreeditString(QPainter& painter , const QRect& rect);
|
||||
|
||||
// --
|
||||
|
||||
// maps an area in the character image to an area on the widget
|
||||
QRect imageToWidget(const QRect& imageArea) const;
|
||||
|
||||
// maps a point on the widget to the position ( ie. line and column )
|
||||
// of the character at that point.
|
||||
void getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const;
|
||||
|
||||
// the area where the preedit string for input methods will be draw
|
||||
QRect preeditRect() const;
|
||||
|
||||
// shows a notification window in the middle of the widget indicating the terminal's
|
||||
// current size in columns and lines
|
||||
void showResizeNotification();
|
||||
|
||||
// scrolls the image by a number of lines.
|
||||
// 'lines' may be positive ( to scroll the image down )
|
||||
// or negative ( to scroll the image up )
|
||||
// 'region' is the part of the image to scroll - currently only
|
||||
// the top, bottom and height of 'region' are taken into account,
|
||||
// the left and right are ignored.
|
||||
void scrollImage(int lines , const QRect& region);
|
||||
|
||||
void calcGeometry();
|
||||
void propagateSize();
|
||||
void updateImageSize();
|
||||
void makeImage();
|
||||
|
||||
void paintFilters(QPainter& painter);
|
||||
|
||||
// returns a region covering all of the areas of the widget which contain
|
||||
// a hotspot
|
||||
QRegion hotSpotRegion() const;
|
||||
|
||||
// returns the position of the cursor in columns and lines
|
||||
QPoint cursorPosition() const;
|
||||
|
||||
// the window onto the terminal screen which this display
|
||||
// is currently showing.
|
||||
QPointer<ScreenWindow> _screenWindow;
|
||||
|
||||
bool _allowBell;
|
||||
|
||||
QGridLayout* _gridLayout;
|
||||
|
||||
bool _fixedFont; // has fixed pitch
|
||||
int _fontHeight; // height
|
||||
int _fontWidth; // width
|
||||
int _fontAscent; // ascend
|
||||
|
||||
int _leftMargin; // offset
|
||||
int _topMargin; // offset
|
||||
|
||||
int _lines; // the number of lines that can be displayed in the widget
|
||||
int _columns; // the number of columns that can be displayed in the widget
|
||||
|
||||
int _usedLines; // the number of lines that are actually being used, this will be less
|
||||
// than 'lines' if the character image provided with setImage() is smaller
|
||||
// than the maximum image size which can be displayed
|
||||
|
||||
int _usedColumns; // the number of columns that are actually being used, this will be less
|
||||
// than 'columns' if the character image provided with setImage() is smaller
|
||||
// than the maximum image size which can be displayed
|
||||
|
||||
int _contentHeight;
|
||||
int _contentWidth;
|
||||
Character* _image; // [lines][columns]
|
||||
// only the area [usedLines][usedColumns] in the image contains valid data
|
||||
|
||||
int _imageSize;
|
||||
QVector<LineProperty> _lineProperties;
|
||||
|
||||
ColorEntry _colorTable[TABLE_COLORS];
|
||||
uint _randomSeed;
|
||||
|
||||
bool _resizing;
|
||||
bool _terminalSizeHint;
|
||||
bool _terminalSizeStartup;
|
||||
bool _bidiEnabled;
|
||||
bool _mouseMarks;
|
||||
|
||||
QPoint _iPntSel; // initial selection point
|
||||
QPoint _pntSel; // current selection point
|
||||
QPoint _tripleSelBegin; // help avoid flicker
|
||||
int _actSel; // selection state
|
||||
bool _wordSelectionMode;
|
||||
bool _lineSelectionMode;
|
||||
bool _preserveLineBreaks;
|
||||
bool _columnSelectionMode;
|
||||
|
||||
QClipboard* _clipboard;
|
||||
QScrollBar* _scrollBar;
|
||||
ScrollBarPosition _scrollbarLocation;
|
||||
QString _wordCharacters;
|
||||
int _bellMode;
|
||||
|
||||
bool _blinking; // hide text in paintEvent
|
||||
bool _hasBlinker; // has characters to blink
|
||||
bool _cursorBlinking; // hide cursor in paintEvent
|
||||
bool _hasBlinkingCursor; // has blinking cursor enabled
|
||||
bool _ctrlDrag; // require Ctrl key for drag
|
||||
TripleClickMode _tripleClickMode;
|
||||
bool _isFixedSize; //Columns / lines are locked.
|
||||
QTimer* _blinkTimer; // active when hasBlinker
|
||||
QTimer* _blinkCursorTimer; // active when hasBlinkingCursor
|
||||
|
||||
// KMenu* _drop;
|
||||
QString _dropText;
|
||||
int _dndFileCount;
|
||||
|
||||
bool _possibleTripleClick; // is set in mouseDoubleClickEvent and deleted
|
||||
// after QApplication::doubleClickInterval() delay
|
||||
|
||||
|
||||
QLabel* _resizeWidget;
|
||||
QTimer* _resizeTimer;
|
||||
|
||||
bool _flowControlWarningEnabled;
|
||||
|
||||
//widgets related to the warning message that appears when the user presses Ctrl+S to suspend
|
||||
//terminal output - informing them what has happened and how to resume output
|
||||
QLabel* _outputSuspendedLabel;
|
||||
|
||||
uint _lineSpacing;
|
||||
|
||||
bool _colorsInverted; // true during visual bell
|
||||
|
||||
QSize _size;
|
||||
|
||||
QRgb _blendColor;
|
||||
|
||||
// list of filters currently applied to the display. used for links and
|
||||
// search highlight
|
||||
TerminalImageFilterChain* _filterChain;
|
||||
QRect _mouseOverHotspotArea;
|
||||
|
||||
KeyboardCursorShape _cursorShape;
|
||||
|
||||
// custom cursor color. if this is invalid then the foreground
|
||||
// color of the character under the cursor is used
|
||||
QColor _cursorColor;
|
||||
|
||||
|
||||
struct InputMethodData
|
||||
{
|
||||
QString preeditString;
|
||||
QRect previousPreeditRect;
|
||||
};
|
||||
InputMethodData _inputMethodData;
|
||||
|
||||
static bool _antialiasText; // do we antialias or not
|
||||
|
||||
//the delay in milliseconds between redrawing blinking text
|
||||
static const int BLINK_DELAY = 500;
|
||||
static const int DEFAULT_LEFT_MARGIN = 1;
|
||||
static const int DEFAULT_TOP_MARGIN = 1;
|
||||
|
||||
public:
|
||||
static void setTransparencyEnabled(bool enable)
|
||||
{
|
||||
HAVE_TRANSPARENCY = enable;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TERMINALDISPLAY_H
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,192 @@
|
||||
/*
|
||||
This file is part of Konsole, an X terminal.
|
||||
|
||||
Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
|
||||
Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef VT102EMULATION_H
|
||||
#define VT102EMULATION_H
|
||||
|
||||
// Standard Library
|
||||
#include <stdio.h>
|
||||
|
||||
// Qt
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
// Konsole
|
||||
#include "Emulation.h"
|
||||
#include "Screen.h"
|
||||
|
||||
#define MODE_AppScreen (MODES_SCREEN+0)
|
||||
#define MODE_AppCuKeys (MODES_SCREEN+1)
|
||||
#define MODE_AppKeyPad (MODES_SCREEN+2)
|
||||
#define MODE_Mouse1000 (MODES_SCREEN+3)
|
||||
#define MODE_Mouse1001 (MODES_SCREEN+4)
|
||||
#define MODE_Mouse1002 (MODES_SCREEN+5)
|
||||
#define MODE_Mouse1003 (MODES_SCREEN+6)
|
||||
#define MODE_Ansi (MODES_SCREEN+7)
|
||||
#define MODE_total (MODES_SCREEN+8)
|
||||
|
||||
namespace Konsole
|
||||
{
|
||||
|
||||
struct DECpar
|
||||
{
|
||||
bool mode[MODE_total];
|
||||
};
|
||||
|
||||
struct CharCodes
|
||||
{
|
||||
// coding info
|
||||
char charset[4]; //
|
||||
int cu_cs; // actual charset.
|
||||
bool graphic; // Some VT100 tricks
|
||||
bool pound ; // Some VT100 tricks
|
||||
bool sa_graphic; // saved graphic
|
||||
bool sa_pound; // saved pound
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides an xterm compatible terminal emulation based on the DEC VT102 terminal.
|
||||
* A full description of this terminal can be found at http://vt100.net/docs/vt102-ug/
|
||||
*
|
||||
* In addition, various additional xterm escape sequences are supported to provide
|
||||
* features such as mouse input handling.
|
||||
* See http://rtfm.etla.org/xterm/ctlseq.html for a description of xterm's escape
|
||||
* sequences.
|
||||
*
|
||||
*/
|
||||
class Vt102Emulation : public Emulation
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/** Constructs a new emulation */
|
||||
Vt102Emulation();
|
||||
~Vt102Emulation();
|
||||
|
||||
// reimplemented
|
||||
virtual void clearEntireScreen();
|
||||
virtual void reset();
|
||||
|
||||
// reimplemented
|
||||
virtual char getErase() const;
|
||||
|
||||
public slots:
|
||||
|
||||
// reimplemented
|
||||
virtual void sendString(const char*,int length = -1);
|
||||
virtual void sendText(const QString& text);
|
||||
virtual void sendKeyEvent(QKeyEvent*);
|
||||
virtual void sendMouseEvent( int buttons, int column, int line , int eventType );
|
||||
|
||||
protected:
|
||||
// reimplemented
|
||||
virtual void setMode (int mode);
|
||||
virtual void resetMode (int mode);
|
||||
|
||||
// reimplemented
|
||||
virtual void receiveChar(int cc);
|
||||
|
||||
|
||||
private slots:
|
||||
|
||||
//causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates
|
||||
//used to buffer multiple title updates
|
||||
void updateTitle();
|
||||
|
||||
|
||||
private:
|
||||
unsigned short applyCharset(unsigned short c);
|
||||
void setCharset(int n, int cs);
|
||||
void useCharset(int n);
|
||||
void setAndUseCharset(int n, int cs);
|
||||
void saveCursor();
|
||||
void restoreCursor();
|
||||
void resetCharset(int scrno);
|
||||
|
||||
void setMargins(int top, int bottom);
|
||||
//set margins for all screens back to their defaults
|
||||
void setDefaultMargins();
|
||||
|
||||
// returns true if 'mode' is set or false otherwise
|
||||
bool getMode (int mode);
|
||||
// saves the current boolean value of 'mode'
|
||||
void saveMode (int mode);
|
||||
// restores the boolean value of 'mode'
|
||||
void restoreMode(int mode);
|
||||
// resets all modes
|
||||
void resetModes();
|
||||
|
||||
void resetToken();
|
||||
#define MAXPBUF 80
|
||||
void pushToToken(int cc);
|
||||
int pbuf[MAXPBUF]; //FIXME: overflow?
|
||||
int ppos;
|
||||
#define MAXARGS 15
|
||||
void addDigit(int dig);
|
||||
void addArgument();
|
||||
int argv[MAXARGS];
|
||||
int argc;
|
||||
void initTokenizer();
|
||||
int tbl[256];
|
||||
|
||||
void scan_buffer_report(); //FIXME: rename
|
||||
void ReportErrorToken(); //FIXME: rename
|
||||
|
||||
void tau(int code, int p, int q);
|
||||
void XtermHack();
|
||||
|
||||
void reportTerminalType();
|
||||
void reportSecondaryAttributes();
|
||||
void reportStatus();
|
||||
void reportAnswerBack();
|
||||
void reportCursorPosition();
|
||||
void reportTerminalParms(int p);
|
||||
|
||||
void onScrollLock();
|
||||
void scrollLock(const bool lock);
|
||||
|
||||
// clears the screen and resizes it to the specified
|
||||
// number of columns
|
||||
void clearScreenAndSetColumns(int columnCount);
|
||||
|
||||
CharCodes _charset[2];
|
||||
|
||||
DECpar _currParm;
|
||||
DECpar _saveParm;
|
||||
|
||||
//hash table and timer for buffering calls to the session instance
|
||||
//to update the name of the session
|
||||
//or window title.
|
||||
//these calls occur when certain escape sequences are seen in the
|
||||
//output from the terminal
|
||||
QHash<int,QString> _pendingTitleUpdates;
|
||||
QTimer* _titleUpdateTimer;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // VT102EMULATION_H
|
@ -0,0 +1,128 @@
|
||||
# [README.default.Keytab] Buildin Keyboard Table
|
||||
#
|
||||
# To customize your keyboard, copy this file to something
|
||||
# ending with .keytab and change it to meet you needs.
|
||||
# Please read the README.KeyTab and the README.keyboard
|
||||
# in this case.
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
|
||||
keyboard "Default (XFree 4)"
|
||||
|
||||
# --------------------------------------------------------------
|
||||
#
|
||||
# Note that this particular table is a "risc" version made to
|
||||
# ease customization without bothering with obsolete details.
|
||||
# See VT100.keytab for the more hairy stuff.
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
|
||||
# common keys
|
||||
|
||||
key Escape : "\E"
|
||||
|
||||
key Tab -Shift : "\t"
|
||||
key Tab +Shift+Ansi : "\E[Z"
|
||||
key Tab +Shift-Ansi : "\t"
|
||||
key Backtab +Ansi : "\E[Z"
|
||||
key Backtab -Ansi : "\t"
|
||||
|
||||
key Return-Shift-NewLine : "\r"
|
||||
key Return-Shift+NewLine : "\r\n"
|
||||
|
||||
key Return+Shift : "\EOM"
|
||||
|
||||
# Backspace and Delete codes are preserving CTRL-H.
|
||||
|
||||
key Backspace : "\x7f"
|
||||
|
||||
# Arrow keys in VT52 mode
|
||||
# shift up/down are reserved for scrolling.
|
||||
# shift left/right are reserved for switching between tabs (this is hardcoded).
|
||||
|
||||
key Up -Shift-Ansi : "\EA"
|
||||
key Down -Shift-Ansi : "\EB"
|
||||
key Right-Shift-Ansi : "\EC"
|
||||
key Left -Shift-Ansi : "\ED"
|
||||
|
||||
# Arrow keys in ANSI mode with Application - and Normal Cursor Mode)
|
||||
|
||||
key Up -Shift-AnyMod+Ansi+AppCuKeys : "\EOA"
|
||||
key Down -Shift-AnyMod+Ansi+AppCuKeys : "\EOB"
|
||||
key Right -Shift-AnyMod+Ansi+AppCuKeys : "\EOC"
|
||||
key Left -Shift-AnyMod+Ansi+AppCuKeys : "\EOD"
|
||||
|
||||
key Up -Shift-AnyMod+Ansi-AppCuKeys : "\E[A"
|
||||
key Down -Shift-AnyMod+Ansi-AppCuKeys : "\E[B"
|
||||
key Right -Shift-AnyMod+Ansi-AppCuKeys : "\E[C"
|
||||
key Left -Shift-AnyMod+Ansi-AppCuKeys : "\E[D"
|
||||
|
||||
key Up -Shift+AnyMod+Ansi : "\E[1;*A"
|
||||
key Down -Shift+AnyMod+Ansi : "\E[1;*B"
|
||||
key Right -Shift+AnyMod+Ansi : "\E[1;*C"
|
||||
key Left -Shift+AnyMod+Ansi : "\E[1;*D"
|
||||
|
||||
# other grey PC keys
|
||||
|
||||
key Enter+NewLine : "\r\n"
|
||||
key Enter-NewLine : "\r"
|
||||
|
||||
key Home -AnyMod -AppCuKeys : "\E[H"
|
||||
key End -AnyMod -AppCuKeys : "\E[F"
|
||||
key Home -AnyMod +AppCuKeys : "\EOH"
|
||||
key End -AnyMod +AppCuKeys : "\EOF"
|
||||
key Home +AnyMod : "\E[1;*H"
|
||||
key End +AnyMod : "\E[1;*F"
|
||||
|
||||
key Insert -AnyMod : "\E[2~"
|
||||
key Delete -AnyMod : "\E[3~"
|
||||
key Insert +AnyMod : "\E[2;*~"
|
||||
key Delete +AnyMod : "\E[3;*~"
|
||||
|
||||
key Prior -Shift-AnyMod : "\E[5~"
|
||||
key Next -Shift-AnyMod : "\E[6~"
|
||||
key Prior -Shift+AnyMod : "\E[5;*~"
|
||||
key Next -Shift+AnyMod : "\E[6;*~"
|
||||
|
||||
# Function keys
|
||||
key F1 -AnyMod : "\EOP"
|
||||
key F2 -AnyMod : "\EOQ"
|
||||
key F3 -AnyMod : "\EOR"
|
||||
key F4 -AnyMod : "\EOS"
|
||||
key F5 -AnyMod : "\E[15~"
|
||||
key F6 -AnyMod : "\E[17~"
|
||||
key F7 -AnyMod : "\E[18~"
|
||||
key F8 -AnyMod : "\E[19~"
|
||||
key F9 -AnyMod : "\E[20~"
|
||||
key F10 -AnyMod : "\E[21~"
|
||||
key F11 -AnyMod : "\E[23~"
|
||||
key F12 -AnyMod : "\E[24~"
|
||||
|
||||
key F1 +AnyMod : "\EO*P"
|
||||
key F2 +AnyMod : "\EO*Q"
|
||||
key F3 +AnyMod : "\EO*R"
|
||||
key F4 +AnyMod : "\EO*S"
|
||||
key F5 +AnyMod : "\E[15;*~"
|
||||
key F6 +AnyMod : "\E[17;*~"
|
||||
key F7 +AnyMod : "\E[18;*~"
|
||||
key F8 +AnyMod : "\E[19;*~"
|
||||
key F9 +AnyMod : "\E[20;*~"
|
||||
key F10 +AnyMod : "\E[21;*~"
|
||||
key F11 +AnyMod : "\E[23;*~"
|
||||
key F12 +AnyMod : "\E[24;*~"
|
||||
|
||||
# Work around dead keys
|
||||
|
||||
key Space +Control : "\x00"
|
||||
|
||||
# Some keys are used by konsole to cause operations.
|
||||
# The scroll* operations refer to the history buffer.
|
||||
|
||||
key Up +Shift-AppScreen : scrollLineUp
|
||||
key Prior +Shift-AppScreen : scrollPageUp
|
||||
key Down +Shift-AppScreen : scrollLineDown
|
||||
key Next +Shift-AppScreen : scrollPageDown
|
||||
|
||||
key ScrollLock : scrollLock
|
||||
|
||||
# keypad characters are not offered differently by Qt.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,890 @@
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef K3PROCESS_H
|
||||
#define K3PROCESS_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <sys/types.h> // for pid_t
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class QSocketNotifier;
|
||||
class K3ProcessPrivate;
|
||||
class KPty;
|
||||
|
||||
/**
|
||||
* @obsolete Use KProcess and KPtyProcess instead.
|
||||
*
|
||||
* Child process invocation, monitoring and control.
|
||||
* This class works only in the application's main thread.
|
||||
*
|
||||
* <b>General usage and features:</b>\n
|
||||
*
|
||||
* This class allows a KDE application to start child processes without having
|
||||
* to worry about UN*X signal handling issues and zombie process reaping.
|
||||
*
|
||||
* @see K3ProcIO
|
||||
*
|
||||
* Basically, this class distinguishes three different ways of running
|
||||
* child processes:
|
||||
*
|
||||
* @li DontCare -- The child process is invoked and both the child
|
||||
* process and the parent process continue concurrently.
|
||||
*
|
||||
* The process is started in an own session (see setsid(2)).
|
||||
*
|
||||
* @li NotifyOnExit -- The child process is invoked and both the
|
||||
* child and the parent process run concurrently.
|
||||
*
|
||||
* When the child process exits, the K3Process instance
|
||||
* corresponding to it emits the Qt signal processExited().
|
||||
* Since this signal is @em not emitted from within a UN*X
|
||||
* signal handler, arbitrary function calls can be made.
|
||||
*
|
||||
* Be aware: When the K3Process object gets destructed, the child
|
||||
* process will be killed if it is still running!
|
||||
* This means in particular, that it usually makes no sense to use
|
||||
* a K3Process on the stack with NotifyOnExit.
|
||||
*
|
||||
* @li OwnGroup -- like NotifyOnExit, but the child process is started
|
||||
* in an own process group (and an own session, FWIW). The behavior of
|
||||
* kill() changes to killing the whole process group - this makes
|
||||
* this mode useful for implementing primitive job management. It can be
|
||||
* used to work around broken wrapper scripts that don't propagate signals
|
||||
* to the "real" program. However, use this with care, as you disturb the
|
||||
* shell's job management if your program is started from the command line.
|
||||
*
|
||||
* @li Block -- The child process starts and the parent process
|
||||
* is suspended until the child process exits. (@em Really not recommended
|
||||
* for programs with a GUI.)
|
||||
* In this mode the parent can read the child's output, but can't send it any
|
||||
* input.
|
||||
*
|
||||
* K3Process also provides several functions for determining the exit status
|
||||
* and the pid of the child process it represents.
|
||||
*
|
||||
* Furthermore it is possible to supply command-line arguments to the process
|
||||
* in a clean fashion (no null-terminated stringlists and such...)
|
||||
*
|
||||
* A small usage example:
|
||||
* \code
|
||||
* K3Process *proc = new K3Process;
|
||||
*
|
||||
* *proc << "my_executable";
|
||||
* *proc << "These" << "are" << "the" << "command" << "line" << "args";
|
||||
* QApplication::connect(proc, SIGNAL(processExited(K3Process *)),
|
||||
* pointer_to_my_object, SLOT(my_objects_slot(K3Process *)));
|
||||
* proc->start();
|
||||
* \endcode
|
||||
*
|
||||
* This will start "my_executable" with the commandline arguments "These"...
|
||||
*
|
||||
* When the child process exits, the slot will be invoked.
|
||||
*
|
||||
* <b>Communication with the child process:</b>\n
|
||||
*
|
||||
* K3Process supports communication with the child process through
|
||||
* stdin/stdout/stderr.
|
||||
*
|
||||
* The following functions are provided for getting data from the child
|
||||
* process or sending data to the child's stdin (For more information,
|
||||
* have a look at the documentation of each function):
|
||||
*
|
||||
* @li writeStdin()
|
||||
* -- Transmit data to the child process' stdin. When all data was sent, the
|
||||
* signal wroteStdin() is emitted.
|
||||
*
|
||||
* @li When data arrives at stdout or stderr, the signal receivedStdout()
|
||||
* resp. receivedStderr() is emitted.
|
||||
*
|
||||
* @li You can shut down individual communication channels with
|
||||
* closeStdin(), closeStdout(), and closeStderr(), resp.
|
||||
*
|
||||
* @author Christian Czezatke e9025461@student.tuwien.ac.at
|
||||
*
|
||||
**/
|
||||
class K3Process : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Modes in which the communication channels can be opened.
|
||||
*
|
||||
* If communication for more than one channel is required,
|
||||
* the values should be or'ed together, for example to get
|
||||
* communication with stdout as well as with stdin, you would
|
||||
* specify @p Stdin | @p Stdout
|
||||
*
|
||||
*/
|
||||
enum CommunicationFlag {
|
||||
NoCommunication = 0, /**< No communication with the process. */
|
||||
Stdin = 1, /**< Connect to write to the process with writeStdin(). */
|
||||
Stdout = 2, /**< Connect to read from the process' output. */
|
||||
Stderr = 4, /**< Connect to read from the process' stderr. */
|
||||
AllOutput = 6, /**< Connects to all output channels. */
|
||||
All = 7, /**< Connects to all channels. */
|
||||
NoRead = 8, /**< If specified with Stdout, no data is actually read from stdout,
|
||||
* only the signal receivedStdout(int fd, int &len) is emitted. */
|
||||
CTtyOnly = NoRead, /**< Tells setUsePty() to create a PTY for the process
|
||||
* and make it the process' controlling TTY, but does not
|
||||
* redirect any I/O channel to the PTY. */
|
||||
MergedStderr = 16 /**< If specified with Stdout, the process' stderr will be
|
||||
* redirected onto the same file handle as its stdout, i.e.,
|
||||
* all error output will be signalled with receivedStdout().
|
||||
* Don't specify Stderr if you specify MergedStderr. */
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(Communication, CommunicationFlag)
|
||||
|
||||
/**
|
||||
* Run-modes for a child process.
|
||||
*/
|
||||
enum RunMode {
|
||||
/**
|
||||
* The application does not receive notifications from the subprocess when
|
||||
* it is finished or aborted.
|
||||
*/
|
||||
DontCare,
|
||||
/**
|
||||
* The application is notified when the subprocess dies.
|
||||
*/
|
||||
NotifyOnExit,
|
||||
/**
|
||||
* The application is suspended until the started process is finished.
|
||||
*/
|
||||
Block,
|
||||
/**
|
||||
* Same as NotifyOnExit, but the process is run in an own session,
|
||||
* just like with DontCare.
|
||||
*/
|
||||
OwnGroup
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
explicit K3Process( QObject* parent=0L );
|
||||
|
||||
/**
|
||||
*Destructor:
|
||||
*
|
||||
* If the process is running when the destructor for this class
|
||||
* is called, the child process is killed with a SIGKILL, but
|
||||
* only if the run mode is not of type @p DontCare.
|
||||
* Processes started as @p DontCare keep running anyway.
|
||||
*/
|
||||
virtual ~K3Process();
|
||||
|
||||
/**
|
||||
* Sets the executable and the command line argument list for this process.
|
||||
*
|
||||
* For example, doing an "ls -l /usr/local/bin" can be achieved by:
|
||||
* \code
|
||||
* K3Process p;
|
||||
* ...
|
||||
* p << "ls" << "-l" << "/usr/local/bin"
|
||||
* \endcode
|
||||
*
|
||||
* @param arg the argument to add
|
||||
* @return a reference to this K3Process
|
||||
**/
|
||||
K3Process &operator<<(const QString& arg);
|
||||
/**
|
||||
* Similar to previous method, takes a char *, supposed to be in locale 8 bit already.
|
||||
*/
|
||||
K3Process &operator<<(const char * arg);
|
||||
/**
|
||||
* Similar to previous method, takes a QByteArray, supposed to be in locale 8 bit already.
|
||||
* @param arg the argument to add
|
||||
* @return a reference to this K3Process
|
||||
*/
|
||||
K3Process &operator<<(const QByteArray & arg);
|
||||
|
||||
/**
|
||||
* Sets the executable and the command line argument list for this process,
|
||||
* in a single method call, or add a list of arguments.
|
||||
* @param args the arguments to add
|
||||
* @return a reference to this K3Process
|
||||
**/
|
||||
K3Process &operator<<(const QStringList& args);
|
||||
|
||||
/**
|
||||
* Clear a command line argument list that has been set by using
|
||||
* operator<<.
|
||||
*/
|
||||
void clearArguments();
|
||||
|
||||
/**
|
||||
* Starts the process.
|
||||
* For a detailed description of the
|
||||
* various run modes and communication semantics, have a look at the
|
||||
* general description of the K3Process class. Note that if you use
|
||||
* setUsePty( Stdout | Stderr, \<bool\> ), you cannot use Stdout | Stderr
|
||||
* here - instead, use Stdout only to receive the mixed output.
|
||||
*
|
||||
* The following problems could cause this function to
|
||||
* return false:
|
||||
*
|
||||
* @li The process is already running.
|
||||
* @li The command line argument list is empty.
|
||||
* @li The the @p comm parameter is incompatible with the selected pty usage.
|
||||
* @li The starting of the process failed (could not fork).
|
||||
* @li The executable was not found.
|
||||
*
|
||||
* @param runmode The Run-mode for the process.
|
||||
* @param comm Specifies which communication channels should be
|
||||
* established to the child process (stdin/stdout/stderr). By default,
|
||||
* no communication takes place and the respective communication
|
||||
* signals will never get emitted.
|
||||
*
|
||||
* @return true on success, false on error
|
||||
* (see above for error conditions)
|
||||
**/
|
||||
virtual bool start(RunMode runmode = NotifyOnExit,
|
||||
Communication comm = NoCommunication);
|
||||
|
||||
/**
|
||||
* Stop the process (by sending it a signal).
|
||||
*
|
||||
* @param signo The signal to send. The default is SIGTERM.
|
||||
* @return true if the signal was delivered successfully.
|
||||
*/
|
||||
virtual bool kill(int signo = SIGTERM);
|
||||
|
||||
/**
|
||||
* Checks whether the process is running.
|
||||
* @return true if the process is (still) considered to be running
|
||||
*/
|
||||
bool isRunning() const;
|
||||
|
||||
/** Returns the process id of the process.
|
||||
*
|
||||
* If it is called after
|
||||
* the process has exited, it returns the process id of the last
|
||||
* child process that was created by this instance of K3Process.
|
||||
*
|
||||
* Calling it before any child process has been started by this
|
||||
* K3Process instance causes pid() to return 0.
|
||||
* @return the pid of the process or 0 if no process has been started yet.
|
||||
**/
|
||||
pid_t pid() const;
|
||||
|
||||
/**
|
||||
* Suspend processing of data from stdout of the child process.
|
||||
*/
|
||||
void suspend();
|
||||
|
||||
/**
|
||||
* Resume processing of data from stdout of the child process.
|
||||
*/
|
||||
void resume();
|
||||
|
||||
/**
|
||||
* Suspend execution of the current thread until the child process dies
|
||||
* or the timeout hits. This function is not recommended for programs
|
||||
* with a GUI.
|
||||
* @param timeout timeout in seconds. -1 means wait indefinitely.
|
||||
* @return true if the process exited, false if the timeout hit.
|
||||
*/
|
||||
bool wait(int timeout = -1);
|
||||
|
||||
/**
|
||||
* Checks whether the process exited cleanly.
|
||||
*
|
||||
* @return true if the process has already finished and has exited
|
||||
* "voluntarily", ie: it has not been killed by a signal.
|
||||
*/
|
||||
bool normalExit() const;
|
||||
|
||||
/**
|
||||
* Checks whether the process was killed by a signal.
|
||||
*
|
||||
* @return true if the process has already finished and has not exited
|
||||
* "voluntarily", ie: it has been killed by a signal.
|
||||
*/
|
||||
bool signalled() const;
|
||||
|
||||
/**
|
||||
* Checks whether a killed process dumped core.
|
||||
*
|
||||
* @return true if signalled() returns true and the process
|
||||
* dumped core. Note that on systems that don't define the
|
||||
* WCOREDUMP macro, the return value is always false.
|
||||
*/
|
||||
bool coreDumped() const;
|
||||
|
||||
/**
|
||||
* Returns the exit status of the process.
|
||||
*
|
||||
* @return the exit status of the process. Note that this value
|
||||
* is not valid if normalExit() returns false.
|
||||
*/
|
||||
int exitStatus() const;
|
||||
|
||||
/**
|
||||
* Returns the signal the process was killed by.
|
||||
*
|
||||
* @return the signal number that caused the process to exit.
|
||||
* Note that this value is not valid if signalled() returns false.
|
||||
*/
|
||||
int exitSignal() const;
|
||||
|
||||
/**
|
||||
* Transmit data to the child process' stdin.
|
||||
*
|
||||
* This function may return false in the following cases:
|
||||
*
|
||||
* @li The process is not currently running.
|
||||
* This implies that you cannot use this function in Block mode.
|
||||
*
|
||||
* @li Communication to stdin has not been requested in the start() call.
|
||||
*
|
||||
* @li Transmission of data to the child process by a previous call to
|
||||
* writeStdin() is still in progress.
|
||||
*
|
||||
* Please note that the data is sent to the client asynchronously,
|
||||
* so when this function returns, the data might not have been
|
||||
* processed by the child process.
|
||||
* That means that you must not free @p buffer or call writeStdin()
|
||||
* again until either a wroteStdin() signal indicates that the
|
||||
* data has been sent or a processExited() signal shows that
|
||||
* the child process is no longer alive.
|
||||
*
|
||||
* If all the data has been sent to the client, the signal
|
||||
* wroteStdin() will be emitted.
|
||||
*
|
||||
* This function does not work when the process is start()ed in Block mode.
|
||||
*
|
||||
* @param buffer the buffer to write
|
||||
* @param buflen the length of the buffer
|
||||
* @return false if an error has occurred
|
||||
**/
|
||||
bool writeStdin(const char *buffer, int buflen);
|
||||
|
||||
/**
|
||||
* Shuts down the Stdin communication link. If no pty is used, this
|
||||
* causes "EOF" to be indicated on the child's stdin file descriptor.
|
||||
*
|
||||
* @return false if no Stdin communication link exists (any more).
|
||||
*/
|
||||
bool closeStdin();
|
||||
|
||||
/**
|
||||
* Shuts down the Stdout communication link. If no pty is used, any further
|
||||
* attempts by the child to write to its stdout file descriptor will cause
|
||||
* it to receive a SIGPIPE.
|
||||
*
|
||||
* @return false if no Stdout communication link exists (any more).
|
||||
*/
|
||||
bool closeStdout();
|
||||
|
||||
/**
|
||||
* Shuts down the Stderr communication link. If no pty is used, any further
|
||||
* attempts by the child to write to its stderr file descriptor will cause
|
||||
* it to receive a SIGPIPE.
|
||||
*
|
||||
* @return false if no Stderr communication link exists (any more).
|
||||
*/
|
||||
bool closeStderr();
|
||||
|
||||
/**
|
||||
* Deletes the optional utmp entry and closes the pty.
|
||||
*
|
||||
* Make sure to shut down any communication links that are using the pty
|
||||
* before calling this function.
|
||||
*
|
||||
* @return false if the pty is not open (any more).
|
||||
*/
|
||||
bool closePty();
|
||||
|
||||
/**
|
||||
* @brief Close stdin, stdout, stderr and the pty
|
||||
*
|
||||
* This is the same that calling all close* functions in a row:
|
||||
* @see closeStdin, @see closeStdout, @see closeStderr and @see closePty
|
||||
*/
|
||||
void closeAll();
|
||||
|
||||
/**
|
||||
* Lets you see what your arguments are for debugging.
|
||||
* @return the list of arguments
|
||||
*/
|
||||
const QList<QByteArray> &args() /* const */ { return arguments; }
|
||||
|
||||
/**
|
||||
* Controls whether the started process should drop any
|
||||
* setuid/setgid privileges or whether it should keep them.
|
||||
* Note that this function is mostly a dummy, as the KDE libraries
|
||||
* currently refuse to run with setuid/setgid privileges.
|
||||
*
|
||||
* The default is false: drop privileges
|
||||
* @param keepPrivileges true to keep the privileges
|
||||
*/
|
||||
void setRunPrivileged(bool keepPrivileges);
|
||||
|
||||
/**
|
||||
* Returns whether the started process will drop any
|
||||
* setuid/setgid privileges or whether it will keep them.
|
||||
* @return true if the process runs privileged
|
||||
*/
|
||||
bool runPrivileged() const;
|
||||
|
||||
/**
|
||||
* Adds the variable @p name to the process' environment.
|
||||
* This function must be called before starting the process.
|
||||
* @param name the name of the environment variable
|
||||
* @param value the new value for the environment variable
|
||||
*/
|
||||
void setEnvironment(const QString &name, const QString &value);
|
||||
|
||||
/**
|
||||
* Changes the current working directory (CWD) of the process
|
||||
* to be started.
|
||||
* This function must be called before starting the process.
|
||||
* @param dir the new directory
|
||||
*/
|
||||
void setWorkingDirectory(const QString &dir);
|
||||
|
||||
/**
|
||||
* Specify whether to start the command via a shell or directly.
|
||||
* The default is to start the command directly.
|
||||
* If @p useShell is true @p shell will be used as shell, or
|
||||
* if shell is empty, /bin/sh will be used.
|
||||
*
|
||||
* When using a shell, the caller should make sure that all filenames etc.
|
||||
* are properly quoted when passed as argument.
|
||||
* @see quote()
|
||||
* @param useShell true if the command should be started via a shell
|
||||
* @param shell the path to the shell that will execute the process, or
|
||||
* 0 to use /bin/sh. Use getenv("SHELL") to use the user's
|
||||
* default shell, but note that doing so is usually a bad idea
|
||||
* for shell compatibility reasons.
|
||||
*/
|
||||
void setUseShell(bool useShell, const char *shell = 0);
|
||||
|
||||
/**
|
||||
* This function can be used to quote an argument string such that
|
||||
* the shell processes it properly. This is e. g. necessary for
|
||||
* user-provided file names which may contain spaces or quotes.
|
||||
* It also prevents expansion of wild cards and environment variables.
|
||||
* @param arg the argument to quote
|
||||
* @return the quoted argument
|
||||
*/
|
||||
static QString quote(const QString &arg);
|
||||
|
||||
/**
|
||||
* Detaches K3Process from child process. All communication is closed.
|
||||
* No exit notification is emitted any more for the child process.
|
||||
* Deleting the K3Process will no longer kill the child process.
|
||||
* Note that the current process remains the parent process of the
|
||||
* child process.
|
||||
*/
|
||||
void detach();
|
||||
|
||||
/**
|
||||
* Specify whether to create a pty (pseudo-terminal) for running the
|
||||
* command.
|
||||
* This function should be called before starting the process.
|
||||
*
|
||||
* @param comm for which stdio handles to use a pty. Note that it is not
|
||||
* allowed to specify Stdout and Stderr at the same time both here and to
|
||||
* start (there is only one pty, so they cannot be distinguished).
|
||||
* @param addUtmp true if a utmp entry should be created for the pty
|
||||
*/
|
||||
void setUsePty(Communication comm, bool addUtmp);
|
||||
|
||||
/**
|
||||
* Obtains the pty object used by this process. The return value is
|
||||
* valid only after setUsePty() was used with a non-zero argument.
|
||||
* The pty is open only while the process is running.
|
||||
* @return a pointer to the pty object
|
||||
*/
|
||||
KPty *pty() const;
|
||||
|
||||
/**
|
||||
* More or less intuitive constants for use with setPriority().
|
||||
*/
|
||||
enum { PrioLowest = 20, PrioLow = 10, PrioLower = 5, PrioNormal = 0,
|
||||
PrioHigher = -5, PrioHigh = -10, PrioHighest = -19 };
|
||||
|
||||
/**
|
||||
* Sets the scheduling priority of the process.
|
||||
* @param prio the new priority in the range -20 (high) to 19 (low).
|
||||
* @return false on error; see setpriority(2) for possible reasons.
|
||||
*/
|
||||
bool setPriority(int prio);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted after the process has terminated when
|
||||
* the process was run in the @p NotifyOnExit (==default option to
|
||||
* start() ) or the Block mode.
|
||||
* @param proc a pointer to the process that has exited
|
||||
**/
|
||||
void processExited(K3Process *proc);
|
||||
|
||||
|
||||
/**
|
||||
* Emitted, when output from the child process has
|
||||
* been received on stdout.
|
||||
*
|
||||
* To actually get this signal, the Stdout communication link
|
||||
* has to be turned on in start().
|
||||
*
|
||||
* @param proc a pointer to the process that has received the output
|
||||
* @param buffer The data received.
|
||||
* @param buflen The number of bytes that are available.
|
||||
*
|
||||
* You should copy the information contained in @p buffer to your private
|
||||
* data structures before returning from the slot.
|
||||
* Example:
|
||||
* \code
|
||||
* QString myBuf = QLatin1String(buffer, buflen);
|
||||
* \endcode
|
||||
**/
|
||||
void receivedStdout(K3Process *proc, char *buffer, int buflen);
|
||||
|
||||
/**
|
||||
* Emitted when output from the child process has
|
||||
* been received on stdout.
|
||||
*
|
||||
* To actually get this signal, the Stdout communication link
|
||||
* has to be turned on in start() and the
|
||||
* NoRead flag must have been passed.
|
||||
*
|
||||
* You will need to explicitly call resume() after your call to start()
|
||||
* to begin processing data from the child process' stdout. This is
|
||||
* to ensure that this signal is not emitted when no one is connected
|
||||
* to it, otherwise this signal will not be emitted.
|
||||
*
|
||||
* The data still has to be read from file descriptor @p fd.
|
||||
* @param fd the file descriptor that provides the data
|
||||
* @param len the number of bytes that have been read from @p fd must
|
||||
* be written here
|
||||
**/
|
||||
void receivedStdout(int fd, int &len); // KDE4: change, broken API
|
||||
|
||||
|
||||
/**
|
||||
* Emitted, when output from the child process has
|
||||
* been received on stderr.
|
||||
*
|
||||
* To actually get this signal, the Stderr communication link
|
||||
* has to be turned on in start().
|
||||
*
|
||||
* You should copy the information contained in @p buffer to your private
|
||||
* data structures before returning from the slot.
|
||||
*
|
||||
* @param proc a pointer to the process that has received the data
|
||||
* @param buffer The data received.
|
||||
* @param buflen The number of bytes that are available.
|
||||
**/
|
||||
void receivedStderr(K3Process *proc, char *buffer, int buflen);
|
||||
|
||||
/**
|
||||
* Emitted after all the data that has been
|
||||
* specified by a prior call to writeStdin() has actually been
|
||||
* written to the child process.
|
||||
* @param proc a pointer to the process
|
||||
**/
|
||||
void wroteStdin(K3Process *proc);
|
||||
|
||||
|
||||
protected Q_SLOTS:
|
||||
|
||||
/**
|
||||
* This slot gets activated when data from the child's stdout arrives.
|
||||
* It usually calls childOutput().
|
||||
* @param fdno the file descriptor for the output
|
||||
*/
|
||||
void slotChildOutput(int fdno);
|
||||
|
||||
/**
|
||||
* This slot gets activated when data from the child's stderr arrives.
|
||||
* It usually calls childError().
|
||||
* @param fdno the file descriptor for the output
|
||||
*/
|
||||
void slotChildError(int fdno);
|
||||
|
||||
/**
|
||||
* Called when another bulk of data can be sent to the child's
|
||||
* stdin. If there is no more data to be sent to stdin currently
|
||||
* available, this function must disable the QSocketNotifier innot.
|
||||
* @param dummy ignore this argument
|
||||
*/
|
||||
void slotSendData(int dummy); // KDE 4: remove dummy
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Sets up the environment according to the data passed via
|
||||
* setEnvironment()
|
||||
*/
|
||||
void setupEnvironment();
|
||||
|
||||
/**
|
||||
* The list of the process' command line arguments. The first entry
|
||||
* in this list is the executable itself.
|
||||
*/
|
||||
QList<QByteArray> arguments;
|
||||
/**
|
||||
* How to run the process (Block, NotifyOnExit, DontCare). You should
|
||||
* not modify this data member directly from derived classes.
|
||||
*/
|
||||
RunMode run_mode;
|
||||
/**
|
||||
* true if the process is currently running. You should not
|
||||
* modify this data member directly from derived classes. Please use
|
||||
* isRunning() for reading the value of this data member since it
|
||||
* will probably be made private in later versions of K3Process.
|
||||
*/
|
||||
bool runs;
|
||||
|
||||
/**
|
||||
* The PID of the currently running process.
|
||||
* You should not modify this data member in derived classes.
|
||||
* Please use pid() instead of directly accessing this
|
||||
* member since it will probably be made private in
|
||||
* later versions of K3Process.
|
||||
*/
|
||||
pid_t pid_;
|
||||
|
||||
/**
|
||||
* The process' exit status as returned by waitpid(). You should not
|
||||
* modify the value of this data member from derived classes. You should
|
||||
* rather use exitStatus() than accessing this data member directly
|
||||
* since it will probably be made private in further versions of
|
||||
* K3Process.
|
||||
*/
|
||||
int status;
|
||||
|
||||
|
||||
/**
|
||||
* If false, the child process' effective uid & gid will be reset to the
|
||||
* real values.
|
||||
* @see setRunPrivileged()
|
||||
*/
|
||||
bool keepPrivs;
|
||||
|
||||
/**
|
||||
* This function is called from start() right before a fork() takes
|
||||
* place. According to the @p comm parameter this function has to initialize
|
||||
* the in, out and err data members of K3Process.
|
||||
*
|
||||
* This function should return 1 if setting the needed communication channels
|
||||
* was successful.
|
||||
*
|
||||
* The default implementation is to create UNIX STREAM sockets for the
|
||||
* communication, but you could reimplement this function to establish a
|
||||
* TCP/IP communication for network communication, for example.
|
||||
*/
|
||||
virtual int setupCommunication(Communication comm);
|
||||
|
||||
/**
|
||||
* Called right after a (successful) fork() on the parent side. This function
|
||||
* will usually do some communications cleanup, like closing in[0],
|
||||
* out[1] and out[1].
|
||||
*
|
||||
* Furthermore, it must also create the QSocketNotifiers innot,
|
||||
* outnot and errnot and connect their Qt signals to the respective
|
||||
* K3Process slots.
|
||||
*
|
||||
* For a more detailed explanation, it is best to have a look at the default
|
||||
* implementation in kprocess.cpp.
|
||||
*/
|
||||
virtual int commSetupDoneP();
|
||||
|
||||
/**
|
||||
* Called right after a (successful) fork(), but before an exec() on the child
|
||||
* process' side. It usually duplicates the in[0], out[1] and
|
||||
* err[1] file handles to the respective standard I/O handles.
|
||||
*/
|
||||
virtual int commSetupDoneC();
|
||||
|
||||
|
||||
/**
|
||||
* Immediately called after a successfully started process in NotifyOnExit
|
||||
* mode has exited. This function normally calls commClose()
|
||||
* and emits the processExited() signal.
|
||||
* @param state the exit code of the process as returned by waitpid()
|
||||
*/
|
||||
virtual void processHasExited(int state);
|
||||
|
||||
/**
|
||||
* Cleans up the communication links to the child after it has exited.
|
||||
* This function should act upon the values of pid() and runs.
|
||||
* See the kprocess.cpp source for details.
|
||||
* @li If pid() returns zero, the communication links should be closed
|
||||
* only.
|
||||
* @li if pid() returns non-zero and runs is false, all data
|
||||
* immediately available from the communication links should be processed
|
||||
* before closing them.
|
||||
* @li if pid() returns non-zero and runs is true, the communication
|
||||
* links should be monitored for data until the file handle returned by
|
||||
* K3ProcessController::theKProcessController->notifierFd() becomes ready
|
||||
* for reading - when it triggers, runs should be reset to false, and
|
||||
* the function should be immediately left without closing anything.
|
||||
*
|
||||
* The previous semantics of this function are forward-compatible, but should
|
||||
* be avoided, as they are prone to race conditions and can cause K3Process
|
||||
* (and thus the whole program) to lock up under certain circumstances. At the
|
||||
* end the function closes the communication links in any case. Additionally
|
||||
* @li if runs is true, the communication links are monitored for data
|
||||
* until all of them have returned EOF. Note that if any system function is
|
||||
* interrupted (errno == EINTR) the polling loop should be aborted.
|
||||
* @li if runs is false, all data immediately available from the
|
||||
* communication links is processed.
|
||||
*/
|
||||
virtual void commClose();
|
||||
|
||||
/* KDE 4 - commClose will be changed to perform cleanup only in all cases *
|
||||
* If @p notfd is -1, all data immediately available from the
|
||||
* communication links should be processed.
|
||||
* If @p notfd is not -1, the communication links should be monitored
|
||||
* for data until the file handle @p notfd becomes ready for reading.
|
||||
*/
|
||||
// virtual void commDrain(int notfd);
|
||||
|
||||
/**
|
||||
* Specify the actual executable that should be started (first argument to execve)
|
||||
* Normally the the first argument is the executable but you can
|
||||
* override that with this function.
|
||||
*/
|
||||
void setBinaryExecutable(const char *filename);
|
||||
|
||||
/**
|
||||
* The socket descriptors for stdout.
|
||||
*/
|
||||
int out[2];
|
||||
/**
|
||||
* The socket descriptors for stdin.
|
||||
*/
|
||||
int in[2];
|
||||
/**
|
||||
* The socket descriptors for stderr.
|
||||
*/
|
||||
int err[2];
|
||||
|
||||
/**
|
||||
* The socket notifier for in[1].
|
||||
*/
|
||||
QSocketNotifier *innot;
|
||||
/**
|
||||
* The socket notifier for out[0].
|
||||
*/
|
||||
QSocketNotifier *outnot;
|
||||
/**
|
||||
* The socket notifier for err[0].
|
||||
*/
|
||||
QSocketNotifier *errnot;
|
||||
|
||||
/**
|
||||
* Lists the communication links that are activated for the child
|
||||
* process. Should not be modified from derived classes.
|
||||
*/
|
||||
Communication communication;
|
||||
|
||||
/**
|
||||
* Called by slotChildOutput() this function copies data arriving from
|
||||
* the child process' stdout to the respective buffer and emits the signal
|
||||
* receivedStdout().
|
||||
*/
|
||||
int childOutput(int fdno);
|
||||
|
||||
/**
|
||||
* Called by slotChildError() this function copies data arriving from
|
||||
* the child process' stderr to the respective buffer and emits the signal
|
||||
* receivedStderr().
|
||||
*/
|
||||
int childError(int fdno);
|
||||
|
||||
/**
|
||||
* The buffer holding the data that has to be sent to the child
|
||||
*/
|
||||
const char *input_data;
|
||||
/**
|
||||
* The number of bytes already transmitted
|
||||
*/
|
||||
int input_sent;
|
||||
/**
|
||||
* The total length of input_data
|
||||
*/
|
||||
int input_total;
|
||||
|
||||
/**
|
||||
* K3ProcessController is a friend of K3Process because it has to have
|
||||
* access to various data members.
|
||||
*/
|
||||
friend class K3ProcessController;
|
||||
|
||||
private:
|
||||
K3ProcessPrivate* const d;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(K3Process::Communication)
|
||||
|
||||
class K3ShellProcessPrivate;
|
||||
|
||||
/**
|
||||
* @obsolete
|
||||
*
|
||||
* Use K3Process and K3Process::setUseShell(true) instead.
|
||||
*
|
||||
* @short A class derived from K3Process to start child
|
||||
* processes through a shell.
|
||||
* @author Christian Czezatke <e9025461@student.tuwien.ac.at>
|
||||
*/
|
||||
class K3ShellProcess : public K3Process
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* If no shellname is specified, the user's default shell is used.
|
||||
*/
|
||||
explicit K3ShellProcess(const char *shellname=0);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~K3ShellProcess();
|
||||
|
||||
virtual bool start(RunMode runmode = NotifyOnExit,
|
||||
Communication comm = NoCommunication);
|
||||
|
||||
static QString quote(const QString &arg);
|
||||
|
||||
private:
|
||||
K3ShellProcessPrivate* const d;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,334 @@
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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 "k3processcontroller.h"
|
||||
#include "k3process.h"
|
||||
|
||||
//#include <config.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <QtCore/QSocketNotifier>
|
||||
|
||||
class K3ProcessController::Private
|
||||
{
|
||||
public:
|
||||
Private()
|
||||
: needcheck( false ),
|
||||
notifier( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
delete notifier;
|
||||
}
|
||||
|
||||
int fd[2];
|
||||
bool needcheck;
|
||||
QSocketNotifier *notifier;
|
||||
QList<K3Process*> kProcessList;
|
||||
QList<int> unixProcessList;
|
||||
static struct sigaction oldChildHandlerData;
|
||||
static bool handlerSet;
|
||||
static int refCount;
|
||||
static K3ProcessController* instance;
|
||||
};
|
||||
|
||||
K3ProcessController *K3ProcessController::Private::instance = 0;
|
||||
int K3ProcessController::Private::refCount = 0;
|
||||
|
||||
void K3ProcessController::ref()
|
||||
{
|
||||
if ( !Private::refCount ) {
|
||||
Private::instance = new K3ProcessController;
|
||||
setupHandlers();
|
||||
}
|
||||
Private::refCount++;
|
||||
}
|
||||
|
||||
void K3ProcessController::deref()
|
||||
{
|
||||
Private::refCount--;
|
||||
if( !Private::refCount ) {
|
||||
resetHandlers();
|
||||
delete Private::instance;
|
||||
Private::instance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
K3ProcessController* K3ProcessController::instance()
|
||||
{
|
||||
/*
|
||||
* there were no safety guards in previous revisions, is that ok?
|
||||
if ( !Private::instance ) {
|
||||
ref();
|
||||
}
|
||||
*/
|
||||
|
||||
return Private::instance;
|
||||
}
|
||||
|
||||
K3ProcessController::K3ProcessController()
|
||||
: d( new Private )
|
||||
{
|
||||
if( pipe( d->fd ) )
|
||||
{
|
||||
perror( "pipe" );
|
||||
abort();
|
||||
}
|
||||
|
||||
fcntl( d->fd[0], F_SETFL, O_NONBLOCK ); // in case slotDoHousekeeping is called without polling first
|
||||
fcntl( d->fd[1], F_SETFL, O_NONBLOCK ); // in case it fills up
|
||||
fcntl( d->fd[0], F_SETFD, FD_CLOEXEC );
|
||||
fcntl( d->fd[1], F_SETFD, FD_CLOEXEC );
|
||||
|
||||
d->notifier = new QSocketNotifier( d->fd[0], QSocketNotifier::Read );
|
||||
d->notifier->setEnabled( true );
|
||||
QObject::connect( d->notifier, SIGNAL(activated(int)),
|
||||
SLOT(slotDoHousekeeping()));
|
||||
}
|
||||
|
||||
K3ProcessController::~K3ProcessController()
|
||||
{
|
||||
#ifndef Q_OS_MAC
|
||||
/* not sure why, but this is causing lockups */
|
||||
close( d->fd[0] );
|
||||
close( d->fd[1] );
|
||||
#else
|
||||
#warning FIXME: why does close() freeze up destruction?
|
||||
#endif
|
||||
|
||||
delete d;
|
||||
}
|
||||
|
||||
|
||||
extern "C" {
|
||||
static void theReaper( int num )
|
||||
{
|
||||
K3ProcessController::theSigCHLDHandler( num );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
struct sigaction K3ProcessController::Private::oldChildHandlerData;
|
||||
#endif
|
||||
bool K3ProcessController::Private::handlerSet = false;
|
||||
|
||||
void K3ProcessController::setupHandlers()
|
||||
{
|
||||
if( Private::handlerSet )
|
||||
return;
|
||||
Private::handlerSet = true;
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
struct sigaction act;
|
||||
sigemptyset( &act.sa_mask );
|
||||
|
||||
act.sa_handler = SIG_IGN;
|
||||
act.sa_flags = 0;
|
||||
sigaction( SIGPIPE, &act, 0L );
|
||||
|
||||
act.sa_handler = theReaper;
|
||||
act.sa_flags = SA_NOCLDSTOP;
|
||||
// CC: take care of SunOS which automatically restarts interrupted system
|
||||
// calls (and thus does not have SA_RESTART)
|
||||
#ifdef SA_RESTART
|
||||
act.sa_flags |= SA_RESTART;
|
||||
#endif
|
||||
sigaction( SIGCHLD, &act, &Private::oldChildHandlerData );
|
||||
|
||||
sigaddset( &act.sa_mask, SIGCHLD );
|
||||
// Make sure we don't block this signal. gdb tends to do that :-(
|
||||
sigprocmask( SIG_UNBLOCK, &act.sa_mask, 0 );
|
||||
#else
|
||||
//TODO: win32
|
||||
#endif
|
||||
}
|
||||
|
||||
void K3ProcessController::resetHandlers()
|
||||
{
|
||||
if( !Private::handlerSet )
|
||||
return;
|
||||
Private::handlerSet = false;
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
sigset_t mask, omask;
|
||||
sigemptyset( &mask );
|
||||
sigaddset( &mask, SIGCHLD );
|
||||
sigprocmask( SIG_BLOCK, &mask, &omask );
|
||||
|
||||
struct sigaction act;
|
||||
sigaction( SIGCHLD, &Private::oldChildHandlerData, &act );
|
||||
if (act.sa_handler != theReaper) {
|
||||
sigaction( SIGCHLD, &act, 0 );
|
||||
Private::handlerSet = true;
|
||||
}
|
||||
|
||||
sigprocmask( SIG_SETMASK, &omask, 0 );
|
||||
#else
|
||||
//TODO: win32
|
||||
#endif
|
||||
// there should be no problem with SIGPIPE staying SIG_IGN
|
||||
}
|
||||
|
||||
// the pipe is needed to sync the child reaping with our event processing,
|
||||
// as otherwise there are race conditions, locking requirements, and things
|
||||
// generally get harder
|
||||
void K3ProcessController::theSigCHLDHandler( int arg )
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
char dummy = 0;
|
||||
::write( instance()->d->fd[1], &dummy, 1 );
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
if ( Private::oldChildHandlerData.sa_handler != SIG_IGN &&
|
||||
Private::oldChildHandlerData.sa_handler != SIG_DFL ) {
|
||||
Private::oldChildHandlerData.sa_handler( arg ); // call the old handler
|
||||
}
|
||||
#else
|
||||
//TODO: win32
|
||||
#endif
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
int K3ProcessController::notifierFd() const
|
||||
{
|
||||
return d->fd[0];
|
||||
}
|
||||
|
||||
void K3ProcessController::unscheduleCheck()
|
||||
{
|
||||
char dummy[16]; // somewhat bigger - just in case several have queued up
|
||||
if( ::read( d->fd[0], dummy, sizeof(dummy) ) > 0 )
|
||||
d->needcheck = true;
|
||||
}
|
||||
|
||||
void
|
||||
K3ProcessController::rescheduleCheck()
|
||||
{
|
||||
if( d->needcheck )
|
||||
{
|
||||
d->needcheck = false;
|
||||
char dummy = 0;
|
||||
::write( d->fd[1], &dummy, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
void K3ProcessController::slotDoHousekeeping()
|
||||
{
|
||||
char dummy[16]; // somewhat bigger - just in case several have queued up
|
||||
::read( d->fd[0], dummy, sizeof(dummy) );
|
||||
|
||||
int status;
|
||||
again:
|
||||
QList<K3Process*>::iterator it( d->kProcessList.begin() );
|
||||
QList<K3Process*>::iterator eit( d->kProcessList.end() );
|
||||
while( it != eit )
|
||||
{
|
||||
K3Process *prc = *it;
|
||||
if( prc->runs && waitpid( prc->pid_, &status, WNOHANG ) > 0 )
|
||||
{
|
||||
prc->processHasExited( status );
|
||||
// the callback can nuke the whole process list and even 'this'
|
||||
if (!instance())
|
||||
return;
|
||||
goto again;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
QList<int>::iterator uit( d->unixProcessList.begin() );
|
||||
QList<int>::iterator ueit( d->unixProcessList.end() );
|
||||
while( uit != ueit )
|
||||
{
|
||||
if( waitpid( *uit, 0, WNOHANG ) > 0 )
|
||||
{
|
||||
uit = d->unixProcessList.erase( uit );
|
||||
deref(); // counterpart to addProcess, can invalidate 'this'
|
||||
} else
|
||||
++uit;
|
||||
}
|
||||
}
|
||||
|
||||
bool K3ProcessController::waitForProcessExit( int timeout )
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
for(;;)
|
||||
{
|
||||
struct timeval tv, *tvp;
|
||||
if (timeout < 0)
|
||||
tvp = 0;
|
||||
else
|
||||
{
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
tvp = &tv;
|
||||
}
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO( &fds );
|
||||
FD_SET( d->fd[0], &fds );
|
||||
|
||||
switch( select( d->fd[0]+1, &fds, 0, 0, tvp ) )
|
||||
{
|
||||
case -1:
|
||||
if( errno == EINTR )
|
||||
continue;
|
||||
// fall through; should never happen
|
||||
case 0:
|
||||
return false;
|
||||
default:
|
||||
slotDoHousekeeping();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
//TODO: win32
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void K3ProcessController::addKProcess( K3Process* p )
|
||||
{
|
||||
d->kProcessList.append( p );
|
||||
}
|
||||
|
||||
void K3ProcessController::removeKProcess( K3Process* p )
|
||||
{
|
||||
d->kProcessList.removeAll( p );
|
||||
}
|
||||
|
||||
void K3ProcessController::addProcess( int pid )
|
||||
{
|
||||
d->unixProcessList.append( pid );
|
||||
ref(); // make sure we stay around when the K3Process goes away
|
||||
}
|
||||
|
||||
//#include "moc_k3processcontroller.cpp"
|
@ -0,0 +1,137 @@
|
||||
/* This file is part of the KDE libraries
|
||||
Copyright (C) 1997 Christian Czezakte (e9025461@student.tuwien.ac.at)
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef K3PROCCTRL_H
|
||||
#define K3PROCCTRL_H
|
||||
|
||||
#include <QtCore/QList>
|
||||
#include <k3process.h>
|
||||
|
||||
|
||||
/**
|
||||
* @short Used internally by K3Process
|
||||
* @internal
|
||||
* @author Christian Czezatke <e9025461@student.tuwien.ac.at>
|
||||
*
|
||||
* A class for internal use by K3Process only. -- Exactly one instance
|
||||
* of this class is created by KApplication.
|
||||
*
|
||||
* This class takes care of the actual (UN*X) signal handling.
|
||||
*/
|
||||
class K3ProcessController : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create an instance if none exists yet.
|
||||
* Called by KApplication::KApplication()
|
||||
*/
|
||||
static void ref();
|
||||
|
||||
/**
|
||||
* Destroy the instance if one exists and it is not referenced any more.
|
||||
* Called by KApplication::~KApplication()
|
||||
*/
|
||||
static void deref();
|
||||
|
||||
/**
|
||||
* Only a single instance of this class is allowed at a time.
|
||||
* This method provides access to that instance.
|
||||
*/
|
||||
static K3ProcessController *instance();
|
||||
|
||||
/**
|
||||
* Automatically called upon SIGCHLD. Never call it directly.
|
||||
* If your application (or some library it uses) redirects SIGCHLD,
|
||||
* the new signal handler (and only it) should call the old handler
|
||||
* returned by sigaction().
|
||||
* @internal
|
||||
*/
|
||||
static void theSigCHLDHandler(int signal); // KDE4: private
|
||||
|
||||
/**
|
||||
* Wait for any process to exit and handle their exit without
|
||||
* starting an event loop.
|
||||
* This function may cause K3Process to emit any of its signals.
|
||||
*
|
||||
* @param timeout the timeout in seconds. -1 means no timeout.
|
||||
* @return true if a process exited, false
|
||||
* if no process exited within @p timeout seconds.
|
||||
*/
|
||||
bool waitForProcessExit(int timeout);
|
||||
|
||||
/**
|
||||
* Call this function to defer processing of the data that became available
|
||||
* on notifierFd().
|
||||
*/
|
||||
void unscheduleCheck();
|
||||
|
||||
/**
|
||||
* This function @em must be called at some point after calling
|
||||
* unscheduleCheck().
|
||||
*/
|
||||
void rescheduleCheck();
|
||||
|
||||
/*
|
||||
* Obtain the file descriptor K3ProcessController uses to get notified
|
||||
* about process exits. select() or poll() on it if you create a custom
|
||||
* event loop that needs to act upon SIGCHLD.
|
||||
* @return the file descriptor of the reading end of the notification pipe
|
||||
*/
|
||||
int notifierFd() const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
void addKProcess( K3Process* );
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
void removeKProcess( K3Process* );
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
void addProcess( int pid );
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotDoHousekeeping();
|
||||
|
||||
private:
|
||||
friend class I_just_love_gcc;
|
||||
|
||||
static void setupHandlers();
|
||||
static void resetHandlers();
|
||||
|
||||
// Disallow instantiation
|
||||
K3ProcessController();
|
||||
~K3ProcessController();
|
||||
|
||||
// Disallow assignment and copy-construction
|
||||
K3ProcessController( const K3ProcessController& );
|
||||
K3ProcessController& operator= ( const K3ProcessController& );
|
||||
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,4 @@
|
||||
/default.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
|
||||
/linux.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
|
||||
/vt420pc.keytab/1.1.1.1/Sat May 10 21:27:57 2008//
|
||||
D
|
@ -0,0 +1 @@
|
||||
qtermwidget/lib/kb-layouts
|
@ -0,0 +1 @@
|
||||
:ext:e_k@qtermwidget.cvs.sourceforge.net:/cvsroot/qtermwidget
|
@ -0,0 +1,133 @@
|
||||
# [README.default.Keytab] Buildin Keyboard Table
|
||||
#
|
||||
# To customize your keyboard, copy this file to something
|
||||
# ending with .keytab and change it to meet you needs.
|
||||
# Please read the README.KeyTab and the README.keyboard
|
||||
# in this case.
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
|
||||
keyboard "Default (XFree 4)"
|
||||
|
||||
# --------------------------------------------------------------
|
||||
#
|
||||
# Note that this particular table is a "risc" version made to
|
||||
# ease customization without bothering with obsolete details.
|
||||
# See VT100.keytab for the more hairy stuff.
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
|
||||
# common keys
|
||||
|
||||
key Escape : "\E"
|
||||
|
||||
key Tab -Shift : "\t"
|
||||
key Tab +Shift+Ansi : "\E[Z"
|
||||
key Tab +Shift-Ansi : "\t"
|
||||
key Backtab +Ansi : "\E[Z"
|
||||
key Backtab -Ansi : "\t"
|
||||
|
||||
key Return-Shift-NewLine : "\r"
|
||||
key Return-Shift+NewLine : "\r\n"
|
||||
|
||||
key Return+Shift : "\EOM"
|
||||
|
||||
# Backspace and Delete codes are preserving CTRL-H.
|
||||
|
||||
key Backspace : "\x7f"
|
||||
|
||||
# Arrow keys in VT52 mode
|
||||
# shift up/down are reserved for scrolling.
|
||||
# shift left/right are reserved for switching between tabs (this is hardcoded).
|
||||
|
||||
key Up -Shift-Ansi : "\EA"
|
||||
key Down -Shift-Ansi : "\EB"
|
||||
key Right-Shift-Ansi : "\EC"
|
||||
key Left -Shift-Ansi : "\ED"
|
||||
|
||||
# Arrow keys in ANSI mode with Application - and Normal Cursor Mode)
|
||||
|
||||
key Up -Shift-AnyMod+Ansi+AppCuKeys : "\EOA"
|
||||
key Down -Shift-AnyMod+Ansi+AppCuKeys : "\EOB"
|
||||
key Right -Shift-AnyMod+Ansi+AppCuKeys : "\EOC"
|
||||
key Left -Shift-AnyMod+Ansi+AppCuKeys : "\EOD"
|
||||
|
||||
key Up -Shift-AnyMod+Ansi-AppCuKeys : "\E[A"
|
||||
key Down -Shift-AnyMod+Ansi-AppCuKeys : "\E[B"
|
||||
key Right -Shift-AnyMod+Ansi-AppCuKeys : "\E[C"
|
||||
key Left -Shift-AnyMod+Ansi-AppCuKeys : "\E[D"
|
||||
|
||||
key Up -Shift+AnyMod+Ansi : "\E[1;*A"
|
||||
key Down -Shift+AnyMod+Ansi : "\E[1;*B"
|
||||
key Right -Shift+AnyMod+Ansi : "\E[1;*C"
|
||||
key Left -Shift+AnyMod+Ansi : "\E[1;*D"
|
||||
|
||||
# other grey PC keys
|
||||
|
||||
key Enter+NewLine : "\r\n"
|
||||
key Enter-NewLine : "\r"
|
||||
|
||||
key Home -AnyMod -AppCuKeys : "\E[H"
|
||||
key End -AnyMod -AppCuKeys : "\E[F"
|
||||
key Home -AnyMod +AppCuKeys : "\EOH"
|
||||
key End -AnyMod +AppCuKeys : "\EOF"
|
||||
key Home +AnyMod : "\E[1;*H"
|
||||
key End +AnyMod : "\E[1;*F"
|
||||
|
||||
key Insert -AnyMod : "\E[2~"
|
||||
key Delete -AnyMod : "\E[3~"
|
||||
key Insert +AnyMod : "\E[2;*~"
|
||||
key Delete +AnyMod : "\E[3;*~"
|
||||
|
||||
key Prior -Shift-AnyMod : "\E[5~"
|
||||
key Next -Shift-AnyMod : "\E[6~"
|
||||
key Prior -Shift+AnyMod : "\E[5;*~"
|
||||
key Next -Shift+AnyMod : "\E[6;*~"
|
||||
|
||||
# Function keys
|
||||
key F1 -AnyMod : "\EOP"
|
||||
key F2 -AnyMod : "\EOQ"
|
||||
key F3 -AnyMod : "\EOR"
|
||||
key F4 -AnyMod : "\EOS"
|
||||
key F5 -AnyMod : "\E[15~"
|
||||
key F6 -AnyMod : "\E[17~"
|
||||
key F7 -AnyMod : "\E[18~"
|
||||
key F8 -AnyMod : "\E[19~"
|
||||
key F9 -AnyMod : "\E[20~"
|
||||
key F10 -AnyMod : "\E[21~"
|
||||
key F11 -AnyMod : "\E[23~"
|
||||
key F12 -AnyMod : "\E[24~"
|
||||
|
||||
key F1 +AnyMod : "\EO*P"
|
||||
key F2 +AnyMod : "\EO*Q"
|
||||
key F3 +AnyMod : "\EO*R"
|
||||
key F4 +AnyMod : "\EO*S"
|
||||
key F5 +AnyMod : "\E[15;*~"
|
||||
key F6 +AnyMod : "\E[17;*~"
|
||||
key F7 +AnyMod : "\E[18;*~"
|
||||
key F8 +AnyMod : "\E[19;*~"
|
||||
key F9 +AnyMod : "\E[20;*~"
|
||||
key F10 +AnyMod : "\E[21;*~"
|
||||
key F11 +AnyMod : "\E[23;*~"
|
||||
key F12 +AnyMod : "\E[24;*~"
|
||||
|
||||
# Work around dead keys
|
||||
|
||||
key Space +Control : "\x00"
|
||||
|
||||
# Some keys are used by konsole to cause operations.
|
||||
# The scroll* operations refer to the history buffer.
|
||||
|
||||
key Up +Shift-AppScreen : scrollLineUp
|
||||
key Prior +Shift-AppScreen : scrollPageUp
|
||||
key Down +Shift-AppScreen : scrollLineDown
|
||||
key Next +Shift-AppScreen : scrollPageDown
|
||||
|
||||
#key Up +Shift : scrollLineUp
|
||||
#key Prior +Shift : scrollPageUp
|
||||
#key Down +Shift : scrollLineDown
|
||||
#key Next +Shift : scrollPageDown
|
||||
|
||||
key ScrollLock : scrollLock
|
||||
|
||||
# keypad characters are not offered differently by Qt.
|
@ -0,0 +1,133 @@
|
||||
# [linux.keytab] Konsole Keyboard Table (Linux console keys)
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
|
||||
# NOT TESTED, MAY NEED SOME CLEANUPS
|
||||
keyboard "Linux console"
|
||||
|
||||
# --------------------------------------------------------------
|
||||
#
|
||||
# This configuration table allows to customize the
|
||||
# meaning of the keys.
|
||||
#
|
||||
# The syntax is that each entry has the form :
|
||||
#
|
||||
# "key" Keyname { ("+"|"-") Modename } ":" (String|Operation)
|
||||
#
|
||||
# Keynames are those defined in <qnamespace.h> with the
|
||||
# "Qt::Key_" removed. (We'd better insert the list here)
|
||||
#
|
||||
# Mode names are :
|
||||
#
|
||||
# - Shift
|
||||
# - Alt
|
||||
# - Control
|
||||
#
|
||||
# The VT100 emulation has two modes that can affect the
|
||||
# sequences emitted by certain keys. These modes are
|
||||
# under control of the client program.
|
||||
#
|
||||
# - Newline : effects Return and Enter key.
|
||||
# - Application : effects Up and Down key.
|
||||
#
|
||||
# - Ansi : effects Up and Down key (This is for VT52, really).
|
||||
#
|
||||
# Operations are
|
||||
#
|
||||
# - scrollUpLine
|
||||
# - scrollUpPage
|
||||
# - scrollDownLine
|
||||
# - scrollDownPage
|
||||
#
|
||||
# - emitSelection
|
||||
#
|
||||
# If the key is not found here, the text of the
|
||||
# key event as provided by QT is emitted, possibly
|
||||
# preceeded by ESC if the Alt key is pressed.
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
|
||||
key Escape : "\E"
|
||||
key Tab : "\t"
|
||||
|
||||
# VT100 can add an extra \n after return.
|
||||
# The NewLine mode is set by an escape sequence.
|
||||
|
||||
key Return-NewLine : "\r"
|
||||
key Return+NewLine : "\r\n"
|
||||
|
||||
# Some desperately try to save the ^H.
|
||||
|
||||
key Backspace : "\x7f"
|
||||
key Delete : "\E[3~"
|
||||
|
||||
# These codes are for the VT52 mode of VT100
|
||||
# The Ansi mode (i.e. VT100 mode) is set by
|
||||
# an escape sequence
|
||||
|
||||
key Up -Shift-Ansi : "\EA"
|
||||
key Down -Shift-Ansi : "\EB"
|
||||
key Right-Shift-Ansi : "\EC"
|
||||
key Left -Shift-Ansi : "\ED"
|
||||
|
||||
# VT100 emits a mode bit together
|
||||
# with the arrow keys.The AppCuKeys
|
||||
# mode is set by an escape sequence.
|
||||
|
||||
key Up -Shift+Ansi+AppCuKeys : "\EOA"
|
||||
key Down -Shift+Ansi+AppCuKeys : "\EOB"
|
||||
key Right-Shift+Ansi+AppCuKeys : "\EOC"
|
||||
key Left -Shift+Ansi+AppCuKeys : "\EOD"
|
||||
|
||||
key Up -Shift+Ansi-AppCuKeys : "\E[A"
|
||||
key Down -Shift+Ansi-AppCuKeys : "\E[B"
|
||||
key Right-Shift+Ansi-AppCuKeys : "\E[C"
|
||||
key Left -Shift+Ansi-AppCuKeys : "\E[D"
|
||||
|
||||
# linux functions keys F1-F5 differ from xterm
|
||||
|
||||
key F1 : "\E[[A"
|
||||
key F2 : "\E[[B"
|
||||
key F3 : "\E[[C"
|
||||
key F4 : "\E[[D"
|
||||
key F5 : "\E[[E"
|
||||
|
||||
key F6 : "\E[17~"
|
||||
key F7 : "\E[18~"
|
||||
key F8 : "\E[19~"
|
||||
key F9 : "\E[20~"
|
||||
key F10 : "\E[21~"
|
||||
key F11 : "\E[23~"
|
||||
key F12 : "\E[24~"
|
||||
|
||||
key Home : "\E[1~"
|
||||
key End : "\E[4~"
|
||||
|
||||
key Prior -Shift : "\E[5~"
|
||||
key Next -Shift : "\E[6~"
|
||||
key Insert-Shift : "\E[2~"
|
||||
|
||||
# Keypad-Enter. See comment on Return above.
|
||||
|
||||
key Enter+NewLine : "\r\n"
|
||||
key Enter-NewLine : "\r"
|
||||
|
||||
key Space +Control : "\x00"
|
||||
|
||||
# some of keys are used by konsole.
|
||||
|
||||
key Up +Shift : scrollLineUp
|
||||
key Prior +Shift : scrollPageUp
|
||||
key Down +Shift : scrollLineDown
|
||||
key Next +Shift : scrollPageDown
|
||||
|
||||
key ScrollLock : scrollLock
|
||||
|
||||
#----------------------------------------------------------
|
||||
|
||||
# keypad characters as offered by Qt
|
||||
# cannot be recognized as such.
|
||||
|
||||
#----------------------------------------------------------
|
||||
|
||||
# Following other strings as emitted by konsole.
|
@ -0,0 +1,163 @@
|
||||
# [vt420pc.keytab] Konsole Keyboard Table (VT420pc keys)
|
||||
# adapted by ferdinand gassauer f.gassauer@aon.at
|
||||
# Nov 2000
|
||||
#
|
||||
################################################################
|
||||
#
|
||||
# The escape sequences emmited by the
|
||||
# keys Shift+F1 to Shift+F12 might not fit your needs
|
||||
#
|
||||
################# IMPORTANT NOTICE #############################
|
||||
# the key bindings (Kcontrol -> look and feel -> keybindgs)
|
||||
# overrule the settings in this file. The key bindings might be
|
||||
# changed by the user WITHOUT notification of the maintainer of
|
||||
# the keytab file. Konsole will not work as expected by
|
||||
# the maintainer of the keytab file.
|
||||
################################################################
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
|
||||
keyboard "DEC VT420 Terminal"
|
||||
|
||||
# --------------------------------------------------------------
|
||||
#
|
||||
# This configuration table allows to customize the
|
||||
# meaning of the keys.
|
||||
#
|
||||
# The syntax is that each entry has the form :
|
||||
#
|
||||
# "key" Keyname { ("+"|"-") Modename } ":" (String|Operation)
|
||||
#
|
||||
# Keynames are those defined in <qnamespace.h> with the
|
||||
# "Qt::Key_" removed. (We'd better insert the list here)
|
||||
#
|
||||
# Mode names are :
|
||||
#
|
||||
# - Shift
|
||||
# - Alt
|
||||
# - Control
|
||||
#
|
||||
# The VT100 emulation has two modes that can affect the
|
||||
# sequences emitted by certain keys. These modes are
|
||||
# under control of the client program.
|
||||
#
|
||||
# - Newline : effects Return and Enter key.
|
||||
# - Application : effects Up and Down key.
|
||||
#
|
||||
# - Ansi : effects Up and Down key (This is for VT52, really).
|
||||
#
|
||||
# Operations are
|
||||
#
|
||||
# - scrollUpLine
|
||||
# - scrollUpPage
|
||||
# - scrollDownLine
|
||||
# - scrollDownPage
|
||||
#
|
||||
# - emitSelection
|
||||
#
|
||||
# If the key is not found here, the text of the
|
||||
# key event as provided by QT is emitted, possibly
|
||||
# preceeded by ESC if the Alt key is pressed.
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
|
||||
key Escape : "\E"
|
||||
key Tab : "\t"
|
||||
key Backtab: "\E[Z"
|
||||
|
||||
# VT100 can add an extra \n after return.
|
||||
# The NewLine mode is set by an escape sequence.
|
||||
|
||||
key Return-NewLine : "\r"
|
||||
key Return+NewLine : "\r\n"
|
||||
|
||||
# Some desperately try to save the ^H.
|
||||
# may be not everyone wants this
|
||||
|
||||
key Backspace : "\x08" # Control H
|
||||
key Delete : "\x7f"
|
||||
|
||||
# These codes are for the VT420pc
|
||||
# The Ansi mode (i.e. VT100 mode) is set by
|
||||
# an escape sequence
|
||||
|
||||
key Up -Shift-Ansi : "\EA"
|
||||
key Down -Shift-Ansi : "\EB"
|
||||
key Right-Shift-Ansi : "\EC"
|
||||
key Left -Shift-Ansi : "\ED"
|
||||
|
||||
# VT100 emits a mode bit together
|
||||
# with the arrow keys.The AppCuKeys
|
||||
# mode is set by an escape sequence.
|
||||
|
||||
key Up -Shift+Ansi+AppCuKeys : "\EOA"
|
||||
key Down -Shift+Ansi+AppCuKeys : "\EOB"
|
||||
key Right-Shift+Ansi+AppCuKeys : "\EOC"
|
||||
key Left -Shift+Ansi+AppCuKeys : "\EOD"
|
||||
|
||||
key Up -Shift+Ansi-AppCuKeys : "\E[A"
|
||||
key Down -Shift+Ansi-AppCuKeys : "\E[B"
|
||||
key Right-Shift+Ansi-AppCuKeys : "\E[C"
|
||||
key Left -Shift+Ansi-AppCuKeys : "\E[D"
|
||||
|
||||
# function keys
|
||||
|
||||
key F1 -Shift : "\E[11~"
|
||||
key F2 -Shift : "\E[12~"
|
||||
key F3 -Shift : "\E[13~"
|
||||
key F4 -Shift : "\E[14~"
|
||||
key F5 -Shift : "\E[15~"
|
||||
key F6 -Shift : "\E[17~"
|
||||
key F7 -Shift : "\E[18~"
|
||||
key F8 -Shift : "\E[19~"
|
||||
key F9 -Shift : "\E[20~"
|
||||
key F10-Shift : "\E[21~"
|
||||
key F11-Shift : "\E[23~"
|
||||
key F12-Shift : "\E[24~"
|
||||
#
|
||||
# Shift F1-F12
|
||||
#
|
||||
key F1 +Shift : "\E[11;2~"
|
||||
key F2 +Shift : "\E[12;2~"
|
||||
key F3 +Shift : "\E[13;2~"
|
||||
key F4 +Shift : "\E[14;2~"
|
||||
key F5 +Shift : "\E[15;2~"
|
||||
key F6 +Shift : "\E[17;2~"
|
||||
key F7 +Shift : "\E[18;2~"
|
||||
key F8 +Shift : "\E[19;2~"
|
||||
key F9 +Shift : "\E[20;2~"
|
||||
key F10+Shift : "\E[21;2~"
|
||||
key F11+Shift : "\E[23;2~"
|
||||
key F12+Shift : "\E[24;2~"
|
||||
|
||||
key Home : "\E[H"
|
||||
key End : "\E[F"
|
||||
|
||||
key Prior -Shift : "\E[5~"
|
||||
key Next -Shift : "\E[6~"
|
||||
key Insert-Shift : "\E[2~"
|
||||
|
||||
# Keypad-Enter. See comment on Return above.
|
||||
|
||||
key Enter+NewLine : "\r\n"
|
||||
key Enter-NewLine : "\r"
|
||||
|
||||
key Space +Control : "\x00"
|
||||
|
||||
# some of keys are used by konsole.
|
||||
|
||||
key Up +Shift : scrollLineUp
|
||||
key Prior +Shift : scrollPageUp
|
||||
key Down +Shift : scrollLineDown
|
||||
key Next +Shift : scrollPageDown
|
||||
|
||||
key ScrollLock : scrollLock
|
||||
|
||||
#----------------------------------------------------------
|
||||
|
||||
# keypad characters as offered by Qt
|
||||
# cannot be recognized as such.
|
||||
|
||||
#----------------------------------------------------------
|
||||
|
||||
# Following other strings as emitted by konsole.
|
@ -0,0 +1,216 @@
|
||||
/* $XFree86: xc/programs/xterm/wcwidth.character,v 1.3 2001/07/29 22:08:16 tsi Exp $ */
|
||||
/*
|
||||
* This is an implementation of wcwidth() and wcswidth() as defined in
|
||||
* "The Single UNIX Specification, Version 2, The Open Group, 1997"
|
||||
* <http://www.UNIX-systems.org/online.html>
|
||||
*
|
||||
* Markus Kuhn -- 2001-01-12 -- public domain
|
||||
*/
|
||||
|
||||
#include "konsole_wcwidth.h"
|
||||
|
||||
struct interval {
|
||||
unsigned short first;
|
||||
unsigned short last;
|
||||
};
|
||||
|
||||
/* auxiliary function for binary search in interval table */
|
||||
static int bisearch(quint16 ucs, const struct interval *table, int max) {
|
||||
int min = 0;
|
||||
int mid;
|
||||
|
||||
if (ucs < table[0].first || ucs > table[max].last)
|
||||
return 0;
|
||||
while (max >= min) {
|
||||
mid = (min + max) / 2;
|
||||
if (ucs > table[mid].last)
|
||||
min = mid + 1;
|
||||
else if (ucs < table[mid].first)
|
||||
max = mid - 1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The following functions define the column width of an ISO 10646
|
||||
* character as follows:
|
||||
*
|
||||
* - The null character (U+0000) has a column width of 0.
|
||||
*
|
||||
* - Other C0/C1 control characters and DEL will lead to a return
|
||||
* value of -1.
|
||||
*
|
||||
* - Non-spacing and enclosing combining characters (general
|
||||
* category code Mn or Me in the Unicode database) have a
|
||||
* column width of 0.
|
||||
*
|
||||
* - Other format characters (general category code Cf in the Unicode
|
||||
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
|
||||
*
|
||||
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
|
||||
* have a column width of 0.
|
||||
*
|
||||
* - Spacing characters in the East Asian Wide (W) or East Asian
|
||||
* FullWidth (F) category as defined in Unicode Technical
|
||||
* Report #11 have a column width of 2.
|
||||
*
|
||||
* - All remaining characters (including all printable
|
||||
* ISO 8859-1 and WGL4 characters, Unicode control characters,
|
||||
* etc.) have a column width of 1.
|
||||
*
|
||||
* This implementation assumes that quint16 characters are encoded
|
||||
* in ISO 10646.
|
||||
*/
|
||||
|
||||
int konsole_wcwidth(quint16 ucs)
|
||||
{
|
||||
/* sorted list of non-overlapping intervals of non-spacing characters */
|
||||
static const struct interval combining[] = {
|
||||
{ 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 },
|
||||
{ 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 },
|
||||
{ 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
|
||||
{ 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 },
|
||||
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
|
||||
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
|
||||
{ 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C },
|
||||
{ 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 },
|
||||
{ 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC },
|
||||
{ 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 },
|
||||
{ 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 },
|
||||
{ 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 },
|
||||
{ 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 },
|
||||
{ 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 },
|
||||
{ 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 },
|
||||
{ 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 },
|
||||
{ 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
|
||||
{ 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
|
||||
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
|
||||
{ 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA },
|
||||
{ 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 },
|
||||
{ 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 },
|
||||
{ 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD },
|
||||
{ 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 },
|
||||
{ 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 },
|
||||
{ 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC },
|
||||
{ 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 },
|
||||
{ 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 },
|
||||
{ 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 },
|
||||
{ 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 },
|
||||
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F },
|
||||
{ 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A },
|
||||
{ 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF },
|
||||
{ 0xFFF9, 0xFFFB }
|
||||
};
|
||||
|
||||
/* test for 8-bit control characters */
|
||||
if (ucs == 0)
|
||||
return 0;
|
||||
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
|
||||
return -1;
|
||||
|
||||
/* binary search in table of non-spacing characters */
|
||||
if (bisearch(ucs, combining,
|
||||
sizeof(combining) / sizeof(struct interval) - 1))
|
||||
return 0;
|
||||
|
||||
/* if we arrive here, ucs is not a combining or C0/C1 control character */
|
||||
|
||||
return 1 +
|
||||
(ucs >= 0x1100 &&
|
||||
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
|
||||
(ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
|
||||
ucs != 0x303f) || /* CJK ... Yi */
|
||||
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
|
||||
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
|
||||
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
|
||||
(ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
|
||||
(ucs >= 0xffe0 && ucs <= 0xffe6) /* do not compare UINT16 with 0x20000 ||
|
||||
(ucs >= 0x20000 && ucs <= 0x2ffff) */));
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* The following function is the same as konsole_wcwidth(), except that
|
||||
* spacing characters in the East Asian Ambiguous (A) category as
|
||||
* defined in Unicode Technical Report #11 have a column width of 2.
|
||||
* This experimental variant might be useful for users of CJK legacy
|
||||
* encodings who want to migrate to UCS. It is not otherwise
|
||||
* recommended for general use.
|
||||
*/
|
||||
int konsole_wcwidth_cjk(quint16 ucs)
|
||||
{
|
||||
/* sorted list of non-overlapping intervals of East Asian Ambiguous
|
||||
* characters */
|
||||
static const struct interval ambiguous[] = {
|
||||
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
|
||||
{ 0x00AA, 0x00AA }, { 0x00AD, 0x00AD }, { 0x00B0, 0x00B4 },
|
||||
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
|
||||
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
|
||||
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
|
||||
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
|
||||
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
|
||||
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
|
||||
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
|
||||
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
|
||||
{ 0x0148, 0x014A }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
|
||||
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
|
||||
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
|
||||
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
|
||||
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
|
||||
{ 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, { 0x02CD, 0x02CD },
|
||||
{ 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, { 0x02DD, 0x02DD },
|
||||
{ 0x0391, 0x03A1 }, { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 },
|
||||
{ 0x03C3, 0x03C9 }, { 0x0401, 0x0401 }, { 0x0410, 0x044F },
|
||||
{ 0x0451, 0x0451 }, { 0x2010, 0x2010 }, { 0x2013, 0x2016 },
|
||||
{ 0x2018, 0x2019 }, { 0x201C, 0x201D }, { 0x2020, 0x2021 },
|
||||
{ 0x2025, 0x2027 }, { 0x2030, 0x2030 }, { 0x2032, 0x2033 },
|
||||
{ 0x2035, 0x2035 }, { 0x203B, 0x203B }, { 0x2074, 0x2074 },
|
||||
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
|
||||
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
|
||||
{ 0x2113, 0x2113 }, { 0x2121, 0x2122 }, { 0x2126, 0x2126 },
|
||||
{ 0x212B, 0x212B }, { 0x2154, 0x2155 }, { 0x215B, 0x215B },
|
||||
{ 0x215E, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
|
||||
{ 0x2190, 0x2199 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 },
|
||||
{ 0x2200, 0x2200 }, { 0x2202, 0x2203 }, { 0x2207, 0x2208 },
|
||||
{ 0x220B, 0x220B }, { 0x220F, 0x220F }, { 0x2211, 0x2211 },
|
||||
{ 0x2215, 0x2215 }, { 0x221A, 0x221A }, { 0x221D, 0x2220 },
|
||||
{ 0x2223, 0x2223 }, { 0x2225, 0x2225 }, { 0x2227, 0x222C },
|
||||
{ 0x222E, 0x222E }, { 0x2234, 0x2237 }, { 0x223C, 0x223D },
|
||||
{ 0x2248, 0x2248 }, { 0x224C, 0x224C }, { 0x2252, 0x2252 },
|
||||
{ 0x2260, 0x2261 }, { 0x2264, 0x2267 }, { 0x226A, 0x226B },
|
||||
{ 0x226E, 0x226F }, { 0x2282, 0x2283 }, { 0x2286, 0x2287 },
|
||||
{ 0x2295, 0x2295 }, { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 },
|
||||
{ 0x22BF, 0x22BF }, { 0x2312, 0x2312 }, { 0x2460, 0x24BF },
|
||||
{ 0x24D0, 0x24E9 }, { 0x2500, 0x254B }, { 0x2550, 0x2574 },
|
||||
{ 0x2580, 0x258F }, { 0x2592, 0x2595 }, { 0x25A0, 0x25A1 },
|
||||
{ 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, { 0x25B6, 0x25B7 },
|
||||
{ 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C8 },
|
||||
{ 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, { 0x25E2, 0x25E5 },
|
||||
{ 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, { 0x2609, 0x2609 },
|
||||
{ 0x260E, 0x260F }, { 0x261C, 0x261C }, { 0x261E, 0x261E },
|
||||
{ 0x2640, 0x2640 }, { 0x2642, 0x2642 }, { 0x2660, 0x2661 },
|
||||
{ 0x2663, 0x2665 }, { 0x2667, 0x266A }, { 0x266C, 0x266D },
|
||||
{ 0x266F, 0x266F }, { 0x300A, 0x300B }, { 0x301A, 0x301B },
|
||||
{ 0xE000, 0xF8FF }, { 0xFFFD, 0xFFFD }
|
||||
};
|
||||
|
||||
/* binary search in table of non-spacing characters */
|
||||
if (bisearch(ucs, ambiguous,
|
||||
sizeof(ambiguous) / sizeof(struct interval) - 1))
|
||||
return 2;
|
||||
|
||||
return konsole_wcwidth(ucs);
|
||||
}
|
||||
#endif
|
||||
|
||||
// single byte char: +1, multi byte char: +2
|
||||
int string_width( const QString &txt )
|
||||
{
|
||||
int w = 0;
|
||||
for ( int i = 0; i < txt.length(); ++i )
|
||||
w += konsole_wcwidth( txt[ i ].unicode() );
|
||||
return w;
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/* $XFree86: xc/programs/xterm/wcwidth.h,v 1.2 2001/06/18 19:09:27 dickey Exp $ */
|
||||
|
||||
/* Markus Kuhn -- 2001-01-12 -- public domain */
|
||||
/* Adaptions for KDE by Waldo Bastian <bastian@kde.org> */
|
||||
/*
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _KONSOLE_WCWIDTH_H_
|
||||
#define _KONSOLE_WCWIDTH_H_
|
||||
|
||||
// Qt
|
||||
#include <QtCore/QBool>
|
||||
#include <QtCore/QString>
|
||||
|
||||
int konsole_wcwidth(quint16 ucs);
|
||||
#if 0
|
||||
int konsole_wcwidth_cjk(Q_UINT16 ucs);
|
||||
#endif
|
||||
|
||||
int string_width( const QString &txt );
|
||||
|
||||
#endif
|
@ -0,0 +1,624 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE libraries
|
||||
Copyright (C) 2002 Waldo Bastian <bastian@kde.org>
|
||||
Copyright (C) 2002-2003,2007 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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 "kpty_p.h"
|
||||
|
||||
#ifdef __sgi
|
||||
#define __svr4__
|
||||
#endif
|
||||
|
||||
#ifdef __osf__
|
||||
#define _OSF_SOURCE
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
#ifdef _AIX
|
||||
#define _ALL_SOURCE
|
||||
#endif
|
||||
|
||||
// __USE_XOPEN isn't defined by default in ICC
|
||||
// (needed for ptsname(), grantpt() and unlockpt())
|
||||
#ifdef __INTEL_COMPILER
|
||||
# ifndef __USE_XOPEN
|
||||
# define __USE_XOPEN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#if defined(HAVE_PTY_H)
|
||||
# include <pty.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUTIL_H
|
||||
# include <libutil.h>
|
||||
#elif defined(HAVE_UTIL_H)
|
||||
# include <util.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTEMPTER
|
||||
extern "C" {
|
||||
# include <utempter.h>
|
||||
}
|
||||
#else
|
||||
# include <utmp.h>
|
||||
# ifdef HAVE_UTMPX
|
||||
# include <utmpx.h>
|
||||
# endif
|
||||
# if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
|
||||
# define _PATH_UTMPX _UTMPX_FILE
|
||||
# endif
|
||||
# if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
|
||||
# define _PATH_WTMPX _WTMPX_FILE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* for HP-UX (some versions) the extern C is needed, and for other
|
||||
platforms it doesn't hurt */
|
||||
extern "C" {
|
||||
#include <termios.h>
|
||||
#if defined(HAVE_TERMIO_H)
|
||||
# include <termio.h> // struct winsize on some systems
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined (_HPUX_SOURCE)
|
||||
# define _TERMIOS_INCLUDED
|
||||
# include <bsdtty.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STROPTS_H
|
||||
# include <sys/stropts.h> // Defines I_PUSH
|
||||
# define _NEW_TTY_CTRL
|
||||
#endif
|
||||
|
||||
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
|
||||
# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
|
||||
#else
|
||||
# if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
|
||||
# define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
|
||||
# else
|
||||
# define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
|
||||
# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
|
||||
#else
|
||||
# if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
|
||||
# define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
|
||||
# else
|
||||
# define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//#include <kdebug.h>
|
||||
//#include <kstandarddirs.h> // findExe
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
// not defined on HP-UX for example
|
||||
#ifndef CTRL
|
||||
# define CTRL(x) ((x) & 037)
|
||||
#endif
|
||||
|
||||
#define TTY_GROUP "tty"
|
||||
|
||||
///////////////////////
|
||||
// private functions //
|
||||
///////////////////////
|
||||
|
||||
//////////////////
|
||||
// private data //
|
||||
//////////////////
|
||||
|
||||
KPtyPrivate::KPtyPrivate() :
|
||||
masterFd(-1), slaveFd(-1)
|
||||
{
|
||||
}
|
||||
|
||||
bool KPtyPrivate::chownpty(bool)
|
||||
{
|
||||
// return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
|
||||
// QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////
|
||||
// public member functions //
|
||||
/////////////////////////////
|
||||
|
||||
KPty::KPty() :
|
||||
d_ptr(new KPtyPrivate)
|
||||
{
|
||||
d_ptr->q_ptr = this;
|
||||
}
|
||||
|
||||
KPty::KPty(KPtyPrivate *d) :
|
||||
d_ptr(d)
|
||||
{
|
||||
d_ptr->q_ptr = this;
|
||||
}
|
||||
|
||||
KPty::~KPty()
|
||||
{
|
||||
close();
|
||||
delete d_ptr;
|
||||
}
|
||||
|
||||
bool KPty::open()
|
||||
{
|
||||
Q_D(KPty);
|
||||
|
||||
if (d->masterFd >= 0)
|
||||
return true;
|
||||
|
||||
QByteArray ptyName;
|
||||
|
||||
// Find a master pty that we can open ////////////////////////////////
|
||||
|
||||
// Because not all the pty animals are created equal, they want to
|
||||
// be opened by several different methods.
|
||||
|
||||
// We try, as we know them, one by one.
|
||||
|
||||
#ifdef HAVE_OPENPTY
|
||||
|
||||
char ptsn[PATH_MAX];
|
||||
if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0))
|
||||
{
|
||||
d->masterFd = -1;
|
||||
d->slaveFd = -1;
|
||||
kWarning(175) << "Can't open a pseudo teletype";
|
||||
return false;
|
||||
}
|
||||
d->ttyName = ptsn;
|
||||
|
||||
#else
|
||||
|
||||
#ifdef HAVE__GETPTY // irix
|
||||
|
||||
char *ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
|
||||
if (ptsn) {
|
||||
d->ttyName = ptsn;
|
||||
goto grantedpt;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
|
||||
|
||||
#ifdef HAVE_POSIX_OPENPT
|
||||
d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
|
||||
#elif defined(HAVE_GETPT)
|
||||
d->masterFd = ::getpt();
|
||||
#elif defined(PTM_DEVICE)
|
||||
d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY);
|
||||
#else
|
||||
# error No method to open a PTY master detected.
|
||||
#endif
|
||||
|
||||
if (d->masterFd >= 0)
|
||||
{
|
||||
|
||||
#ifdef HAVE_PTSNAME
|
||||
char *ptsn = ptsname(d->masterFd);
|
||||
if (ptsn) {
|
||||
d->ttyName = ptsn;
|
||||
#else
|
||||
int ptyno;
|
||||
if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
|
||||
d->ttyName = QByteArray("/dev/pts/") + QByteArray::number(ptyno);
|
||||
#endif
|
||||
#ifdef HAVE_GRANTPT
|
||||
if (!grantpt(d->masterFd))
|
||||
goto grantedpt;
|
||||
#else
|
||||
|
||||
goto gotpty;
|
||||
#endif
|
||||
}
|
||||
::close(d->masterFd);
|
||||
d->masterFd = -1;
|
||||
}
|
||||
#endif // HAVE_PTSNAME || TIOCGPTN
|
||||
|
||||
// Linux device names, FIXME: Trouble on other systems?
|
||||
for (const char* s3 = "pqrstuvwxyzabcde"; *s3; s3++)
|
||||
{
|
||||
for (const char* s4 = "0123456789abcdef"; *s4; s4++)
|
||||
{
|
||||
ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
|
||||
d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
|
||||
|
||||
d->masterFd = ::open(ptyName.data(), O_RDWR);
|
||||
if (d->masterFd >= 0)
|
||||
{
|
||||
#ifdef Q_OS_SOLARIS
|
||||
/* Need to check the process group of the pty.
|
||||
* If it exists, then the slave pty is in use,
|
||||
* and we need to get another one.
|
||||
*/
|
||||
int pgrp_rtn;
|
||||
if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
|
||||
::close(d->masterFd);
|
||||
d->masterFd = -1;
|
||||
continue;
|
||||
}
|
||||
#endif /* Q_OS_SOLARIS */
|
||||
if (!access(d->ttyName.data(),R_OK|W_OK)) // checks availability based on permission bits
|
||||
{
|
||||
if (!geteuid())
|
||||
{
|
||||
struct group* p = getgrnam(TTY_GROUP);
|
||||
if (!p)
|
||||
p = getgrnam("wheel");
|
||||
gid_t gid = p ? p->gr_gid : getgid ();
|
||||
|
||||
chown(d->ttyName.data(), getuid(), gid);
|
||||
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
|
||||
}
|
||||
goto gotpty;
|
||||
}
|
||||
::close(d->masterFd);
|
||||
d->masterFd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qWarning() << "Can't open a pseudo teletype";
|
||||
return false;
|
||||
|
||||
gotpty:
|
||||
struct stat st;
|
||||
if (stat(d->ttyName.data(), &st)) {
|
||||
return false; // this just cannot happen ... *cough* Yeah right, I just
|
||||
// had it happen when pty #349 was allocated. I guess
|
||||
// there was some sort of leak? I only had a few open.
|
||||
}
|
||||
if (((st.st_uid != getuid()) ||
|
||||
(st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
|
||||
!d->chownpty(true))
|
||||
{
|
||||
qWarning()
|
||||
<< "chownpty failed for device " << ptyName << "::" << d->ttyName
|
||||
<< "\nThis means the communication can be eavesdropped." << endl;
|
||||
}
|
||||
|
||||
#if defined (HAVE__GETPTY) || defined (HAVE_GRANTPT)
|
||||
grantedpt:
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_REVOKE
|
||||
revoke(d->ttyName.data());
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNLOCKPT
|
||||
unlockpt(d->masterFd);
|
||||
#elif defined(TIOCSPTLCK)
|
||||
int flag = 0;
|
||||
ioctl(d->masterFd, TIOCSPTLCK, &flag);
|
||||
#endif
|
||||
|
||||
d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
|
||||
if (d->slaveFd < 0)
|
||||
{
|
||||
qWarning() << "Can't open slave pseudo teletype";
|
||||
::close(d->masterFd);
|
||||
d->masterFd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if (defined(__svr4__) || defined(__sgi__))
|
||||
// Solaris
|
||||
ioctl(d->slaveFd, I_PUSH, "ptem");
|
||||
ioctl(d->slaveFd, I_PUSH, "ldterm");
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_OPENPTY */
|
||||
|
||||
fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
|
||||
fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KPty::closeSlave()
|
||||
{
|
||||
Q_D(KPty);
|
||||
|
||||
if (d->slaveFd < 0)
|
||||
return;
|
||||
::close(d->slaveFd);
|
||||
d->slaveFd = -1;
|
||||
}
|
||||
|
||||
void KPty::close()
|
||||
{
|
||||
Q_D(KPty);
|
||||
|
||||
if (d->masterFd < 0)
|
||||
return;
|
||||
closeSlave();
|
||||
// don't bother resetting unix98 pty, it will go away after closing master anyway.
|
||||
if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
|
||||
if (!geteuid()) {
|
||||
struct stat st;
|
||||
if (!stat(d->ttyName.data(), &st)) {
|
||||
chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
|
||||
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
|
||||
}
|
||||
} else {
|
||||
fcntl(d->masterFd, F_SETFD, 0);
|
||||
d->chownpty(false);
|
||||
}
|
||||
}
|
||||
::close(d->masterFd);
|
||||
d->masterFd = -1;
|
||||
}
|
||||
|
||||
void KPty::setCTty()
|
||||
{
|
||||
Q_D(KPty);
|
||||
|
||||
// Setup job control //////////////////////////////////
|
||||
|
||||
// Become session leader, process group leader,
|
||||
// and get rid of the old controlling terminal.
|
||||
setsid();
|
||||
|
||||
// make our slave pty the new controlling terminal.
|
||||
#ifdef TIOCSCTTY
|
||||
ioctl(d->slaveFd, TIOCSCTTY, 0);
|
||||
#else
|
||||
// __svr4__ hack: the first tty opened after setsid() becomes controlling tty
|
||||
::close(::open(d->ttyName, O_WRONLY, 0));
|
||||
#endif
|
||||
|
||||
// make our new process group the foreground group on the pty
|
||||
int pgrp = getpid();
|
||||
#if defined(_POSIX_VERSION) || defined(__svr4__)
|
||||
tcsetpgrp(d->slaveFd, pgrp);
|
||||
#elif defined(TIOCSPGRP)
|
||||
ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void KPty::login(const char *user, const char *remotehost)
|
||||
{
|
||||
#ifdef HAVE_UTEMPTER
|
||||
Q_D(KPty);
|
||||
|
||||
addToUtmp(d->ttyName, remotehost, d->masterFd);
|
||||
Q_UNUSED(user);
|
||||
#else
|
||||
# ifdef HAVE_UTMPX
|
||||
struct utmpx l_struct;
|
||||
# else
|
||||
struct utmp l_struct;
|
||||
# endif
|
||||
memset(&l_struct, 0, sizeof(l_struct));
|
||||
// note: strncpy without terminators _is_ correct here. man 4 utmp
|
||||
|
||||
if (user)
|
||||
strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name));
|
||||
|
||||
if (remotehost) {
|
||||
strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host));
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
|
||||
l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host));
|
||||
# endif
|
||||
}
|
||||
|
||||
# ifndef __GLIBC__
|
||||
Q_D(KPty);
|
||||
const char *str_ptr = d->ttyName.data();
|
||||
if (!memcmp(str_ptr, "/dev/", 5))
|
||||
str_ptr += 5;
|
||||
strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_ID
|
||||
strncpy(l_struct.ut_id,
|
||||
str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id),
|
||||
sizeof(l_struct.ut_id));
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_UTMPX
|
||||
gettimeofday(&l_struct.ut_tv, 0);
|
||||
# else
|
||||
l_struct.ut_time = time(0);
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_LOGIN
|
||||
# ifdef HAVE_LOGINX
|
||||
::loginx(&l_struct);
|
||||
# else
|
||||
::login(&l_struct);
|
||||
# endif
|
||||
# else
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_TYPE
|
||||
l_struct.ut_type = USER_PROCESS;
|
||||
# endif
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_PID
|
||||
l_struct.ut_pid = getpid();
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_SESSION
|
||||
l_struct.ut_session = getsid(0);
|
||||
# endif
|
||||
# endif
|
||||
# ifdef HAVE_UTMPX
|
||||
utmpxname(_PATH_UTMPX);
|
||||
setutxent();
|
||||
pututxline(&l_struct);
|
||||
endutxent();
|
||||
updwtmpx(_PATH_WTMPX, &l_struct);
|
||||
# else
|
||||
utmpname(_PATH_UTMP);
|
||||
setutent();
|
||||
pututline(&l_struct);
|
||||
endutent();
|
||||
updwtmp(_PATH_WTMP, &l_struct);
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void KPty::logout()
|
||||
{
|
||||
#ifdef HAVE_UTEMPTER
|
||||
Q_D(KPty);
|
||||
|
||||
removeLineFromUtmp(d->ttyName, d->masterFd);
|
||||
#else
|
||||
Q_D(KPty);
|
||||
|
||||
const char *str_ptr = d->ttyName.data();
|
||||
if (!memcmp(str_ptr, "/dev/", 5))
|
||||
str_ptr += 5;
|
||||
# ifdef __GLIBC__
|
||||
else {
|
||||
const char *sl_ptr = strrchr(str_ptr, '/');
|
||||
if (sl_ptr)
|
||||
str_ptr = sl_ptr + 1;
|
||||
}
|
||||
# endif
|
||||
# ifdef HAVE_LOGIN
|
||||
# ifdef HAVE_LOGINX
|
||||
::logoutx(str_ptr, 0, DEAD_PROCESS);
|
||||
# else
|
||||
::logout(str_ptr);
|
||||
# endif
|
||||
# else
|
||||
# ifdef HAVE_UTMPX
|
||||
struct utmpx l_struct, *ut;
|
||||
# else
|
||||
struct utmp l_struct, *ut;
|
||||
# endif
|
||||
memset(&l_struct, 0, sizeof(l_struct));
|
||||
|
||||
strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
|
||||
|
||||
# ifdef HAVE_UTMPX
|
||||
utmpxname(_PATH_UTMPX);
|
||||
setutxent();
|
||||
if ((ut = getutxline(&l_struct))) {
|
||||
# else
|
||||
utmpname(_PATH_UTMP);
|
||||
setutent();
|
||||
if ((ut = getutline(&l_struct))) {
|
||||
# endif
|
||||
memset(ut->ut_name, 0, sizeof(*ut->ut_name));
|
||||
memset(ut->ut_host, 0, sizeof(*ut->ut_host));
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
|
||||
ut->ut_syslen = 0;
|
||||
# endif
|
||||
# ifdef HAVE_STRUCT_UTMP_UT_TYPE
|
||||
ut->ut_type = DEAD_PROCESS;
|
||||
# endif
|
||||
# ifdef HAVE_UTMPX
|
||||
gettimeofday(ut->ut_tv, 0);
|
||||
pututxline(ut);
|
||||
}
|
||||
endutxent();
|
||||
# else
|
||||
ut->ut_time = time(0);
|
||||
pututline(ut);
|
||||
}
|
||||
endutent();
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// XXX Supposedly, tc[gs]etattr do not work with the master on Solaris.
|
||||
// Please verify.
|
||||
|
||||
bool KPty::tcGetAttr(struct ::termios *ttmode) const
|
||||
{
|
||||
Q_D(const KPty);
|
||||
|
||||
return _tcgetattr(d->masterFd, ttmode) == 0;
|
||||
}
|
||||
|
||||
bool KPty::tcSetAttr(struct ::termios *ttmode)
|
||||
{
|
||||
Q_D(KPty);
|
||||
|
||||
return _tcsetattr(d->masterFd, ttmode) == 0;
|
||||
}
|
||||
|
||||
bool KPty::setWinSize(int lines, int columns)
|
||||
{
|
||||
Q_D(KPty);
|
||||
|
||||
struct winsize winSize;
|
||||
memset(&winSize, 0, sizeof(winSize));
|
||||
winSize.ws_row = (unsigned short)lines;
|
||||
winSize.ws_col = (unsigned short)columns;
|
||||
return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
|
||||
}
|
||||
|
||||
bool KPty::setEcho(bool echo)
|
||||
{
|
||||
struct ::termios ttmode;
|
||||
if (!tcGetAttr(&ttmode))
|
||||
return false;
|
||||
if (!echo)
|
||||
ttmode.c_lflag &= ~ECHO;
|
||||
else
|
||||
ttmode.c_lflag |= ECHO;
|
||||
return tcSetAttr(&ttmode);
|
||||
}
|
||||
|
||||
const char *KPty::ttyName() const
|
||||
{
|
||||
Q_D(const KPty);
|
||||
|
||||
return d->ttyName.data();
|
||||
}
|
||||
|
||||
int KPty::masterFd() const
|
||||
{
|
||||
Q_D(const KPty);
|
||||
|
||||
return d->masterFd;
|
||||
}
|
||||
|
||||
int KPty::slaveFd() const
|
||||
{
|
||||
Q_D(const KPty);
|
||||
|
||||
return d->slaveFd;
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
/* This file is part of the KDE libraries
|
||||
|
||||
Copyright (C) 2003,2007 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef kpty_h
|
||||
#define kpty_h
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
struct KPtyPrivate;
|
||||
struct termios;
|
||||
|
||||
/**
|
||||
* Provides primitives for opening & closing a pseudo TTY pair, assigning the
|
||||
* controlling TTY, utmp registration and setting various terminal attributes.
|
||||
*/
|
||||
class KPty {
|
||||
Q_DECLARE_PRIVATE(KPty)
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
KPty();
|
||||
|
||||
/**
|
||||
* Destructor:
|
||||
*
|
||||
* If the pty is still open, it will be closed. Note, however, that
|
||||
* an utmp registration is @em not undone.
|
||||
*/
|
||||
~KPty();
|
||||
|
||||
/**
|
||||
* Create a pty master/slave pair.
|
||||
*
|
||||
* @return true if a pty pair was successfully opened
|
||||
*/
|
||||
bool open();
|
||||
|
||||
/**
|
||||
* Close the pty master/slave pair.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Close the pty slave descriptor.
|
||||
*
|
||||
* When creating the pty, KPty also opens the slave and keeps it open.
|
||||
* Consequently the master will never receive an EOF notification.
|
||||
* Usually this is the desired behavior, as a closed pty slave can be
|
||||
* reopened any time - unlike a pipe or socket. However, in some cases
|
||||
* pipe-alike behavior might be desired.
|
||||
*
|
||||
* After this function was called, slaveFd() and setCTty() cannot be
|
||||
* used.
|
||||
*/
|
||||
void closeSlave();
|
||||
|
||||
/**
|
||||
* Creates a new session and process group and makes this pty the
|
||||
* controlling tty.
|
||||
*/
|
||||
void setCTty();
|
||||
|
||||
/**
|
||||
* Creates an utmp entry for the tty.
|
||||
* This function must be called after calling setCTty and
|
||||
* making this pty the stdin.
|
||||
* @param user the user to be logged on
|
||||
* @param remotehost the host from which the login is coming. This is
|
||||
* @em not the local host. For remote logins it should be the hostname
|
||||
* of the client. For local logins from inside an X session it should
|
||||
* be the name of the X display. Otherwise it should be empty.
|
||||
*/
|
||||
void login(const char *user = 0, const char *remotehost = 0);
|
||||
|
||||
/**
|
||||
* Removes the utmp entry for this tty.
|
||||
*/
|
||||
void logout();
|
||||
|
||||
/**
|
||||
* Wrapper around tcgetattr(3).
|
||||
*
|
||||
* This function can be used only while the PTY is open.
|
||||
* You will need an #include <termios.h> to do anything useful
|
||||
* with it.
|
||||
*
|
||||
* @param ttmode a pointer to a termios structure.
|
||||
* Note: when declaring ttmode, @c struct @c ::termios must be used -
|
||||
* without the '::' some version of HP-UX thinks, this declares
|
||||
* the struct in your class, in your method.
|
||||
* @return @c true on success, false otherwise
|
||||
*/
|
||||
bool tcGetAttr(struct ::termios *ttmode) const;
|
||||
|
||||
/**
|
||||
* Wrapper around tcsetattr(3) with mode TCSANOW.
|
||||
*
|
||||
* This function can be used only while the PTY is open.
|
||||
*
|
||||
* @param ttmode a pointer to a termios structure.
|
||||
* @return @c true on success, false otherwise. Note that success means
|
||||
* that @em at @em least @em one attribute could be set.
|
||||
*/
|
||||
bool tcSetAttr(struct ::termios *ttmode);
|
||||
|
||||
/**
|
||||
* Change the logical (screen) size of the pty.
|
||||
* The default is 24 lines by 80 columns.
|
||||
*
|
||||
* This function can be used only while the PTY is open.
|
||||
*
|
||||
* @param lines the number of rows
|
||||
* @param columns the number of columns
|
||||
* @return @c true on success, false otherwise
|
||||
*/
|
||||
bool setWinSize(int lines, int columns);
|
||||
|
||||
/**
|
||||
* Set whether the pty should echo input.
|
||||
*
|
||||
* Echo is on by default.
|
||||
* If the output of automatically fed (non-interactive) PTY clients
|
||||
* needs to be parsed, disabling echo often makes it much simpler.
|
||||
*
|
||||
* This function can be used only while the PTY is open.
|
||||
*
|
||||
* @param echo true if input should be echoed.
|
||||
* @return @c true on success, false otherwise
|
||||
*/
|
||||
bool setEcho(bool echo);
|
||||
|
||||
/**
|
||||
* @return the name of the slave pty device.
|
||||
*
|
||||
* This function should be called only while the pty is open.
|
||||
*/
|
||||
const char *ttyName() const;
|
||||
|
||||
/**
|
||||
* @return the file descriptor of the master pty
|
||||
*
|
||||
* This function should be called only while the pty is open.
|
||||
*/
|
||||
int masterFd() const;
|
||||
|
||||
/**
|
||||
* @return the file descriptor of the slave pty
|
||||
*
|
||||
* This function should be called only while the pty slave is open.
|
||||
*/
|
||||
int slaveFd() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
KPty(KPtyPrivate *d);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
KPtyPrivate * const d_ptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,44 @@
|
||||
/* This file is part of the KDE libraries
|
||||
|
||||
Copyright (C) 2003,2007 Oswald Buddenhagen <ossi@kde.org>
|
||||
|
||||
Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef kpty_p_h
|
||||
#define kpty_p_h
|
||||
|
||||
#include "kpty.h"
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
|
||||
struct KPtyPrivate {
|
||||
Q_DECLARE_PUBLIC(KPty)
|
||||
|
||||
KPtyPrivate();
|
||||
bool chownpty(bool grant);
|
||||
|
||||
int masterFd;
|
||||
int slaveFd;
|
||||
|
||||
QByteArray ttyName;
|
||||
|
||||
KPty *q_ptr;
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,222 @@
|
||||
/* Copyright (C) 2008 e_k (e_k@users.sourceforge.net)
|
||||
|
||||
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 "qtermwidget.h"
|
||||
|
||||
#include "Session.h"
|
||||
#include "TerminalDisplay.h"
|
||||
|
||||
using namespace Konsole;
|
||||
|
||||
void *createTermWidget(int startnow, void *parent)
|
||||
{
|
||||
return (void*) new QTermWidget(startnow, (QWidget*)parent);
|
||||
}
|
||||
|
||||
struct TermWidgetImpl
|
||||
{
|
||||
TermWidgetImpl(QWidget* parent = 0);
|
||||
|
||||
TerminalDisplay *m_terminalDisplay;
|
||||
Session *m_session;
|
||||
|
||||
Session* createSession();
|
||||
TerminalDisplay* createTerminalDisplay(Session *session, QWidget* parent);
|
||||
};
|
||||
|
||||
TermWidgetImpl::TermWidgetImpl(QWidget* parent)
|
||||
{
|
||||
this->m_session = createSession();
|
||||
this->m_terminalDisplay = createTerminalDisplay(this->m_session, parent);
|
||||
}
|
||||
|
||||
|
||||
Session *TermWidgetImpl::createSession()
|
||||
{
|
||||
Session *session = new Session();
|
||||
|
||||
session->setTitle(Session::NameRole, "QTermWidget");
|
||||
session->setProgram("/bin/bash");
|
||||
QStringList args("");
|
||||
session->setArguments(args);
|
||||
session->setAutoClose(true);
|
||||
|
||||
session->setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
session->setFlowControlEnabled(true);
|
||||
session->setHistoryType(HistoryTypeBuffer(1000));
|
||||
|
||||
session->setDarkBackground(true);
|
||||
|
||||
session->setKeyBindings("");
|
||||
return session;
|
||||
}
|
||||
|
||||
TerminalDisplay *TermWidgetImpl::createTerminalDisplay(Session *session, QWidget* parent)
|
||||
{
|
||||
// TerminalDisplay* display = new TerminalDisplay(this);
|
||||
TerminalDisplay* display = new TerminalDisplay(parent);
|
||||
|
||||
display->setBellMode(TerminalDisplay::NotifyBell);
|
||||
display->setTerminalSizeHint(true);
|
||||
display->setTripleClickMode(TerminalDisplay::SelectWholeLine);
|
||||
display->setTerminalSizeStartup(true);
|
||||
|
||||
display->setRandomSeed(session->sessionId() * 31);
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
|
||||
QTermWidget::QTermWidget(int startnow, QWidget *parent)
|
||||
:QWidget(parent)
|
||||
{
|
||||
m_impl = new TermWidgetImpl(this);
|
||||
|
||||
init();
|
||||
|
||||
if (startnow && m_impl->m_session) {
|
||||
m_impl->m_session->run();
|
||||
}
|
||||
|
||||
this->setFocus( Qt::OtherFocusReason );
|
||||
m_impl->m_terminalDisplay->resize(this->size());
|
||||
|
||||
this->setFocusProxy(m_impl->m_terminalDisplay);
|
||||
}
|
||||
|
||||
void QTermWidget::startShellProgram()
|
||||
{
|
||||
if ( m_impl->m_session->isRunning() )
|
||||
return;
|
||||
|
||||
m_impl->m_session->run();
|
||||
}
|
||||
|
||||
void QTermWidget::init()
|
||||
{
|
||||
m_impl->m_terminalDisplay->setSize(80, 40);
|
||||
|
||||
QFont font = QApplication::font();
|
||||
font.setFamily("Monospace");
|
||||
font.setPointSize(10);
|
||||
font.setStyleHint(QFont::TypeWriter);
|
||||
setTerminalFont(font);
|
||||
setScrollBarPosition(NoScrollBar);
|
||||
|
||||
m_impl->m_session->addView(m_impl->m_terminalDisplay);
|
||||
|
||||
connect(m_impl->m_session, SIGNAL(finished()), this, SLOT(sessionFinished()));
|
||||
}
|
||||
|
||||
|
||||
QTermWidget::~QTermWidget()
|
||||
{
|
||||
emit destroyed();
|
||||
}
|
||||
|
||||
|
||||
void QTermWidget::setTerminalFont(QFont &font)
|
||||
{
|
||||
if (!m_impl->m_terminalDisplay)
|
||||
return;
|
||||
m_impl->m_terminalDisplay->setVTFont(font);
|
||||
}
|
||||
|
||||
void QTermWidget::setShellProgram(QString &progname)
|
||||
{
|
||||
if (!m_impl->m_session)
|
||||
return;
|
||||
m_impl->m_session->setProgram(progname);
|
||||
}
|
||||
|
||||
void QTermWidget::setArgs(QStringList &args)
|
||||
{
|
||||
if (!m_impl->m_session)
|
||||
return;
|
||||
m_impl->m_session->setArguments(args);
|
||||
}
|
||||
|
||||
void QTermWidget::setTextCodec(QTextCodec *codec)
|
||||
{
|
||||
if (!m_impl->m_session)
|
||||
return;
|
||||
m_impl->m_session->setCodec(codec);
|
||||
}
|
||||
|
||||
void QTermWidget::setColorScheme(int scheme)
|
||||
{
|
||||
switch(scheme) {
|
||||
case COLOR_SCHEME_WHITE_ON_BLACK:
|
||||
m_impl->m_terminalDisplay->setColorTable(whiteonblack_color_table);
|
||||
break;
|
||||
case COLOR_SCHEME_GREEN_ON_BLACK:
|
||||
m_impl->m_terminalDisplay->setColorTable(greenonblack_color_table);
|
||||
break;
|
||||
case COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW:
|
||||
m_impl->m_terminalDisplay->setColorTable(blackonlightyellow_color_table);
|
||||
break;
|
||||
default: //do nothing
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void QTermWidget::setSize(int h, int v)
|
||||
{
|
||||
if (!m_impl->m_terminalDisplay)
|
||||
return;
|
||||
m_impl->m_terminalDisplay->setSize(h, v);
|
||||
}
|
||||
|
||||
void QTermWidget::setHistorySize(int lines)
|
||||
{
|
||||
if (lines < 0)
|
||||
m_impl->m_session->setHistoryType(HistoryTypeFile());
|
||||
else
|
||||
m_impl->m_session->setHistoryType(HistoryTypeBuffer(lines));
|
||||
}
|
||||
|
||||
void QTermWidget::setScrollBarPosition(ScrollBarPosition pos)
|
||||
{
|
||||
if (!m_impl->m_terminalDisplay)
|
||||
return;
|
||||
m_impl->m_terminalDisplay->setScrollBarPosition((TerminalDisplay::ScrollBarPosition)pos);
|
||||
}
|
||||
|
||||
void QTermWidget::sendText(QString &text)
|
||||
{
|
||||
m_impl->m_session->sendText(text);
|
||||
}
|
||||
|
||||
void QTermWidget::resizeEvent(QResizeEvent*)
|
||||
{
|
||||
//qDebug("global window resizing...with %d %d", this->size().width(), this->size().height());
|
||||
m_impl->m_terminalDisplay->resize(this->size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void QTermWidget::sessionFinished()
|
||||
{
|
||||
emit finished();
|
||||
}
|
||||
|
||||
|
||||
//#include "moc_consoleq.cpp"
|
||||
|
@ -0,0 +1,108 @@
|
||||
/* Copyright (C) 2008 e_k (e_k@users.sourceforge.net)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _Q_TERM_WIDGET
|
||||
#define _Q_TERM_WIDGET
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
struct TermWidgetImpl;
|
||||
|
||||
enum COLOR_SCHEME { COLOR_SCHEME_WHITE_ON_BLACK = 1,
|
||||
COLOR_SCHEME_GREEN_ON_BLACK,
|
||||
COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW };
|
||||
|
||||
class QTermWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum ScrollBarPosition
|
||||
{
|
||||
/** Do not show the scroll bar. */
|
||||
NoScrollBar=0,
|
||||
/** Show the scroll bar on the left side of the display. */
|
||||
ScrollBarLeft=1,
|
||||
/** Show the scroll bar on the right side of the display. */
|
||||
ScrollBarRight=2
|
||||
};
|
||||
|
||||
|
||||
//Creation of widget
|
||||
QTermWidget(int startnow = 1, //start shell programm immediatelly
|
||||
QWidget *parent = 0);
|
||||
~QTermWidget();
|
||||
|
||||
//start shell program if it was not started in constructor
|
||||
void startShellProgram();
|
||||
|
||||
//look-n-feel, if you don`t like defaults
|
||||
|
||||
// Terminal font
|
||||
// Default is application font with family Monospace, size 10
|
||||
void setTerminalFont(QFont &font);
|
||||
|
||||
// Shell program, default is /bin/bash
|
||||
void setShellProgram(QString &progname);
|
||||
|
||||
// Shell program args, default is none
|
||||
void setArgs(QStringList &args);
|
||||
|
||||
//Text codec, default is UTF-8
|
||||
void setTextCodec(QTextCodec *codec);
|
||||
|
||||
//Color scheme, default is white on black
|
||||
void setColorScheme(int scheme);
|
||||
|
||||
//set size
|
||||
void setSize(int h, int v);
|
||||
|
||||
// History size for scrolling
|
||||
void setHistorySize(int lines); //infinite if lines < 0
|
||||
|
||||
// Presence of scrollbar
|
||||
void setScrollBarPosition(ScrollBarPosition);
|
||||
|
||||
// Send some text to terminal
|
||||
void sendText(QString &text);
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent *);
|
||||
|
||||
protected slots:
|
||||
void sessionFinished();
|
||||
|
||||
private:
|
||||
void init();
|
||||
TermWidgetImpl *m_impl;
|
||||
};
|
||||
|
||||
|
||||
//Maybe useful, maybe not
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
void *createTermWidget(int startnow, void *parent);
|
||||
|
||||
#endif
|
||||
|
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1 @@
|
||||
License EN
|
@ -0,0 +1 @@
|
||||
Лицензия Русский
|
@ -0,0 +1,9 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>img/calculate-logo.png</file>
|
||||
<file>licenses/en.txt</file>
|
||||
<file>licenses/ru.txt</file>
|
||||
<file>texts/welcome_en.txt</file>
|
||||
<file>texts/complete_en.txt</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -0,0 +1,2 @@
|
||||
Congratulations, the instalation is complete!
|
||||
|
@ -0,0 +1,6 @@
|
||||
<html>
|
||||
Welcome to Calculate Linux.<br>
|
||||
<a href='http://calculate-linux.org'>http://calculate-linux.org</a>
|
||||
<br>
|
||||
<br>
|
||||
</html>
|
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
|
||||
class InstallerPage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
InstallerPage( const QString& title, QObject* parent = 0 ) : QObject(parent), m_Widget(new QWidget()), m_Title(title) {}
|
||||
virtual ~InstallerPage() { delete m_Widget; }
|
||||
|
||||
public:
|
||||
QWidget* getWidget() { return m_Widget; }
|
||||
QString getTitle() { return m_Title; }
|
||||
|
||||
virtual bool validate() = 0;
|
||||
|
||||
public slots:
|
||||
virtual void show() {}
|
||||
|
||||
protected:
|
||||
QWidget* m_Widget;
|
||||
QString m_Title;
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
#include <QtGui/QApplication>
|
||||
|
||||
#include <QTextCodec>
|
||||
#include <QLocale>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "systeminstaller.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
QTextCodec::setCodecForLocale( QTextCodec::codecForName("UTF-8") );
|
||||
QTextCodec::setCodecForTr( QTextCodec::codecForName("UTF-8") );
|
||||
QTextCodec::setCodecForCStrings( QTextCodec::codecForName("UTF-8") );
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// QTranslator localize;
|
||||
|
||||
// app.installTranslator();
|
||||
|
||||
SystemInstaller installer;
|
||||
|
||||
installer.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
#include "pagecfdisk.h"
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QFont>
|
||||
|
||||
//
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "libs/qtermwidget/qtermwidget.h"
|
||||
|
||||
PageCfdisk::PageCfdisk(const QString& title) :
|
||||
InstallerPage(title)
|
||||
{
|
||||
QLabel* label = new QLabel("cfdisk");
|
||||
QWidget* widget = new QWidget;
|
||||
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
QVBoxLayout* vbox_1 = new QVBoxLayout;
|
||||
|
||||
vbox_1->addWidget(label);
|
||||
vbox_1->addWidget(widget);
|
||||
|
||||
m_Term = new QTermWidget;
|
||||
|
||||
QFont font = QApplication::font();
|
||||
font.setFamily("Terminus");
|
||||
font.setPointSize(12);
|
||||
|
||||
m_Term->setTerminalFont(font);
|
||||
m_Term->setParent(widget);
|
||||
|
||||
m_Widget->setLayout(vbox_1);
|
||||
|
||||
connect(m_Term, SIGNAL(finished()), this, SIGNAL(completed()));
|
||||
}
|
||||
|
||||
bool PageCfdisk::validate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void PageCfdisk::show()
|
||||
{
|
||||
QString cmd = "cfdisk /dev/sda && exit \r\n";
|
||||
m_Term->sendText( cmd );
|
||||
m_Term->setFocus();
|
||||
|
||||
m_Term->setSize(100, 200);
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "installerpage.h"
|
||||
|
||||
class QTermWidget;
|
||||
|
||||
class PageCfdisk : public InstallerPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageCfdisk(const QString& title);
|
||||
|
||||
bool validate();
|
||||
|
||||
public slots:
|
||||
void show();
|
||||
//
|
||||
|
||||
signals:
|
||||
void completed();
|
||||
//
|
||||
|
||||
private:
|
||||
QTermWidget* m_Term;
|
||||
|
||||
};
|
||||
|
@ -0,0 +1,78 @@
|
||||
#include "pageconfiguration.h"
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
|
||||
PageConfiguration::PageConfiguration(const QString& title) :
|
||||
InstallerPage(title)
|
||||
{
|
||||
|
||||
QLabel* labelText = new QLabel( tr("Select parameters: ") );
|
||||
|
||||
QHBoxLayout* hbox_1 = new QHBoxLayout;
|
||||
|
||||
QLabel* labelHostName = new QLabel( tr("Hostname:") );
|
||||
m_Hostname = new QLineEdit( "calculate" );
|
||||
|
||||
hbox_1->addWidget(labelHostName);
|
||||
hbox_1->addWidget(m_Hostname);
|
||||
|
||||
QHBoxLayout* hbox_2 = new QHBoxLayout;
|
||||
|
||||
QLabel* langText = new QLabel( tr("Language:") );
|
||||
m_Language = new QComboBox;
|
||||
|
||||
m_Language->addItem("en_EN");
|
||||
m_Language->addItem("ru_RU");
|
||||
|
||||
hbox_2->addWidget(langText);
|
||||
hbox_2->addWidget(m_Language);
|
||||
|
||||
QHBoxLayout* hbox_3 = new QHBoxLayout;
|
||||
|
||||
QLabel* labelFormat = new QLabel( tr("Format") );
|
||||
m_Format = new QComboBox;
|
||||
|
||||
m_Format->addItem( "reiserfs" );
|
||||
m_Format->addItem( "ext2" );
|
||||
m_Format->addItem( "ext3" );
|
||||
m_Format->addItem( "ext4" );
|
||||
m_Format->addItem( "jfs" );
|
||||
m_Format->addItem( "xfs" );
|
||||
|
||||
hbox_3->addWidget(labelFormat);
|
||||
hbox_3->addWidget(m_Format);
|
||||
|
||||
QHBoxLayout* hbox_4 = new QHBoxLayout;
|
||||
|
||||
QLabel* labelTimezone = new QLabel( tr("Timezone:") );
|
||||
m_Timezone = new QComboBox;
|
||||
|
||||
// TODO: load list timezones
|
||||
m_Timezone->addItem( "Europe/Moscow" );
|
||||
m_Timezone->addItem( "Europe/Minsk" );
|
||||
m_Timezone->addItem( "Europe/Kiev" );
|
||||
|
||||
hbox_4->addWidget(labelTimezone);
|
||||
hbox_4->addWidget(m_Timezone);
|
||||
|
||||
QVBoxLayout* vbox_1 = new QVBoxLayout;
|
||||
|
||||
vbox_1->addWidget( labelText );
|
||||
vbox_1->addLayout(hbox_1);
|
||||
vbox_1->addLayout(hbox_2);
|
||||
vbox_1->addLayout(hbox_3);
|
||||
vbox_1->addLayout(hbox_4);
|
||||
vbox_1->addStretch();
|
||||
//
|
||||
|
||||
m_Widget->setLayout( vbox_1 );
|
||||
}
|
||||
|
||||
bool PageConfiguration::validate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "installerpage.h"
|
||||
|
||||
class QComboBox;
|
||||
class QLineEdit;
|
||||
|
||||
class PageConfiguration : public InstallerPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageConfiguration(const QString& title);
|
||||
|
||||
bool validate();
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
QLineEdit* m_Hostname;
|
||||
QComboBox* m_Language;
|
||||
QComboBox* m_Format;
|
||||
QComboBox* m_Timezone;
|
||||
QComboBox* m_Composite;
|
||||
};
|
||||
|
@ -0,0 +1,26 @@
|
||||
#include "pagefinish.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QBoxLayout>
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
PageFinish::PageFinish(const QString& title) :
|
||||
InstallerPage(title)
|
||||
{
|
||||
QLabel* label = new QLabel( LoadTextFile(":/texts/complete_en.txt") );
|
||||
|
||||
label->setWordWrap(true);
|
||||
label->setAlignment( Qt::AlignLeft | Qt::AlignTop );
|
||||
|
||||
QVBoxLayout* vbox = new QVBoxLayout;
|
||||
|
||||
vbox->addWidget(label);
|
||||
|
||||
m_Widget->setLayout(vbox);
|
||||
}
|
||||
|
||||
bool PageFinish::validate()
|
||||
{
|
||||
return true;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "installerpage.h"
|
||||
|
||||
class PageFinish : public InstallerPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageFinish(const QString& title);
|
||||
|
||||
bool validate();
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,35 @@
|
||||
#include "pageinstall.h"
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
#include <QProgressBar>
|
||||
|
||||
PageInstall::PageInstall(const QString& title) :
|
||||
InstallerPage(title)
|
||||
{
|
||||
//QLabel* label = new QLabel( tr("") )
|
||||
|
||||
m_Output = new QTextEdit;
|
||||
m_Output->setReadOnly(true);
|
||||
m_Progress = new QProgressBar(0);
|
||||
|
||||
QVBoxLayout* vbox = new QVBoxLayout;
|
||||
|
||||
vbox->addWidget(m_Output);
|
||||
vbox->addWidget(m_Progress);
|
||||
|
||||
m_Widget->setLayout(vbox);
|
||||
}
|
||||
|
||||
void PageInstall::show()
|
||||
{
|
||||
// emit changeNext(false);
|
||||
// emit changePrev(false);
|
||||
}
|
||||
|
||||
bool PageInstall::validate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "installerpage.h"
|
||||
|
||||
class QTextEdit;
|
||||
class QProgressBar;
|
||||
|
||||
class PageInstall : public InstallerPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageInstall(const QString& title);
|
||||
|
||||
bool validate();
|
||||
|
||||
public slots:
|
||||
void show();
|
||||
|
||||
signals:
|
||||
void changeNext(bool);
|
||||
void changePrev(bool);
|
||||
|
||||
private:
|
||||
QTextEdit* m_Output;
|
||||
QProgressBar* m_Progress;
|
||||
|
||||
};
|
||||
|
@ -0,0 +1,45 @@
|
||||
#include "pagelanguage.h"
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
PageLanguage::PageLanguage(const QString& title) :
|
||||
InstallerPage(title)
|
||||
{
|
||||
// widgets
|
||||
m_labelWelcome = new QLabel( LoadTextFile(":/texts/welcome_en.txt") );
|
||||
m_labelWelcome->setWordWrap( true );
|
||||
m_labelWelcome->setOpenExternalLinks( true );
|
||||
|
||||
m_labelLanguage = new QLabel( tr("Choose a language: ") );
|
||||
|
||||
m_comboboxLanguages = new QComboBox;
|
||||
|
||||
//
|
||||
QHBoxLayout* hbox_1 = new QHBoxLayout;
|
||||
hbox_1->addWidget(m_comboboxLanguages);
|
||||
hbox_1->addStretch();
|
||||
|
||||
//
|
||||
QVBoxLayout* vbox_1 = new QVBoxLayout;
|
||||
vbox_1->addWidget( m_labelWelcome );
|
||||
vbox_1->addWidget( m_labelLanguage );
|
||||
vbox_1->addLayout( hbox_1 );
|
||||
vbox_1->addStretch();
|
||||
|
||||
m_Widget->setLayout(vbox_1);
|
||||
|
||||
// TODO: fill use translate files
|
||||
m_comboboxLanguages->addItem( tr("English") );
|
||||
m_comboboxLanguages->addItem( tr("Russian") );
|
||||
}
|
||||
|
||||
bool PageLanguage::validate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "installerpage.h"
|
||||
|
||||
class QLabel;
|
||||
class QComboBox;
|
||||
class QTextBrowser;
|
||||
|
||||
class PageLanguage : public InstallerPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageLanguage(const QString& title);
|
||||
|
||||
bool validate();
|
||||
|
||||
signals:
|
||||
void changeLanguage(int);
|
||||
|
||||
private:
|
||||
QLabel* m_labelWelcome;
|
||||
QLabel* m_labelLanguage;
|
||||
QComboBox* m_comboboxLanguages;
|
||||
};
|
||||
|
@ -0,0 +1,39 @@
|
||||
#include "pagelicense.h"
|
||||
|
||||
#include <QLayout>
|
||||
#include <QTextEdit>
|
||||
#include <QCheckBox>
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
PageLicense::PageLicense(const QString& title) :
|
||||
InstallerPage(title)
|
||||
{
|
||||
// TODO: select file for locale
|
||||
textLicense = new QTextEdit( LoadTextFile(":/licenses/en.txt") );
|
||||
checkAccept = new QCheckBox( tr("Accept") );
|
||||
connect( checkAccept, SIGNAL(toggled(bool)), this, SIGNAL(changeNext(bool)) );
|
||||
|
||||
QHBoxLayout* hbox_1 = new QHBoxLayout;
|
||||
|
||||
hbox_1->addWidget(checkAccept);
|
||||
hbox_1->addStretch();
|
||||
|
||||
QVBoxLayout* vbox_1 = new QVBoxLayout;
|
||||
|
||||
vbox_1->addWidget(textLicense);
|
||||
vbox_1->addLayout(hbox_1);
|
||||
|
||||
m_Widget->setLayout(vbox_1);
|
||||
}
|
||||
|
||||
bool PageLicense::validate()
|
||||
{
|
||||
emit changeNext(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PageLicense::show()
|
||||
{
|
||||
emit changeNext(checkAccept->isChecked());
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "installerpage.h"
|
||||
|
||||
class QTextEdit;
|
||||
class QCheckBox;
|
||||
|
||||
class PageLicense : public InstallerPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageLicense(const QString& title);
|
||||
|
||||
bool validate();
|
||||
|
||||
public slots:
|
||||
void show();
|
||||
|
||||
signals:
|
||||
void changeNext(bool);
|
||||
|
||||
private:
|
||||
QTextEdit* textLicense;
|
||||
QCheckBox* checkAccept;
|
||||
|
||||
};
|
||||
|
@ -0,0 +1,132 @@
|
||||
#include "pagemanager.h"
|
||||
#include <QStackedWidget>
|
||||
#include <QLabel>
|
||||
|
||||
#include "installerpage.h"
|
||||
|
||||
PageManager::PageManager(QStackedWidget* stackedWidget, QLabel* listLabel, QObject* parent) :
|
||||
QObject(parent),
|
||||
m_StackWidget(stackedWidget),
|
||||
m_ListLabel(listLabel),
|
||||
m_isSinglePage(false)
|
||||
{
|
||||
Q_ASSERT_X( stackedWidget != 0, "PageManager::PageManager", "stackedWidget pointer is 0");
|
||||
Q_ASSERT_X( listLabel != 0, "PageManager::PageManager", "listLabel pointer is 0");
|
||||
|
||||
listLabel->setWordWrap(true);
|
||||
listLabel->setAlignment ( Qt::AlignLeft | Qt::AlignTop );
|
||||
}
|
||||
|
||||
PageManager::~PageManager()
|
||||
{
|
||||
// clear stack widget
|
||||
removeStackedPage();
|
||||
|
||||
qDeleteAll(m_Pages);
|
||||
}
|
||||
|
||||
void PageManager::addPage(InstallerPage* page)
|
||||
{
|
||||
Q_ASSERT_X( page != 0, "PageManager::addPage", "page pointer is 0");
|
||||
|
||||
m_Pages.push_back(page);
|
||||
|
||||
m_CurPage = m_Pages.begin();
|
||||
pageUpdate();
|
||||
|
||||
}
|
||||
|
||||
unsigned int PageManager::getPageCount()
|
||||
{
|
||||
return m_Pages.count();
|
||||
}
|
||||
|
||||
void PageManager::showOnce(InstallerPage* page)
|
||||
{
|
||||
Q_ASSERT_X( page != 0, "PageManager::showOnce", "page pointer is 0");
|
||||
|
||||
if (page)
|
||||
{
|
||||
removeStackedPage();
|
||||
m_isSinglePage = true;
|
||||
m_StackWidget->addWidget( page->getWidget() );
|
||||
m_StackWidget->setCurrentIndex(0);
|
||||
page->show();
|
||||
}
|
||||
|
||||
//pageUpdate();
|
||||
}
|
||||
|
||||
void PageManager::showFirst()
|
||||
{
|
||||
}
|
||||
|
||||
void PageManager::showNext()
|
||||
{
|
||||
if ( !m_isSinglePage && (m_CurPage != m_Pages.end()) && ((m_CurPage + 1) != m_Pages.end()) )
|
||||
{
|
||||
if ((*m_CurPage)->validate())
|
||||
{
|
||||
++m_CurPage;
|
||||
pageUpdate();
|
||||
}
|
||||
}
|
||||
if (m_isSinglePage)
|
||||
{
|
||||
m_isSinglePage = false;
|
||||
pageUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void PageManager::showPrevious()
|
||||
{
|
||||
if ( !m_isSinglePage && (m_CurPage != m_Pages.begin()) )
|
||||
{
|
||||
if ((*m_CurPage)->validate())
|
||||
{
|
||||
--m_CurPage;
|
||||
pageUpdate();
|
||||
}
|
||||
}
|
||||
if (m_isSinglePage)
|
||||
{
|
||||
m_isSinglePage = false;
|
||||
pageUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
void PageManager::pageUpdate()
|
||||
{
|
||||
QString label;
|
||||
|
||||
removeStackedPage();
|
||||
|
||||
m_StackWidget->addWidget( (*m_CurPage)->getWidget() );
|
||||
m_StackWidget->setCurrentIndex(0);
|
||||
|
||||
foreach(InstallerPage* page, m_Pages)
|
||||
{
|
||||
QString title = page->getTitle();
|
||||
|
||||
if (title == (*m_CurPage)->getTitle())
|
||||
{
|
||||
title = "<b>" + title + "</b>";
|
||||
page->show();
|
||||
}
|
||||
title += "<br>";
|
||||
|
||||
label += title;
|
||||
}
|
||||
|
||||
m_ListLabel->setText( label );
|
||||
}
|
||||
|
||||
void PageManager::removeStackedPage()
|
||||
{
|
||||
QWidget* currWidget = m_StackWidget->currentWidget();
|
||||
if (currWidget)
|
||||
{
|
||||
m_StackWidget->removeWidget( currWidget );
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
#ifndef PAGEMANAGER_H
|
||||
#define PAGEMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QLabel;
|
||||
class QStackedWidget;
|
||||
class InstallerPage;
|
||||
|
||||
typedef QList<InstallerPage*>::iterator PageIterator;
|
||||
|
||||
class PageManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PageManager(QStackedWidget* stackedWidget, QLabel* listLabel, QObject* parent = 0);
|
||||
~PageManager();
|
||||
|
||||
public:
|
||||
void addPage(InstallerPage* page);
|
||||
unsigned int getPageCount();
|
||||
|
||||
void showOnce(InstallerPage* page);
|
||||
|
||||
public slots:
|
||||
void showFirst();
|
||||
|
||||
void showNext();
|
||||
void showPrevious();
|
||||
|
||||
private:
|
||||
void pageUpdate();
|
||||
void removeStackedPage();
|
||||
|
||||
private:
|
||||
QStackedWidget* m_StackWidget;
|
||||
QLabel* m_ListLabel;
|
||||
|
||||
QList<InstallerPage*> m_Pages;
|
||||
|
||||
PageIterator m_CurPage;
|
||||
|
||||
bool m_isSinglePage;
|
||||
};
|
||||
|
||||
#endif // PAGEMANAGER_H
|
@ -0,0 +1,67 @@
|
||||
#include "pagepartitioning.h"
|
||||
|
||||
#include <QRadioButton>
|
||||
#include <QPushButton>
|
||||
#include <QComboBox>
|
||||
#include <QBoxLayout>
|
||||
|
||||
|
||||
PagePartitioning::PagePartitioning(const QString& title) :
|
||||
InstallerPage(title)
|
||||
{
|
||||
// widgets
|
||||
m_ButExistPartition = new QRadioButton( tr("Use existing partition") );
|
||||
m_ButAllDisk = new QRadioButton( tr("Use automatical partitioning") );
|
||||
|
||||
m_ButPartitioning = new QPushButton( tr("Manualy partitioning") );
|
||||
|
||||
m_Partitions = new QComboBox;
|
||||
m_Disks = new QComboBox;
|
||||
|
||||
// layouts
|
||||
QHBoxLayout* hbox_1 = new QHBoxLayout;
|
||||
hbox_1->addWidget( m_ButExistPartition );
|
||||
hbox_1->addWidget( m_Partitions );
|
||||
|
||||
QHBoxLayout* hbox_2 = new QHBoxLayout;
|
||||
hbox_2->addWidget( m_ButAllDisk );
|
||||
hbox_2->addWidget( m_Disks );
|
||||
|
||||
QHBoxLayout* hbox_3 = new QHBoxLayout;
|
||||
hbox_3->addWidget( m_ButPartitioning );
|
||||
hbox_3->addStretch();
|
||||
|
||||
QVBoxLayout* vbox_1 = new QVBoxLayout;
|
||||
vbox_1->addLayout(hbox_1);
|
||||
vbox_1->addLayout(hbox_2);
|
||||
vbox_1->addLayout(hbox_3);
|
||||
vbox_1->addStretch();
|
||||
|
||||
m_Widget->setLayout(vbox_1);
|
||||
|
||||
m_ButExistPartition->setChecked(true);
|
||||
m_Disks->setEnabled(false);
|
||||
|
||||
connect(m_ButExistPartition, SIGNAL(toggled(bool)), m_Partitions, SLOT(setEnabled(bool)));
|
||||
connect(m_ButAllDisk, SIGNAL(toggled(bool)), m_Disks, SLOT(setEnabled(bool)));
|
||||
|
||||
connect( m_ButPartitioning, SIGNAL(clicked()), this, SIGNAL(manualyPartitioning()) );
|
||||
|
||||
// TODO: replace code and get data from libparted
|
||||
m_Partitions->addItem( "/dev/sda1 (100G)" );
|
||||
m_Partitions->addItem( "/dev/sda2 (100G)" );
|
||||
m_Partitions->addItem( "/dev/sdb1 (80G)" );
|
||||
|
||||
m_Disks->addItem( "/dev/sda" );
|
||||
m_Disks->addItem( "/dev/sdb" );
|
||||
}
|
||||
|
||||
bool PagePartitioning::validate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void PagePartitioning::show()
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "installerpage.h"
|
||||
|
||||
class QRadioButton;
|
||||
class QPushButton;
|
||||
class QComboBox;
|
||||
|
||||
class PagePartitioning : public InstallerPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PagePartitioning(const QString& title);
|
||||
|
||||
bool validate();
|
||||
|
||||
public slots:
|
||||
void show();
|
||||
|
||||
signals:
|
||||
void manualyPartitioning();
|
||||
|
||||
private:
|
||||
QRadioButton* m_ButExistPartition;
|
||||
QRadioButton* m_ButAllDisk;
|
||||
QPushButton* m_ButPartitioning;
|
||||
|
||||
QComboBox* m_Partitions;
|
||||
QComboBox* m_Disks;
|
||||
};
|
||||
|
@ -0,0 +1,148 @@
|
||||
#include "systeminstaller.h"
|
||||
|
||||
#include <QtGui>
|
||||
#include <QStackedWidget>
|
||||
#include <QPushButton>
|
||||
#include <QGroupBox>
|
||||
|
||||
#include "pagemanager.h"
|
||||
|
||||
#include "pagelanguage.h"
|
||||
#include "pagelicense.h"
|
||||
#include "pagepartitioning.h"
|
||||
#include "pageconfiguration.h"
|
||||
#include "pageinstall.h"
|
||||
#include "pagefinish.h"
|
||||
|
||||
#include "pagecfdisk.h"
|
||||
|
||||
SystemInstaller::SystemInstaller(QWidget *parent) :
|
||||
QMainWindow(parent)
|
||||
{
|
||||
// need for QMainWindow
|
||||
QWidget* centralWidget = new QWidget(this);
|
||||
|
||||
// buttons
|
||||
QHBoxLayout* hbox_buttons = new QHBoxLayout;
|
||||
|
||||
m_butPrev = new QPushButton( tr("Prevoius") );
|
||||
m_butNext = new QPushButton( tr("Next") );
|
||||
|
||||
hbox_buttons->addStretch();
|
||||
hbox_buttons->addWidget( m_butPrev );
|
||||
hbox_buttons->addWidget( m_butNext );
|
||||
|
||||
// right pannel = widget for pages + buttons
|
||||
QStackedWidget* stackPages = new QStackedWidget;
|
||||
|
||||
QVBoxLayout* vbox_1 = new QVBoxLayout;
|
||||
|
||||
QGroupBox* group_box_page = new QGroupBox;
|
||||
|
||||
QVBoxLayout* group_box_page_l = new QVBoxLayout;
|
||||
group_box_page_l->addWidget( stackPages );
|
||||
|
||||
group_box_page->setLayout( group_box_page_l );
|
||||
|
||||
vbox_1->addWidget( group_box_page );
|
||||
vbox_1->addLayout( hbox_buttons );
|
||||
|
||||
// left pannel
|
||||
QLabel* labelPages = new QLabel;
|
||||
QGroupBox* group_box_list = new QGroupBox;
|
||||
|
||||
QVBoxLayout* group_box_list_l = new QVBoxLayout;
|
||||
group_box_list_l->addWidget( labelPages );
|
||||
|
||||
group_box_list->setLayout( group_box_list_l );
|
||||
|
||||
// left + right pannels
|
||||
QHBoxLayout* hbox_2 = new QHBoxLayout;
|
||||
|
||||
hbox_2->addWidget( group_box_list, 2 );
|
||||
hbox_2->addLayout( vbox_1, 8 );
|
||||
|
||||
// all window
|
||||
QVBoxLayout* vbox_2 = new QVBoxLayout(centralWidget);
|
||||
|
||||
m_labelImage = new QLabel("");
|
||||
m_labelImage->setAlignment( Qt::AlignHCenter | Qt::AlignVCenter );
|
||||
|
||||
// logo
|
||||
QImage logo( ":/img/calculate-logo.png" );
|
||||
m_labelImage->setPixmap( QPixmap::fromImage(logo) );
|
||||
|
||||
vbox_2->addWidget( m_labelImage );
|
||||
vbox_2->addLayout( hbox_2 );
|
||||
|
||||
setCentralWidget( centralWidget );
|
||||
|
||||
// minimum size for window
|
||||
setMinimumSize(640, 480);
|
||||
QRect scr = QApplication::desktop()->screenGeometry();
|
||||
move( scr.width() - scr.width()/2 - 640/2, scr.height() - scr.height()/2 - 480/2 );
|
||||
|
||||
// create PageManager and pages
|
||||
m_PageManager = new PageManager(stackPages, labelPages, this);
|
||||
|
||||
PageLanguage* pageLanguage = new PageLanguage( tr("Language") );
|
||||
connect( pageLanguage, SIGNAL(changeLanguage(int)), this, SLOT(changedLanguage(int)) );
|
||||
|
||||
m_PageManager->addPage(pageLanguage);
|
||||
|
||||
PageLicense* pageLicense = new PageLicense( tr("License") );
|
||||
connect( pageLicense, SIGNAL(changeNext(bool)), this, SLOT(changedNext(bool)) );
|
||||
m_PageManager->addPage(pageLicense);
|
||||
|
||||
PagePartitioning* pagePartitoning = new PagePartitioning( tr("Partitioning") );
|
||||
connect(pagePartitoning, SIGNAL(manualyPartitioning()), this, SLOT(doPartitioning()));
|
||||
m_PageManager->addPage(pagePartitoning);
|
||||
|
||||
PageConfiguration* pageConfiguration = new PageConfiguration( tr("Configuring") );
|
||||
m_PageManager->addPage(pageConfiguration);
|
||||
|
||||
PageInstall* pageInstall = new PageInstall( tr("Installing") );
|
||||
m_PageManager->addPage(pageInstall);
|
||||
|
||||
PageFinish* pageFinish = new PageFinish( tr("Complete") );
|
||||
m_PageManager->addPage(pageFinish);
|
||||
|
||||
m_PageManager->showFirst();
|
||||
|
||||
connect( m_butNext, SIGNAL(clicked()), m_PageManager, SLOT(showNext()) );
|
||||
connect( m_butPrev, SIGNAL(clicked()), m_PageManager, SLOT(showPrevious()) );
|
||||
}
|
||||
|
||||
SystemInstaller::~SystemInstaller()
|
||||
{
|
||||
delete m_PageManager;
|
||||
}
|
||||
|
||||
|
||||
void SystemInstaller::changedNext(bool state)
|
||||
{
|
||||
m_butNext->setEnabled(state);
|
||||
}
|
||||
|
||||
void SystemInstaller::changedPrev(bool state)
|
||||
{
|
||||
m_butPrev->setEnabled(state);
|
||||
}
|
||||
|
||||
void SystemInstaller::changedLanguage(int lang)
|
||||
{
|
||||
Q_UNUSED(lang);
|
||||
}
|
||||
|
||||
void SystemInstaller::doPartitioning()
|
||||
{
|
||||
m_PageCfdisk = new PageCfdisk("Partitioning");
|
||||
m_PageManager->showOnce(m_PageCfdisk);
|
||||
connect( m_PageCfdisk, SIGNAL(completed()), this, SLOT(completePartitioning()) );
|
||||
}
|
||||
|
||||
void SystemInstaller::completePartitioning()
|
||||
{
|
||||
delete m_PageCfdisk;
|
||||
m_PageManager->showPrevious();
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
class QPushButton;
|
||||
class QLabel;
|
||||
|
||||
class PageManager;
|
||||
class PageCfdisk;
|
||||
|
||||
class SystemInstaller : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SystemInstaller(QWidget *parent = 0);
|
||||
~SystemInstaller();
|
||||
|
||||
public:
|
||||
|
||||
private:
|
||||
|
||||
private slots:
|
||||
void changedNext(bool);
|
||||
void changedPrev(bool);
|
||||
void changedLanguage(int);
|
||||
|
||||
void doPartitioning();
|
||||
void completePartitioning();
|
||||
|
||||
private:
|
||||
// ui
|
||||
QPushButton* m_butPrev;
|
||||
QPushButton* m_butNext;
|
||||
|
||||
QLabel* m_labelImage;
|
||||
|
||||
PageManager* m_PageManager;
|
||||
|
||||
PageCfdisk* m_PageCfdisk;
|
||||
};
|
||||
|
@ -0,0 +1,17 @@
|
||||
#include "tools.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
QString LoadTextFile(const QString& name)
|
||||
{
|
||||
QString result;
|
||||
|
||||
QFile inputFile(name);
|
||||
if ( inputFile.open(QIODevice::ReadOnly | QIODevice::Text) )
|
||||
{
|
||||
result = QTextStream(&inputFile).readAll();
|
||||
inputFile.close();
|
||||
}
|
||||
return result;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
QString LoadTextFile(const QString& name);
|
Loading…
Reference in new issue