diff options
Diffstat (limited to 'khexedit')
183 files changed, 40949 insertions, 0 deletions
diff --git a/khexedit/Makefile.am b/khexedit/Makefile.am new file mode 100644 index 0000000..bacaa75 --- /dev/null +++ b/khexedit/Makefile.am @@ -0,0 +1,35 @@ +INCLUDES = $(all_includes) + +SUBDIRS = pics lib parts + +bin_PROGRAMS = khexedit + +khexedit_SOURCES = main.cc toplevel.cc hexmanagerwidget.cc \ +hexeditorwidget.cc hextoolwidget.cc hexviewwidget.cc hexbuffer.cc \ +conversion.cc dialog.cc hexvalidator.cc hexclipboard.cc \ +optiondialog.cc printdialogpage.cc statusbarprogress.cc \ +hexprinter.cc hexerror.cc draglabel.cc stringdialog.cc \ +bitswapwidget.cc chartabledialog.cc hexdrag.cc exportdialog.cc \ +fileinfodialog.cc converterdialog.cc listview.cc searchbar.cc + +noinst_HEADERS = toplevel.h hexmanagerwidget.h hexeditorwidget.h \ +hextoolwidget.h hexviewwidget.h hexbuffer.h conversion.h dialog.h \ +hexvalidator.h hexclipboard.h optiondialog.h \ +printdialogpage.h statusbarprogress.h hexprinter.h hexerror.h \ +draglabel.h progress.h hexeditstate.h chartabledialog.h hexdrag.h \ +exportdialog.h fileinfodialog.h converterdialog.h listview.h searchbar.h + +khexedit_METASOURCES = AUTO +khexedit_LDFLAGS = $(all_libraries) $(KDE_RPATH) +khexedit_LDADD = $(LIB_KIO) $(LIB_KDEPRINT) + +xdg_apps_DATA = khexedit.desktop + +KDE_ICON = khexedit + +rcdir = $(kde_datadir)/khexedit +rc_DATA = khexeditui.rc + +messages: rc.cpp + $(EXTRACTRC) parts/kpart/*rc >> rc.cpp + $(XGETTEXT) rc.cpp `find . -name \*.cc -o -name \*.cpp` -o $(podir)/khexedit.pot diff --git a/khexedit/README b/khexedit/README new file mode 100644 index 0000000..ef686b7 --- /dev/null +++ b/khexedit/README @@ -0,0 +1,34 @@ +Overview +-------- +To confuse you these directories mix two binary editor projects. +The first project is the current khexedit app from Espen Sand, +(here called KHE1). The second project is the coming khexedit app +from Friedrich W. H. Kossebau (called KHE2) which has been already +partly moved from kdenonbeta/khexedit2. + + +What to find in which directory: +-------------------------------- +khexedit: + sources of KHE1 + +khexedit/pics: + pictures used by KHE1 + +khexedit/lib: + sources of the basic library of KHE2 + +khexedit/parts: + collection of all parts based on KHE2 + +khexedit/parts/kbytesedit: + sources of the implementation for the service type KHexEdit/KBytesEdit + + +Future plans: +------------- +* inclusion of the KReadWritePart based HexEdit2Part which can handle + GB sized files. (-> KDE 3.3) +* a binary diff editor widget in the KHE2 lib +* binary diff editor widget based parts +* a standalone KHE2 app, replacing KHE1 diff --git a/khexedit/bitswapwidget.cc b/khexedit/bitswapwidget.cc new file mode 100644 index 0000000..212d126 --- /dev/null +++ b/khexedit/bitswapwidget.cc @@ -0,0 +1,323 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <qpainter.h> + +#include <kglobalsettings.h> + +#include "bitswapwidget.h" + +CDigitLabel::CDigitLabel( QWidget *parent, uint digit, const char *name ) + :QLabel(parent, name), mDigit( digit ), mDotPosition( 0 ) +{ + setFocusPolicy( StrongFocus ); + initialize(); +} + +CDigitLabel::~CDigitLabel( void ) +{ + +} + +void CDigitLabel::initialize( void ) +{ + QFont font( KGlobalSettings::generalFont() ); + font.setBold( true ); + setFont( font ); +} + + +void CDigitLabel::paletteChange( const QPalette & ) +{ + update(); +} + + +void CDigitLabel::setValue( uint digit, bool notify ) +{ + if( mDigit != digit ) + { + if( notify == true ) + { + emit valueChanged( this, digit, false ); + } + + mDigit = digit; + update(); + + if( notify == true ) + { + emit valueChanged( this, mDigit, true ); + } + } +} + + +void CDigitLabel::setDotPosition( uint dotPosition ) +{ + if( mDotPosition != dotPosition ) + { + mDotPosition = dotPosition; + update(); + } +} + + + +QSize CDigitLabel::sizeHint( void ) const +{ + int h = fontMetrics().height(); + QSize s( h, h ); // Retangular + return( s ); +} + + +#include <stdio.h> + + +void CDigitLabel::drawContents( QPainter *p ) +{ + QRect cr = contentsRect(); + + if( hasFocus() == true ) + { + p->fillRect( cr, palette().active().highlight() ); + p->setPen( palette().active().highlightedText() ); + } + else + { + p->fillRect( cr, palette().active().base() ); + p->setPen( palette().active().text() ); + } + + if( mDotPosition != 0 ) + { + p->fillRect( cr.x()+2, cr.y()+2, 5, 5, Qt::red ); // UL + /* + if( mDotPosition == 1 ) + { + p->fillRect( cr.x()+2, cr.y()+2, 5, 5, red ); // UL + } + else if( mDotPosition == 2 ) + { + p->fillRect( cr.width()-7, cr.y()+2, 5, 5, red ); // UR + } + else if( mDotPosition == 3 ) + { + p->fillRect( cr.x()+2, cr.height()-7, 5, 5, red ); // LL + } + else if( mDotPosition == 4 ) + { + p->fillRect( cr.width()-7, cr.height()-7, 5, 5, red ); // LR + } + */ + } + + QString text; + text.setNum( mDigit ); + p->drawText( 0, 0, cr.width(), cr.height(), alignment(), text ); + + + +} + + +void CDigitLabel::keyPressEvent( QKeyEvent *e ) +{ + switch ( e->key() ) + { + case Key_Left: + case Key_Up: + emit stepCell( this, false ); + break; + + case Key_Right: + case Key_Down: + emit stepCell( this, true ); + break; + + case Key_Escape: + e->ignore(); // Allow dialog or whatever use this one + return; + break; + + default: + { + int val = e->text()[0].digitValue(); + if( val >= 0 && val <= 7 ) + { + setValue( val, true ); + } + } + break; + } + + e->accept(); +} + + + +CByteWidget::CByteWidget( QWidget *parent, const char *name ) + :QWidget(parent, name) +{ + mHBox = new QHBoxLayout( this, 0 ); + + for( uint i=0; i<8; i++ ) + { + mDigit[i] = new CDigitLabel( this, 7-i ); + mDigit[i]->setLineWidth( 1 ); + mDigit[i]->setFixedSize( mDigit[i]->sizeHint()*2 ); + mDigit[i]->setFrameStyle( QFrame::Panel | QFrame::Sunken ); + mDigit[i]->setAlignment( AlignCenter ); + connect( mDigit[i], SIGNAL(stepCell(const QObject *, bool )), + this, SLOT(stepCell(const QObject *, bool ))); + connect( mDigit[i], SIGNAL(valueChanged(const QObject *, uint, bool )), + this, SLOT(valueChanged(const QObject *, uint, bool ))); + mHBox->addWidget( mDigit[i] ); + } + + mHBox->addStretch(); +} + +CByteWidget::~CByteWidget( void ) +{ + for( uint i=0; i<8; i++ ) { delete mDigit[i]; } + delete mHBox; +} + +void CByteWidget::stepCell( const QObject *obj, bool next ) +{ + for( uint i=0; i<8; i++ ) + { + if( obj == mDigit[i] ) + { + if( next == true ) + { + mDigit[(i+1)%8]->setFocus(); + } + else + { + mDigit[(i+7)%8]->setFocus(); + } + } + } +} + + + +void CByteWidget::valueChanged( const QObject *obj, uint val, bool after ) +{ + if( after == false ) + { + for( uint i=0; i<8; i++ ) + { + if( obj == mDigit[i] ) + { + uint tmp = 7-mDigit[i]->value(); + mDigit[tmp]->setValue( mDigit[i]->value(), false ); + break; + } + } + + + if( mDigit[7-val]->value() != val ) + { + uint tmp = mDigit[7-val]->value(); + mDigit[7-tmp]->setValue( tmp, false ); + mDigit[7-val]->setValue( val, false ); + } + + } + else + { + setBuddy( obj ); + + uint pos = 1; + for( uint i=0; i<8; i++ ) + { + if( mDigit[i]->value() < (7-i) ) + { + mDigit[i]->setDotPosition( pos ); + mDigit[7-mDigit[i]->value()]->setDotPosition( pos ); + pos++; + } + else if( mDigit[i]->value() == (7-i) ) + { + mDigit[i]->setDotPosition( 0 ); + } + } + + } +} + + +void CByteWidget::reset( void ) +{ + for( uint i=0; i<8; i++ ) + { + mDigit[i]->setValue( 7-i, false ); + mDigit[i]->setDotPosition( 0 ); + } +} + + +void CByteWidget::setBuddy( const QObject *obj ) +{ + for( uint i=0; i<8; i++ ) + { + if( obj == mDigit[i] ) + { + uint val = mDigit[i]->value(); + if( val < 8 ) + { + mDigit[7-val]->setValue( 7-i, false ); + } + break; + } + } +} + + + + + +bool CByteWidget::flag( QByteArray &buf ) +{ + bool swapPresent = false; + uint i, j; + + buf.resize( 8 ); + for( i=0; i<8; buf[i++] = 0 ); + + for( i=j=0; i<8; i++ ) + { + if( mDigit[i]->value() < (7-i) ) + { + buf[j] = 7 - i; j++; + buf[j] = mDigit[i]->value(); j++; + swapPresent = true; + } + } + + return( swapPresent ); +} + + +#include "bitswapwidget.moc" diff --git a/khexedit/bitswapwidget.h b/khexedit/bitswapwidget.h new file mode 100644 index 0000000..f1d3582 --- /dev/null +++ b/khexedit/bitswapwidget.h @@ -0,0 +1,101 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _BITSWAP_WIDGET_H_ +#define _BITSWAP_WIDGET_H_ + +#include <qlabel.h> +#include <qlayout.h> +#include <qstring.h> + + +class CDigitLabel : public QLabel +{ + Q_OBJECT + + public: + CDigitLabel( QWidget *parent, uint digit = 0, const char *name=0 ); + ~CDigitLabel( void ); + + virtual QSize sizeHint() const; + inline uint value( void ); + + signals: + void stepCell( const QObject *obj, bool next ); + void valueChanged( const QObject *obj, uint newVal, bool after ); + + public slots: + void setValue( uint digit, bool notify ); + void setDotPosition( uint dotPosition ); + + protected: + void paletteChange( const QPalette & ); + void drawContents( QPainter * ); + virtual void keyPressEvent( QKeyEvent *e ); + + private: + void initialize( void ); + + private: + uint mDigit; + uint mDotPosition; +}; + + +inline uint CDigitLabel::value( void ) +{ + return( mDigit ); +} + + + + +class CByteWidget : public QWidget +{ + Q_OBJECT + + public: + CByteWidget( QWidget *parent, const char *name=0 ); + ~CByteWidget( void ); + + bool flag( QByteArray &buf ); + + public slots: + void reset( void ); + + private slots: + void stepCell( const QObject *obj, bool next ); + void valueChanged( const QObject *obj, uint newVal, bool after ); + + private: + void setBuddy( const QObject *obj ); + + private: + QHBoxLayout *mHBox; + CDigitLabel *mDigit[8]; +}; + + + + + + + +#endif diff --git a/khexedit/chartabledialog.cc b/khexedit/chartabledialog.cc new file mode 100644 index 0000000..1914750 --- /dev/null +++ b/khexedit/chartabledialog.cc @@ -0,0 +1,212 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <limits.h> + +#include <qlabel.h> +#include <qheader.h> +#include <qlayout.h> +#include <qspinbox.h> + +#include <kglobalsettings.h> +#include <klocale.h> +#include <kstdguiitem.h> + +#include "chartabledialog.h" + + +CCharTableDialog::CCharTableDialog( QWidget *parent, const char *name, + bool modal ) + :KDialogBase( Plain, i18n("Character Table"), Help|User1|Cancel, User1, + parent, name, modal, true, KStdGuiItem::insert()) +{ + updateGeometry(); + setHelp( "khexedit/khexedit.html", QString::null ); + + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + mCharacterList = new CListView( plainPage(), "characterList" ); + mCharacterList->setFont( KGlobalSettings::fixedFont() ); + mCharacterList->addColumn( i18n("Decimal") ); + mCharacterList->addColumn( i18n("Hexadecimal") ); + mCharacterList->addColumn( i18n("Octal") ); + mCharacterList->addColumn( i18n("Binary") ); + mCharacterList->addColumn( i18n("Text") ); + mCharacterList->setAllColumnsShowFocus( true ); + mCharacterList->setFrameStyle( QFrame::WinPanel + QFrame::Sunken ); + mCharacterList->setSorting( -1 ); + + // + // I am setting the min. size below + // + //connect( mCharacterList, SIGNAL(doubleClicked(QListViewItem *) ), + //SLOT(startAssign(QListViewItem *))); + + topLayout->addWidget( mCharacterList, 10 ); + + QHBoxLayout *hbox = new QHBoxLayout(); + if( hbox == 0 ) { return; } + topLayout->addLayout( hbox ); + + text = i18n("Insert this number of characters:"); + QLabel *label = new QLabel( text, plainPage() ); + label->setFixedWidth( label->sizeHint().width() ); + hbox->addWidget( label ); + + mInputCountSpin = new QSpinBox( plainPage(), "spin" ); + mInputCountSpin->setMinimumWidth( fontMetrics().maxWidth()*7 ); + mInputCountSpin->setRange( 1, INT_MAX ); + mInputCountSpin->setValue( 1 ); + hbox->addWidget( mInputCountSpin ); + + hbox->addStretch ( 10 ); + + createListData(); + setColumnWidth(); + mCharacterList->setVisibleItem( 15 ); +} + + + +CCharTableDialog::~CCharTableDialog( void ) +{ +} + + +const char *printBinary( uint val ) +{ + static char buf[9]; + for( int i = 0; i < 8; i++ ) + { + buf[7-i] = (val&(1<<i)) ? '1' : '0'; + } + buf[8] = 0; + return( buf ); +} + + +void CCharTableDialog::createListData( void ) +{ + QString d, h, o, b, c; + QListViewItem *item = 0; + + char buf[10]; + memset( buf, 0, sizeof( buf ) ); + + for( uint i=0; i<256; i++ ) + { + d.sprintf("%03d", i ); + h.sprintf("0x%02x", i ); + o.sprintf("%03o", i ); + b.sprintf("%s", printBinary(i) ); + + if( QChar((char)i).isPrint() == true ) + { + c = QChar((char)i); + } + else + { + c = QChar('.'); + } + + item = new QListViewItem( mCharacterList, item, d, h, o, b, c ); + if( i == 0 ) + { + mCharacterList->setSelected( item, true ); + } + + } +} + + +void CCharTableDialog::slotUser1( void ) // Insert +{ + QListViewItem *item = mCharacterList->selectedItem(); + if( item != 0 ) + { + startAssign( item ); + } + +} + +void CCharTableDialog::startAssign( QListViewItem *item ) +{ + QByteArray buf; + if( buf.fill( item->text(0).toInt(), mInputCountSpin->value() ) == false ) + { + return; + } + emit assign( buf ); +} + + +void CCharTableDialog::setColumnWidth( void ) +{ + const QFontMetrics &fm = mCharacterList->fontMetrics(); + int w0, w1, w2, w3, w4; + + w0 = -fm.minLeftBearing() - fm.minRightBearing() + 8 + fm.maxWidth(); + w3 = 0; + + w1 = fm.width( mCharacterList->header()->label(0) ) + w0; + w2 = fm.width('0')*5; + w3 += w1 > w2 ? w1 : w2; + mCharacterList->setColumnWidth( 0, w1 > w2 ? w1 : w2 ); + + w1 = fm.boundingRect( mCharacterList->header()->label(1) ).width() + w0; + w2 = fm.width('0')*6; + w3 += w1 > w2 ? w1 : w2; + mCharacterList->setColumnWidth( 1, w1 > w2 ? w1 : w2 ); + + w1 = fm.boundingRect( mCharacterList->header()->label(2) ).width() + w0; + w2 = fm.width('0')*5; + w3 += w1 > w2 ? w1 : w2; + mCharacterList->setColumnWidth( 2, w1 > w2 ? w1 : w2 ); + + w1 = fm.boundingRect( mCharacterList->header()->label(3) ).width() + w0; + w2 = fm.width('0')*10; + w3 += w1 > w2 ? w1 : w2; + mCharacterList->setColumnWidth( 3, w1 > w2 ? w1 : w2 ); + + w4 = mCharacterList->viewport()->width() - w3; + w1 = fm.boundingRect( mCharacterList->header()->label(4) ).width() + w0; + w2 = fm.width('0')*3; + w1 = w1 > w2 ? w1 : w2; + mCharacterList->setColumnWidth( 4, w1 > w4 ? w1 : w4 ); +} + + +void CCharTableDialog::resizeEvent( QResizeEvent * ) +{ + setColumnWidth(); +} + + +void CCharTableDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + setColumnWidth(); + mCharacterList->setFocus(); +} + + +#include "chartabledialog.moc" diff --git a/khexedit/chartabledialog.h b/khexedit/chartabledialog.h new file mode 100644 index 0000000..a35246b --- /dev/null +++ b/khexedit/chartabledialog.h @@ -0,0 +1,72 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _CHAR_TABLE_DIALOG_H_ +#define _CHAR_TABLE_DIALOG_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +class QLabel; +class QSpinBox; + +#include <kdialogbase.h> +#include "listview.h" + + +class CCharTableDialog : public KDialogBase +{ + Q_OBJECT + + public: + CCharTableDialog( QWidget *parent=0, const char *name=0,bool modal=false ); + ~CCharTableDialog( void ); + + signals: + void assign( const QByteArray &buf ); + + protected slots: + virtual void slotUser1( void ); + virtual void startAssign( QListViewItem * ); + + protected: + virtual void resizeEvent( QResizeEvent *e ); + virtual void showEvent( QShowEvent *e ); + + private: + void createListData( void ); + void setColumnWidth( void ); + + private: + QSpinBox *mInputCountSpin; + CListView *mCharacterList; +}; + +#endif + + + + + + + + + diff --git a/khexedit/configure.in.in b/khexedit/configure.in.in new file mode 100644 index 0000000..8f094fa --- /dev/null +++ b/khexedit/configure.in.in @@ -0,0 +1,8 @@ +# kossebau: copied from kdelibs/configure.in.in for khexedit +AC_LANG_SAVE +AC_LANG_C +dnl AC_C_BIGENDIAN has a bug (one of its tests uses "main()" instead of +dnl "int main()") so C++ compilers would break. Thats why we switch languages +AC_C_BIGENDIAN +AC_LANG_RESTORE +# kossebau end diff --git a/khexedit/conversion.cc b/khexedit/conversion.cc new file mode 100644 index 0000000..7a5c25c --- /dev/null +++ b/khexedit/conversion.cc @@ -0,0 +1,395 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <string.h> + +#include <klocale.h> + +#include "conversion.h" + + +CConversion::CConversion( void ) +{ + setMode( cnvDefault ); +} + + +CConversion::EMode CConversion::mode( void ) +{ + return( (EMode)mState.mode ); +} + +const SEncodeState &CConversion::state( void ) +{ + return( mState ); +} + +QString CConversion::names( unsigned int index ) +{ + static const QString strings[4] = + { + i18n("Default encoding", "Default"), + i18n("EBCDIC"), + i18n("US-ASCII (7 bit)"), + i18n("Unknown"), + }; + + return( strings[ index > cnvUsAscii ? 3 : index ] ); +} + + +const unsigned char *CConversion::tables( EMode cnvMode ) +{ + /* + static unsigned char ebcdicToLatin1[256] = + { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, + 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, + 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, + 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, + 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, + 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, + 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, + 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, + 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, + 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, + 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F + }; + */ + + static unsigned char ebcdicToLatin1[256] = + { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, + 0x20, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, + 0x26, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, + 0xC2, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0xC3, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, + 0xCA, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, + 0xD1, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, + 0x5C, 0x9F, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + }; + + static unsigned char buf[256]; + + + if( cnvMode == cnvEbcdic ) + { + return( ebcdicToLatin1 ); + } + else if( cnvMode == cnvUsAscii ) + { + memset( buf, 0, 256 ); + for( unsigned int i=0; i<127; i++ ) { buf[i] = i; } + return( buf ); + } + else if( cnvMode == cnvDefault ) + { + for( unsigned int i=0; i<256; i++ ) { buf[i] = i; } + return( buf ); + } + else + { + return( 0 ); + } +} + + +void CConversion::setMode( EMode cnvMode ) +{ + const unsigned char *table = tables( cnvMode ); + if( table == 0 ) + { + cnvMode = cnvDefault; + table = tables( cnvMode ); + } + + mState.mode = cnvMode; + mState.name = names( mState.mode ); + memcpy( mData, table, 256 ); +} + + +bool CConversion::lossless( EMode cnvMode ) +{ + const unsigned char *table = tables( cnvMode ); + if( table == 0 ) + { + return( false ); + } + + unsigned char flag[256]; + memset( flag, 0, sizeof( flag ) ); + + for( uint i=0; i<256; i++ ) + { + int index = table[i]; + if( flag[index] != 0 ) + { + return( false ); + } + flag[index] += 1; + } + + return( true ); +} + + + +#if 0 +void CConversion::setMode( EMode cnvMode ) +{ + /* + static unsigned char ebcdicToLatin1[256] = + { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, + 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, + 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, + 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, + 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, + 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, + 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, + 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, + 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0x5B, 0xDE, 0xAE, + 0xAC, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, + 0xBD, 0xBE, 0xDD, 0xA8, 0xAF, 0x5D, 0xB4, 0xD7, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, + 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F + }; + */ + + static unsigned char ebcdicToLatin1[256] = + { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, + 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, + 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, + 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, + 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, + 0x20, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, + 0x26, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + 0x2D, 0x2F, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, + 0xC2, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + 0xC3, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, + 0xCA, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + 0x71, 0x72, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, + 0xD1, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, + 0x5C, 0x9F, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + }; + + + if( cnvMode == cnvEbcdic ) + { + memcpy( mData, ebcdicToLatin1, 256 ); + } + else if( cnvMode == cnvUsAscii ) + { + memset( mData, 0, 256 ); + for( unsigned int i=0; i<127; i++ ) { mData[i] = i; } + } + else + { + for( unsigned int i=0; i<256; i++ ) { mData[i] = i; } + cnvMode = cnvDefault; + } + + mState.mode = cnvMode; + mState.name = names( mState.mode ); +} +#endif + + + + +int CConversion::convert( QByteArray &buf, EMode newMode, CProgress &p ) +{ + if( newMode == mode() ) + { + p.finish(); + return( Err_Success ); + } + + if( buf.isEmpty() ) + { + p.finish(); + setMode( newMode ); + return( Err_Success ); + } + + // + // Make backup + // + const QByteArray tmp( buf.copy() ); + if( tmp.isEmpty() ) + { + p.finish(); + return( Err_NoMemory ); + } + + unsigned char rev[256]; + uint i, sum; + + sum = 0; + + const float total = buf.size() * 2.0; + + // + // Prepare reverse buffer. + // + for( i=0; i < 256; i++ ) + { + rev[(unsigned char)mData[i]] = i; + } + + // + // Normalize + // + for( i=0; i<buf.size(); i++, sum++ ) + { + buf[i] = rev[ (unsigned char)buf[i] ]; + + // + // The expired() function introduces too much overhead in this case + // so it is only executed every 100'th character + // + if( i % 100 == 0 && p.expired() == true ) + { + const int errCode = p.step( (float)sum/ total ); + if( errCode == Err_Stop ) + { + buf = tmp; + p.finish(); + return( Err_OperationAborted ); + } + } + } + + EMode origMode = mode(); + setMode( newMode ); + + // + // Apply new encoding. + // + for( uint i=0; i<buf.size(); i++, sum++ ) + { + buf[i] = mData[ (unsigned char)buf[i] ]; + + // + // The expired() function introduces too much overhead in this case + // so it is only executed every 100'th character + // + if( i % 100 == 0 && p.expired() == true ) + { + const int errCode = p.step( (float)sum/ total ); + if( errCode == Err_Stop ) + { + buf = tmp; + setMode( origMode ); + p.finish(); + return( Err_OperationAborted ); + } + } + } + + p.finish(); + return( Err_Success ); +} + + diff --git a/khexedit/conversion.h b/khexedit/conversion.h new file mode 100644 index 0000000..ef453ca --- /dev/null +++ b/khexedit/conversion.h @@ -0,0 +1,71 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _CONVERSION_H_ +#define _CONVERSION_H_ + +#include <qstring.h> + +#include "progress.h" + + +struct SEncodeState +{ + unsigned int mode; + QString name; +}; + + +class CConversion +{ + public: + enum EMode + { + cnvDefault = 0, + cnvEbcdic, + cnvUsAscii + }; + + public: + CConversion( void ); + + int convert( QByteArray &buf, EMode mode, CProgress &p ); + bool lossless( EMode cnvMode ); + + EMode mode( void ); + const SEncodeState &state( void ); + + unsigned char operator[]( unsigned int i ) const + { + return( mData[i] ); + } + + private: + QString names( unsigned int index ); + const unsigned char *tables( EMode cnvMode ); + void setMode( EMode cnvMode ); + + private: + SEncodeState mState; + unsigned char mData[256]; +}; + + +#endif diff --git a/khexedit/converterdialog.cc b/khexedit/converterdialog.cc new file mode 100644 index 0000000..f8dd9be --- /dev/null +++ b/khexedit/converterdialog.cc @@ -0,0 +1,163 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + + +#include <qlabel.h> +#include <qlayout.h> + +#include <klocale.h> + +#include "converterdialog.h" +#include "hexvalidator.h" + + +CValidateLineEdit::CValidateLineEdit( QWidget *parent, int validateType, + const char *name ) + :QLineEdit( parent, name ), mBusy(false) +{ + mValidator = new CHexValidator( this, (CHexValidator::EState)validateType ); + setValidator( mValidator ); + connect( this, SIGNAL(textChanged(const QString &)), + this, SLOT(convertText(const QString &)) ); +} + + +CValidateLineEdit::~CValidateLineEdit( void ) +{ +} + + +void CValidateLineEdit::setData( const QByteArray &buf ) +{ + if( mBusy == false ) + { + QString text; + mValidator->format( text, buf ); + setText( text ); + } +} + + +void CValidateLineEdit::convertText( const QString &text ) +{ + QByteArray buf; + mValidator->convert( buf, text ); + mBusy = true; // Don't update while editing + emit dataChanged( buf ); + mBusy = false; +} + + + +CConverterDialog::CConverterDialog( QWidget *parent, const char *name, + bool modal ) + :KDialogBase( parent, name, modal, i18n("Converter"), Cancel|User2|User1, + Cancel, true, KStdGuiItem::clear(), i18n("&On Cursor") ) +{ + QWidget *page = new QWidget( this ); + setMainWidget( page ); + + QGridLayout *topLayout = new QGridLayout( page, 6, 2, 0, spacingHint() ); + topLayout->setRowStretch( 5, 10 ); + topLayout->setColStretch( 1, 10 ); + + QLabel *label = new QLabel( i18n("Hexadecimal:"), page ); + topLayout->addWidget( label, 0, 0 ); + label = new QLabel( i18n("Decimal:"), page ); + topLayout->addWidget( label, 1, 0 ); + label = new QLabel( i18n("Octal:"), page ); + topLayout->addWidget( label, 2, 0 ); + label = new QLabel( i18n("Binary:"), page ); + topLayout->addWidget( label, 3, 0 ); + label = new QLabel( i18n("Text:"), page ); + topLayout->addWidget( label, 4, 0 ); + + mHexInput = new CValidateLineEdit( page, CHexValidator::hexadecimal ); + mHexInput->setMinimumWidth( fontMetrics().maxWidth()*17 ); + topLayout->addWidget( mHexInput, 0, 1 ); + mDecInput = new CValidateLineEdit( page, CHexValidator::decimal ); + topLayout->addWidget( mDecInput, 1, 1 ); + mOctInput = new CValidateLineEdit( page, CHexValidator::octal ); + topLayout->addWidget( mOctInput, 2, 1 ); + mBinInput = new CValidateLineEdit( page, CHexValidator::binary ); + topLayout->addWidget( mBinInput, 3, 1 ); + mTxtInput = new CValidateLineEdit( page, CHexValidator::regularText ); + topLayout->addWidget( mTxtInput, 4, 1 ); + + connect( mHexInput, SIGNAL(dataChanged(const QByteArray &)), + this, SLOT(setData(const QByteArray &)) ); + connect( mDecInput, SIGNAL(dataChanged(const QByteArray &)), + this, SLOT(setData(const QByteArray &)) ); + connect( mOctInput, SIGNAL(dataChanged(const QByteArray &)), + this, SLOT(setData(const QByteArray &)) ); + connect( mBinInput, SIGNAL(dataChanged(const QByteArray &)), + this, SLOT(setData(const QByteArray &)) ); + connect( mTxtInput, SIGNAL(dataChanged(const QByteArray &)), + this, SLOT(setData(const QByteArray &)) ); + +} + + +CConverterDialog::~CConverterDialog( void ) +{ +} + + +void CConverterDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + mHexInput->setFocus(); +} + + +void CConverterDialog::setData( const QByteArray &data ) +{ + mHexInput->blockSignals(true); + mDecInput->blockSignals(true); + mOctInput->blockSignals(true); + mBinInput->blockSignals(true); + mTxtInput->blockSignals(true); + mHexInput->setData(data); + mDecInput->setData(data); + mOctInput->setData(data); + mBinInput->setData(data); + mTxtInput->setData(data); + mHexInput->blockSignals(false); + mDecInput->blockSignals(false); + mOctInput->blockSignals(false); + mBinInput->blockSignals(false); + mTxtInput->blockSignals(false); +} + +void CConverterDialog::slotUser1( void ) // Clear +{ + QByteArray buf; + setData( buf ); +} + +void CConverterDialog::slotUser2( void ) // On Cursor +{ + QByteArray buf; + emit probeCursorValue( buf, 1 ); + setData( buf ); +} + + +#include "converterdialog.moc" diff --git a/khexedit/converterdialog.h b/khexedit/converterdialog.h new file mode 100644 index 0000000..f84fe66 --- /dev/null +++ b/khexedit/converterdialog.h @@ -0,0 +1,83 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * 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 _CONVERTER_DIALOG_H_ +#define _CONVERTER_DIALOG_H_ + +#include <qlineedit.h> +#include <kdialogbase.h> + +class CHexValidator; + + +class CValidateLineEdit : public QLineEdit +{ + Q_OBJECT + + public: + CValidateLineEdit( QWidget *parent, int validateType, const char *name=0 ); + ~CValidateLineEdit( void ); + + public slots: + void setData( const QByteArray &buf ); + + private slots: + void convertText( const QString &text ); + + signals: + void dataChanged( const QByteArray &buf ); + + private: + bool mBusy; + CHexValidator *mValidator; +}; + + +class CConverterDialog : public KDialogBase +{ + Q_OBJECT + + public: + CConverterDialog( QWidget *parent, const char *name=0, bool modal=true ); + ~CConverterDialog( void ); + + protected: + void showEvent( QShowEvent *e ); + + protected slots: + virtual void slotUser1( void ); + virtual void slotUser2( void ); + + private slots: + void setData( const QByteArray &data ); + + signals: + void probeCursorValue( QByteArray &buf, uint size ); + + private: + CValidateLineEdit *mHexInput; + CValidateLineEdit *mDecInput; + CValidateLineEdit *mOctInput; + CValidateLineEdit *mBinInput; + CValidateLineEdit *mTxtInput; +}; + +#endif + diff --git a/khexedit/dialog.cc b/khexedit/dialog.cc new file mode 100644 index 0000000..6ef1273 --- /dev/null +++ b/khexedit/dialog.cc @@ -0,0 +1,1433 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <ctype.h> +#include <iostream> +#include <limits.h> + +#include <qbuttongroup.h> +#include <qfileinfo.h> +#include <qlayout.h> +#include <qvalidator.h> + +#include <kfiledialog.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kseparator.h> +#include <kstdguiitem.h> + +#include "dialog.h" +#include <qpushbutton.h> + +static const QStringList &formatStrings( void ); +static const QStringList &operationStrings( void ); + + +CGotoDialog::CGotoDialog( QWidget *parent, const char *name, bool modal ) + :KDialogBase( Plain, i18n("Goto Offset"), Ok|Cancel, Ok, parent, name, + modal ) +{ + QVBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + QVBoxLayout *vbox = new QVBoxLayout(); + if( vbox == 0 ) { return; } + topLayout->addLayout( vbox ); + + mComboBox = new QComboBox( true, plainPage() ); + if( mComboBox == 0 ) { return; } + mComboBox->setMaxCount( 10 ); + mComboBox->setInsertionPolicy( QComboBox::AtTop ); + mComboBox->setMinimumWidth( fontMetrics().maxWidth()*17 ); + + QLabel *label = new QLabel( mComboBox, i18n("O&ffset:"), plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mComboBox ); + + QButtonGroup *group = new QButtonGroup( i18n("Options"), plainPage() ); + if( group == 0 ) { return; } + topLayout->addWidget( group, 10 ); + + QGridLayout *gbox = new QGridLayout( group, 4, 2, spacingHint() ); + if( gbox == 0 ) { return; } + gbox->addRowSpacing( 0, fontMetrics().lineSpacing() ); + mCheckFromCursor = new QCheckBox( i18n("&From cursor"), group ); + gbox->addWidget( mCheckFromCursor, 1, 0 ); + mCheckBackward = new QCheckBox( i18n("&Backwards"), group ); + gbox->addWidget( mCheckBackward, 1, 1 ); + mCheckVisible = new QCheckBox( i18n("&Stay visible"), group ); + gbox->addWidget( mCheckVisible, 2, 0 ); + gbox->setRowStretch( 3, 10 ); + + KConfig &config = *kapp->config(); + config.setGroup("Goto Dialog"); + mCheckFromCursor->setChecked( config.readBoolEntry( "FromCursor", false ) ); + mCheckVisible->setChecked( config.readBoolEntry( "StayVisible", true ) ); + mCheckBackward->setChecked( config.readBoolEntry( "Backwards", false ) ); +} + + + +CGotoDialog::~CGotoDialog( void ) +{ + KConfig &config = *kapp->config(); + config.setGroup("Goto Dialog"); + config.writeEntry( "FromCursor", mCheckFromCursor->isChecked() ); + config.writeEntry( "StayVisible", mCheckVisible->isChecked() ); + config.writeEntry( "Backwards", mCheckBackward->isChecked() ); + config.sync(); +} + + + +void CGotoDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + mComboBox->setFocus(); +} + + + +// +// Format of input string: +// 0x<HexNumber>|<DecimalNumber>s<Bit> +// s = :,. or space +// +void CGotoDialog::slotOk( void ) +{ + uint offset; + bool success = stringToOffset( mComboBox->currentText(), offset ); + if( success == false ) + { + showEntryFailure( this, QString("") ); + return; + } + + if( mCheckVisible->isChecked() == false ) + { + hide(); + } + emit gotoOffset( offset, 7, mCheckFromCursor->isChecked(), + mCheckBackward->isChecked() == true ? false : true ); + + #if 0 + const char *p = mComboBox->currentText(); + if( strlen( p ) == 0 ) + { + return; + } + + // + // Skip any whitespaces in front of string + // + for( ; *p != 0 && isspace( *p ) ; p++ ); + + uint offset, bit; + int match; + if( strncmp( p, "0x", 2 ) == 0 || strncmp( p, "0X", 2 ) == 0 ) + { + match = sscanf( p+2, "%x", &offset ); + } + else + { + match = sscanf( p, "%u", &offset ); + } + + if( match == 0 ) + { + return; + } + + bit = 7; + + p = strpbrk( p, ":,. " ); + if( p != 0 ) + { + match = sscanf( p+1, "%u", &bit ); + if( match == 0 ) + { + return; + } + if( bit > 7 ) { bit = 7; } + } + #endif +} + + + +CFindDialog::CFindDialog( QWidget *parent, const char *name, bool modal ) + :KDialogBase( Plain, i18n("Find"), Ok|Cancel, Ok, parent, name, modal ) +{ + + QVBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + QVBoxLayout *vbox = new QVBoxLayout(); + if( vbox == 0 ) { return; } + topLayout->addLayout( vbox ); + + mSelector = new QComboBox( false, plainPage() ); + if( mSelector == 0 ) { return; } + mSelector->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mSelector->insertStringList( formatStrings() ); + connect( mSelector, SIGNAL(activated(int)), SLOT(selectorChanged(int)) ); + + QLabel *label = new QLabel( mSelector, i18n("Fo&rmat:"), plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mSelector ); + + mInput = new QLineEdit( plainPage() ); + if( mInput == 0 ) { return; } + mInput->setMinimumWidth( fontMetrics().maxWidth()*17 ); + connect( mInput, SIGNAL(textChanged(const QString&)), + SLOT(inputChanged(const QString&)) ); + mFindValidator = new CHexValidator( this, CHexValidator::regularText ); + if( mFindValidator == 0 ) { return; } + mInput->setValidator( mFindValidator ); + + label = new QLabel( mInput, i18n("F&ind:"), plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mInput ); + + QButtonGroup *group = new QButtonGroup( i18n("Options"), plainPage() ); + if( group == 0 ) { return; } + topLayout->addWidget( group, 10 ); + + QGridLayout *gbox = new QGridLayout( group, 5, 2, spacingHint() ); + if( gbox == 0 ) { return; } + gbox->addRowSpacing( 0, fontMetrics().lineSpacing() ); + + mCheckFromCursor = new QCheckBox( i18n("&From cursor"), group ); + gbox->addWidget( mCheckFromCursor, 1, 0 ); + mCheckBackward = new QCheckBox( i18n("&Backwards"), group ); + gbox->addWidget( mCheckBackward, 1, 1 ); + mCheckInSelection = new QCheckBox( i18n("&In selection"), group ); + gbox->addWidget( mCheckInSelection, 2, 0 ); + mCheckUseNavigator = new QCheckBox( i18n("&Use navigator"),group); + gbox->addWidget( mCheckUseNavigator, 2, 1 ); + mCheckIgnoreCase = new QCheckBox( i18n("Ignore c&ase"),group); + gbox->addWidget( mCheckIgnoreCase, 3, 0 ); + gbox->setRowStretch( 4, 10 ); + + KConfig &config = *kapp->config(); + config.setGroup("Find Dialog"); + mCheckFromCursor->setChecked( config.readBoolEntry( "FromCursor", true ) ); + mCheckInSelection->setChecked( config.readBoolEntry( "InSelection", false) ); + mCheckIgnoreCase->setChecked( config.readBoolEntry( "IgnoreCase", false ) ); + mCheckBackward->setChecked( config.readBoolEntry( "Backwards", false ) ); + mCheckUseNavigator->setChecked( config.readBoolEntry( "UseNavigator", true)); + uint val = config.readUnsignedNumEntry( "Format", 0 ); + mSelector->setCurrentItem(QMIN(4,val) ); + selectorChanged( mSelector->currentItem() ); + enableButtonOK(!mInput->text().isEmpty()); +} + + +CFindDialog::~CFindDialog( void ) +{ + KConfig &config = *kapp->config(); + config.setGroup("Find Dialog"); + config.writeEntry( "FromCursor", mCheckFromCursor->isChecked() ); + config.writeEntry( "InSelection", mCheckInSelection->isChecked() ); + config.writeEntry( "IgnoreCase", mCheckIgnoreCase->isChecked() ); + config.writeEntry( "Backwards", mCheckBackward->isChecked() ); + config.writeEntry( "UseNavigator", mCheckUseNavigator->isChecked() ); + config.writeEntry( "Format", mSelector->currentItem() ); + config.sync(); +} + + +void CFindDialog::selectorChanged( int index ) +{ + mFindValidator->setState( (CHexValidator::EState)index ); + mInput->setText( mFindString[ index ] ); + mCheckIgnoreCase->setEnabled( index == 4 ); +} + + +void CFindDialog::inputChanged( const QString &text ) +{ + mFindString[ mSelector->currentItem() ] = text; + mFindValidator->convert( mFindData, + mFindString[ mSelector->currentItem() ] ); + enableButtonOK(!text.isEmpty()); +} + + +void CFindDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + mInput->setFocus(); +} + + +bool CFindDialog::isEmpty( void ) +{ + return( mFindData.isEmpty() ); +} + + +void CFindDialog::slotOk( void ) +{ + if( isEmpty() == true ) + { + showEntryFailure( this, QString("") ); + return; + } + + SSearchControl sc; + sc.key = mFindData; + sc.keyType = mSelector->currentItem(); + sc.fromCursor = mCheckFromCursor->isChecked(); + sc.inSelection = mCheckInSelection->isChecked(); + sc.forward = mCheckBackward->isChecked() == true ? false : true; + sc.ignoreCase = mCheckIgnoreCase->isEnabled() && mCheckIgnoreCase->isChecked(); + + hide(); + emit findData( sc, Find_First, mCheckUseNavigator->isChecked() ); +} + + +void CFindDialog::findAgain( EOperation operation ) +{ + if( isEmpty() == true ) + { + showEntryFailure( this, QString("") ); + return; + } + + SSearchControl sc; + sc.key = mFindData; + sc.fromCursor = true; + sc.inSelection = mCheckInSelection->isChecked(); + sc.ignoreCase = mCheckIgnoreCase->isEnabled() && mCheckIgnoreCase->isChecked(); + if( operation == find_Next ) + { + sc.forward = true; + } + else if( operation == find_Previous ) + { + sc.forward = false; + } + else + { + sc.forward = mCheckBackward->isChecked() == true ? false : true; + } + + hide(); + emit findData( sc, Find_Next, false ); +} + + + +CFindNavigatorDialog::CFindNavigatorDialog( QWidget *parent, const char *name, + bool modal ) + :KDialogBase( Plain, i18n("Find (Navigator)"), User3|User2|User1|Close, + User2, parent, name, modal, true, i18n("New &Key"), + i18n("&Next"), i18n("&Previous") ) +{ + QString text; + QBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + topLayout->addSpacing( spacingHint() ); // A little bit extra space + + QHBoxLayout *hbox = new QHBoxLayout(); + if( hbox == 0 ) { return; } + topLayout->addLayout( hbox ); + + text = i18n("Searching for:"); + QLabel *label = new QLabel( text, plainPage() ); + hbox->addWidget( label ); + + mKey = new QLineEdit( plainPage() ); + mKey->setMinimumWidth( fontMetrics().width("M") * 20 ); + mKey->setFocusPolicy( QWidget::NoFocus ); + hbox->addWidget( mKey ); + + topLayout->addSpacing( spacingHint() ); // A little bit extra space + topLayout->addStretch(10); +} + + +CFindNavigatorDialog::~CFindNavigatorDialog( void ) +{ +} + + +void CFindNavigatorDialog::defineData( SSearchControl &sc ) +{ + mSearchControl = sc; + mSearchControl.key.duplicate( sc.key ); + + if( mSearchControl.key.isEmpty() == true ) + { + mKey->setText(""); + return; + } + + if( mSearchControl.keyType == 0 ) + { + QString str; + for( uint i=0; i<mSearchControl.key.size(); i++ ) + { + str += mSearchControl.key[i]; + } + mKey->setText( str ); + + } + else if( mSearchControl.keyType == 1 ) + { + QString str("0x "); + for( uint i=0; i<mSearchControl.key.size(); i++ ) + { + str += QString().sprintf("%02X ", (unsigned char)mSearchControl.key[i]); + } + mKey->setText( str ); + } + else if( mSearchControl.keyType == 2 ) + { + QString str; + for( uint i=0; i<mSearchControl.key.size(); i++ ) + { + str += QString().sprintf("%03o ", (unsigned char)mSearchControl.key[i]); + } + mKey->setText( str ); + } + else + { + char buf[10]; + memset( buf, 0, sizeof( buf ) ); buf[8] = ' '; + + QString str; + for( uint i=0; i<mSearchControl.key.size(); i++ ) + { + unsigned char data = (unsigned char)mSearchControl.key[i]; + for( int j = 0; j < 8; j++ ) + { + buf[7-j] = (data&(1<<j)) ? '1' : '0'; + } + str += buf; + } + mKey->setText( str ); + } +} + + +void CFindNavigatorDialog::slotUser3( void ) // Previous +{ + done( repPrevious ); +} + + +void CFindNavigatorDialog::slotUser2( void ) // Next +{ + done( repNext ); +} + + +void CFindNavigatorDialog::slotUser1( void ) // New key +{ + done( repNewKey ); +} + + +void CFindNavigatorDialog::slotClose( void ) +{ + done( repClose ); +} + + +void CFindNavigatorDialog::done( int resultCode ) +{ + setResult( resultCode ); + if( resultCode == repClose || resultCode == repNewKey ) + { + if( resultCode == repNewKey ) + { + emit makeKey(); + } + hide(); + return; + } + + mSearchControl.forward = resultCode == repNext ? true : false; + emit findData( mSearchControl, Find_Next, true ); +} + + + + +CReplaceDialog::CReplaceDialog( QWidget *parent, const char *name, bool modal ) + :KDialogBase( Plain, i18n("Find & Replace"), Ok|Cancel, Ok, + parent, name, modal ) +{ + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + QVBoxLayout *vbox = new QVBoxLayout(); + if( vbox == 0 ) { return; } + topLayout->addLayout( vbox ); + + + mFindSelector = new QComboBox( false, plainPage() ); + if( mFindSelector == 0 ) { return; } + mFindSelector->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mFindSelector->insertStringList( formatStrings() ); + connect( mFindSelector, SIGNAL(activated(int)), + SLOT(findSelectorChanged(int)) ); + + text = i18n("Fo&rmat (find):"); + QLabel *label = new QLabel( mFindSelector, text, plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mFindSelector ); + + mFindInput = new QLineEdit( plainPage() ); + if( mFindInput == 0 ) { return; } + mFindInput->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mFindValidator = new CHexValidator( this, CHexValidator::regularText ); + if( mFindValidator == 0 ) { return; } + mFindInput->setValidator( mFindValidator ); + connect( mFindInput, SIGNAL(textChanged(const QString&)), + SLOT(findInputChanged(const QString&)) ); + + label = new QLabel( mFindInput, i18n("F&ind:"), plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mFindInput ); + + mReplaceSelector = new QComboBox( false, plainPage() ); + if( mReplaceSelector == 0 ) { return; } + mReplaceSelector->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mReplaceSelector->insertStringList( formatStrings() ); + connect( mReplaceSelector, SIGNAL(activated(int)), + SLOT(replaceSelectorChanged(int)) ); + + text = i18n("For&mat (replace):"); + label = new QLabel( mReplaceSelector, text, plainPage() ); + if( label == 0 ) { return; } + label->setFixedHeight( label->sizeHint().height() ); + + vbox->addWidget( label ); + vbox->addWidget( mReplaceSelector ); + + mReplaceInput = new QLineEdit( plainPage() ); + if( mReplaceInput == 0 ) { return; } + mReplaceInput->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mReplaceValidator = new CHexValidator( this, CHexValidator::regularText ); + if( mReplaceValidator == 0 ) { return; } + mReplaceInput->setValidator( mReplaceValidator ); + connect( mReplaceInput, SIGNAL(textChanged(const QString&)), + SLOT(replaceInputChanged(const QString&)) ); + + label = new QLabel( mReplaceInput, i18n("Rep&lace:"), plainPage() ); + if( label == 0 ) { return; } + label->setFixedHeight( label->sizeHint().height() ); + + vbox->addWidget( label ); + vbox->addWidget( mReplaceInput ); + + QButtonGroup *group = new QButtonGroup( i18n("Options"), plainPage() ); + if( group == 0 ) { return; } + topLayout->addWidget( group, 10 ); + + QGridLayout *gbox = new QGridLayout( group, 5, 2, spacingHint() ); + if( gbox == 0 ) { return; } + gbox->addRowSpacing( 0, fontMetrics().lineSpacing() ); + mCheckFromCursor = new QCheckBox( i18n("&From cursor"), group ); + gbox->addWidget( mCheckFromCursor, 1, 0 ); + mCheckBackward = new QCheckBox( i18n("&Backwards"), group ); + gbox->addWidget( mCheckBackward, 1, 1 ); + mCheckInSelection = new QCheckBox( i18n("&In selection"), group ); + gbox->addWidget( mCheckInSelection, 2, 0 ); + mCheckPrompt = new QCheckBox( i18n("&Prompt"), group ); + gbox->addWidget( mCheckPrompt, 2, 1 ); + mCheckIgnoreCase = new QCheckBox( i18n("Ignore c&ase"), group ); + gbox->addWidget( mCheckIgnoreCase, 3, 0 ); + gbox->setRowStretch( 4, 10 ); + + KConfig &config = *kapp->config(); + config.setGroup("Replace Dialog"); + mCheckFromCursor->setChecked( config.readBoolEntry( "FromCursor", true ) ); + mCheckInSelection->setChecked( config.readBoolEntry( "InSelection", false) ); + mCheckIgnoreCase->setChecked( config.readBoolEntry( "IgnoreCase", false ) ); + mCheckBackward->setChecked( config.readBoolEntry( "Backwards", false ) ); + mCheckPrompt->setChecked( config.readBoolEntry( "Prompt", true)); + uint val = config.readUnsignedNumEntry( "FindFormat", 0 ); + mFindSelector->setCurrentItem(QMIN(4,val) ); + findSelectorChanged( mFindSelector->currentItem() ); + val = config.readUnsignedNumEntry( "ReplaceFormat", 0 ); + mReplaceSelector->setCurrentItem(QMIN(4,val) ); + replaceSelectorChanged( mReplaceSelector->currentItem() ); + enableButtonOK(!mFindInput->text().isEmpty()); +} + + +CReplaceDialog::~CReplaceDialog( void ) +{ + KConfig &config = *kapp->config(); + config.setGroup("Replace Dialog"); + config.writeEntry( "FromCursor", mCheckFromCursor->isChecked() ); + config.writeEntry( "InSelection", mCheckInSelection->isChecked() ); + config.writeEntry( "IgnoreCase", mCheckIgnoreCase->isChecked() ); + config.writeEntry( "Backwards", mCheckBackward->isChecked() ); + config.writeEntry( "Prompt", mCheckPrompt->isChecked() ); + config.writeEntry( "FindFormat", mFindSelector->currentItem() ); + config.writeEntry( "ReplaceFormat", mReplaceSelector->currentItem() ); + config.sync(); +} + + +void CReplaceDialog::findSelectorChanged( int index ) +{ + mFindValidator->setState( (CHexValidator::EState)index ); + mFindInput->setText( mFindString[ index ] ); + mCheckIgnoreCase->setEnabled( index == 4 ); +} + + +void CReplaceDialog::findInputChanged( const QString &text ) +{ + mFindString[ mFindSelector->currentItem() ] = text; + mFindValidator->convert( mFindData, + mFindString[ mFindSelector->currentItem() ] ); + enableButtonOK(!text.isEmpty()); +} + + +void CReplaceDialog::replaceSelectorChanged( int index ) +{ + mReplaceValidator->setState( (CHexValidator::EState)index ); + mReplaceInput->setText( mReplaceString[ index ] ); +} + + +void CReplaceDialog::replaceInputChanged( const QString &text ) +{ + mReplaceString[ mReplaceSelector->currentItem() ] = text; + mReplaceValidator->convert( mReplaceData, + mReplaceString[ mReplaceSelector->currentItem() ] ); +} + + +void CReplaceDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + mFindInput->setFocus(); +} + + +void CReplaceDialog::slotOk( void ) +{ + if( mFindData.isEmpty() == true ) + { + showEntryFailure( this, QString("") ); + return; + } + + if( mFindData == mReplaceData ) + { + showEntryFailure( this,i18n("Source and target values can not be equal.")); + return; + } + + hide(); + + SSearchControl sc; + sc.key = mFindData; + sc.val = mReplaceData; + sc.fromCursor = mCheckFromCursor->isChecked(); + sc.inSelection = mCheckInSelection->isChecked(); + sc.forward = mCheckBackward->isChecked() == true ? false : true; + + sc.ignoreCase = mCheckIgnoreCase->isEnabled() && mCheckIgnoreCase->isChecked(); + + emit replaceData( sc, mCheckPrompt->isChecked() ? Replace_First: Replace_AllInit ); +} + + + + + +CReplacePromptDialog::CReplacePromptDialog( QWidget *parent, const char *name, + bool modal ) + :KDialogBase( Plain, i18n("Find & Replace"), User3|User2|User1|Close, + User2, parent, name, modal, true, i18n("Replace &All"), + i18n("Do Not Replace"), i18n("Replace")) +{ + QString text; + QBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + topLayout->addSpacing( spacingHint() ); // A little bit extra space + + text = i18n("Replace marked data at cursor position?"); + QLabel* label = new QLabel( text, plainPage() ); + topLayout->addWidget( label ); + + topLayout->addSpacing( spacingHint() ); // A little bit extra space + topLayout->addStretch(10); +} + + +CReplacePromptDialog::~CReplacePromptDialog( void ) +{ +} + + +void CReplacePromptDialog::defineData( SSearchControl &sc ) +{ + mSearchControl = sc; + mSearchControl.key.duplicate( sc.key ); + mSearchControl.val.duplicate( sc.val ); +} + + +void CReplacePromptDialog::slotUser3( void ) +{ + done( repYes ); +} + + +void CReplacePromptDialog::slotUser2( void ) +{ + done( repNo ); +} + + +void CReplacePromptDialog::slotUser1( void ) +{ + done( repAll ); +} + + +void CReplacePromptDialog::slotClose( void ) +{ + done( repClose ); +} + + +void CReplacePromptDialog::done( int returnCode ) +{ + if( returnCode == repClose ) + { + hide(); + } + else if( returnCode == repYes ) + { + emit replaceData( mSearchControl, Replace_Next ); + } + else if( returnCode == repNo ) + { + emit replaceData( mSearchControl, Replace_Ignore ); + } + else + { + emit replaceData( mSearchControl, Replace_All ); + } +} + + + + +CFilterDialog::CFilterDialog( QWidget *parent, const char *name, bool modal ) + :KDialogBase( Plain, i18n("Binary Filter"), Ok|Cancel, Ok, + parent, name, modal ) +{ + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + QVBoxLayout *vbox = new QVBoxLayout(); + if( vbox == 0 ) { return; } + topLayout->addLayout( vbox ); + + + mOperationSelector = new QComboBox( false, plainPage() ); + if( mOperationSelector == 0 ) { return; } + mOperationSelector->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mOperationSelector->insertStringList( operationStrings() ); + connect( mOperationSelector, SIGNAL(activated(int)), + SLOT(operationSelectorChanged(int)) ); + + text = i18n("O&peration:"); + QLabel *label = new QLabel( mOperationSelector, text, plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mOperationSelector ); + + KSeparator *separator = new KSeparator( plainPage() ); + separator->setOrientation( QFrame::HLine ); + vbox->addWidget( separator ); + + + mWidgetStack = new QWidgetStack( plainPage(), "pagestack" ); + if( mWidgetStack == 0 ) { return; } + vbox->addWidget( mWidgetStack ); + + makeEmptyLayout(); + makeOperandLayout(); + makeBitSwapLayout(); + makeRotateLayout(); + mWidgetStack->raiseWidget( (int)OperandPage ); + + + QButtonGroup *group = new QButtonGroup( i18n("Options"), plainPage() ); + if( group == 0 ) { return; } + topLayout->addWidget( group, 10 ); + + QGridLayout *gbox = new QGridLayout( group, 4, 2, spacingHint() ); + if( gbox == 0 ) { return; } + gbox->addRowSpacing( 0, fontMetrics().lineSpacing() ); + mCheckFromCursor = new QCheckBox( i18n("&From cursor"), group ); + gbox->addWidget( mCheckFromCursor, 1, 0 ); + mCheckBackward = new QCheckBox( i18n("&Backwards"), group ); + gbox->addWidget( mCheckBackward, 1, 1 ); + mCheckInSelection = new QCheckBox( i18n("&In selection"), group ); + gbox->addWidget( mCheckInSelection, 2, 0 ); + mCheckVisible = new QCheckBox( i18n("&Stay visible"), group ); + gbox->addWidget( mCheckVisible, 2, 1 ); + gbox->setRowStretch( 3, 10 ); +} + + +CFilterDialog::~CFilterDialog( void ) +{ + delete mOperandValidator; +} + + +void CFilterDialog::makeEmptyLayout( void ) +{ + QFrame *page = new QFrame( plainPage() ); + if( page == 0 ) { return; } + mWidgetStack->addWidget( page, EmptyPage ); +} + + +void CFilterDialog::makeOperandLayout( void ) +{ + QString text; + + QFrame *page = new QFrame( plainPage() ); + if( page == 0 ) { return; } + mWidgetStack->addWidget( page, OperandPage ); + + QVBoxLayout *vbox = new QVBoxLayout( page, 0, spacingHint() ); + if( vbox == 0 ) { return; } + + mOperandSelector = new QComboBox( false, page ); + if( mOperandSelector == 0 ) { return; } + mOperandSelector->setFixedHeight( mOperandSelector->sizeHint().height()); + mOperandSelector->setMinimumWidth( fontMetrics().width("M")*20 ); + mOperandSelector->insertStringList( formatStrings() ); + connect( mOperandSelector, SIGNAL(activated(int)), + SLOT(operandSelectorChanged(int)) ); + + text = i18n("Fo&rmat (operand):"); + mOperandFormatLabel = new QLabel( mOperandSelector, text, page ); + if( mOperandFormatLabel == 0 ) { return; } + + vbox->addWidget( mOperandFormatLabel ); + vbox->addWidget( mOperandSelector ); + + mOperandInput = new QLineEdit( page ); + if( mOperandInput == 0 ) { return; } + mOperandInput->setMinimumWidth( fontMetrics().width("M") * 20 ); + mOperandValidator = new CHexValidator( this, CHexValidator::regularText ); + if( mOperandValidator == 0 ) { return; } + mOperandInput->setValidator( mOperandValidator ); + connect( mOperandInput, SIGNAL(textChanged(const QString&)), + SLOT(operandInputChanged(const QString&)) ); + + mOperandInputLabel = new QLabel( mOperandInput, i18n("O&perand:"), page ); + if( mOperandInputLabel == 0 ) { return; } + + vbox->addWidget( mOperandInputLabel ); + vbox->addWidget( mOperandInput ); + vbox->addSpacing( 1 ); +} + + +void CFilterDialog::makeBitSwapLayout( void ) +{ + QString text; + + QFrame *page = new QFrame( plainPage() ); + if( page == 0 ) { return; } + mWidgetStack->addWidget( page, BitSwapPage ); + + QVBoxLayout *vbox = new QVBoxLayout( page, 0, spacingHint() ); + if( vbox == 0 ) { return; } + + text = i18n("Swap rule"); + QLabel *label = new QLabel( text, page ); + if( label == 0 ) { return; } + label->setFixedHeight( label->sizeHint().height() ); + vbox->addWidget( label ); + + mByteWidget = new CByteWidget( page ); + vbox->addWidget( mByteWidget ); + + QHBoxLayout *hbox = new QHBoxLayout( 0 ); + vbox->addLayout( hbox ); + + text = i18n("&Reset"); + QPushButton *resetButton = new QPushButton( text, page ); + resetButton->setFixedHeight( resetButton->sizeHint().height() ); + connect( resetButton, SIGNAL(clicked()), mByteWidget, SLOT(reset()) ); + + hbox->addWidget( resetButton ); + hbox->addStretch( 10 ); +} + + +void CFilterDialog::makeRotateLayout( void ) +{ + QString text; + + QFrame *page = new QFrame( plainPage() ); + if( page == 0 ) { return; } + mWidgetStack->addWidget( page, RotatePage ); + + QVBoxLayout *vbox = new QVBoxLayout( page, 0, spacingHint() ); + if( vbox == 0 ) { return; } + + mGroupSpin = new QSpinBox( page ); + if( mGroupSpin == 0 ) { return; } + mGroupSpin->setMinimumWidth( fontMetrics().width("M")*20 ); + mGroupSpin->setRange(1, INT_MAX ); + + text = i18n("&Group size [bytes]"); + QLabel *label = new QLabel( mGroupSpin, text, page ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mGroupSpin ); + + mBitSpin = new QSpinBox( page ); + if( mBitSpin == 0 ) { return; } + mBitSpin->setMinimumWidth( fontMetrics().width("M")*20 ); + mBitSpin->setRange(INT_MIN, INT_MAX); + + text = i18n("S&hift size [bits]"); + label = new QLabel( mBitSpin, text, page ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mBitSpin ); +} + + + +void CFilterDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + mOperandInput->setFocus(); +} + + + +void CFilterDialog::slotOk( void ) +{ + SFilterControl fc; + switch( mOperationSelector->currentItem() ) + { + case SFilterControl::OperandAndData: + case SFilterControl::OperandOrData: + case SFilterControl::OperandXorData: + if( mOperandData.isEmpty() == true ) + { + showEntryFailure( this, QString("") ); + return; + } + fc.operand = mOperandData; + break; + + case SFilterControl::InvertData: + case SFilterControl::ReverseData: + break; + + case SFilterControl::RotateData: + case SFilterControl::ShiftData: + fc.rotate[0] = mGroupSpin->value(); + fc.rotate[1] = mBitSpin->value(); + if( fc.rotate[1] == 0 ) + { + QString msg = i18n("Shift size is zero."); + showEntryFailure( this, msg ); + return; + } + break; + + case SFilterControl::SwapBits: + if( mByteWidget->flag( fc.operand ) == false ) + { + QString msg = i18n("Swap rule does not define any swapping."); + showEntryFailure( this, msg ); + return; + } + break; + + default: + return; + break; + + } + + if( mCheckVisible->isChecked() == false ) + { + hide(); + } + + fc.operation = (SFilterControl::Operation)mOperationSelector->currentItem(); + fc.fromCursor = mCheckFromCursor->isChecked(); + fc.inSelection = mCheckInSelection->isChecked(); + if( mCheckBackward->isEnabled() == true ) + { + fc.forward = mCheckBackward->isChecked() == true ? false : true; + } + else + { + fc.forward = true; + } + + emit filterData( fc ); +} + + +void CFilterDialog::operandSelectorChanged( int index ) +{ + mOperandValidator->setState( (CHexValidator::EState)index ); + mOperandInput->setText( mOperandString[ index ] ); +} + + +void CFilterDialog::operandInputChanged( const QString &text ) +{ + mOperandString[ mOperandSelector->currentItem() ] = text; + mOperandValidator->convert( mOperandData, + mOperandString[ mOperandSelector->currentItem() ] ); +} + + +void CFilterDialog::operationSelectorChanged( int index ) +{ + if( index <= 2 ) + { + mWidgetStack->raiseWidget( OperandPage ); + mCheckBackward->setEnabled( true ); + } + else if( index <= 4 ) + { + mWidgetStack->raiseWidget( EmptyPage ); + mCheckBackward->setEnabled( true ); + } + else if( index <= 6 ) + { + mWidgetStack->raiseWidget( RotatePage ); + mCheckBackward->setEnabled( false ); + } + else + { + mWidgetStack->raiseWidget( BitSwapPage ); + mCheckBackward->setEnabled( true ); + } +} + + + + +CInsertDialog::CInsertDialog( QWidget *parent, const char *name, bool modal ) + :KDialogBase( Plain, i18n("Insert Pattern"), Ok|Cancel, Ok, + parent, name, modal ) +{ + setButtonOKText(i18n("&Insert")); + + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + QVBoxLayout *vbox = new QVBoxLayout(); + if( vbox == 0 ) { return; } + topLayout->addLayout( vbox ); + + mSizeBox = new QSpinBox( plainPage() ); + if( mSizeBox == 0 ) { return; } + mSizeBox->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mSizeBox->setRange( 1, INT_MAX ); + mSizeBox->setValue( 1 ); + + QLabel *label = new QLabel( mSizeBox, i18n("&Size:"), plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mSizeBox ); + + mPatternSelector = new QComboBox( false, plainPage() ); + if( mPatternSelector == 0 ) { return; } + mPatternSelector->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mPatternSelector->insertStringList( formatStrings() ); + connect( mPatternSelector, SIGNAL(activated(int)), + SLOT(patternSelectorChanged(int)) ); + + text = i18n("Fo&rmat (pattern):"); + label = new QLabel( mPatternSelector, text, plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mPatternSelector ); + + mPatternInput = new QLineEdit( plainPage() ); + if( mPatternInput == 0 ) { return; } + mPatternInput->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mPatternValidator = new CHexValidator( this, CHexValidator::regularText ); + if( mPatternValidator == 0 ) { return; } + mPatternInput->setValidator( mPatternValidator ); + connect( mPatternInput, SIGNAL(textChanged(const QString&)), + SLOT(patternInputChanged(const QString&)) ); + + label = new QLabel( mPatternInput, i18n("&Pattern:"), plainPage() ); + if( label == 0 ) { return; } + + vbox->addWidget( label ); + vbox->addWidget( mPatternInput ); + + mOffsetInput = new QLineEdit( plainPage() ); + mOffsetInput->setMinimumWidth( fontMetrics().maxWidth()*17 ); + + mOffsetLabel = new QLabel( mOffsetInput, i18n("&Offset:"), plainPage() ); + if( mOffsetLabel == 0 ) { return; } + + vbox->addWidget( mOffsetLabel ); + vbox->addWidget( mOffsetInput ); + + QButtonGroup *group = new QButtonGroup( i18n("Options"), plainPage() ); + if( group == 0 ) { return; } + topLayout->addWidget( group, 10 ); + + + QGridLayout *gbox = new QGridLayout( group, 4, 2, spacingHint() ); + if( gbox == 0 ) { return; } + gbox->addRowSpacing( 0, fontMetrics().lineSpacing() ); + + mCheckPattern = new QCheckBox( i18n("R&epeat pattern"), group ); + gbox->addWidget( mCheckPattern, 1, 0 ); + mCheckOnCursor = new QCheckBox( i18n("&Insert on cursor position"), group ); + gbox->addWidget( mCheckOnCursor, 2, 0 ); + connect( mCheckOnCursor, SIGNAL(clicked()), SLOT(cursorCheck()) ); + gbox->setRowStretch( 3, 10 ); + + KConfig &config = *kapp->config(); + config.setGroup("Insert Pattern Dialog"); + mCheckPattern->setChecked( config.readBoolEntry( "RepeatPattern", false ) ); + mCheckOnCursor->setChecked( config.readBoolEntry( "InsertOnCursor", false) ); + cursorCheck(); + uint val = config.readUnsignedNumEntry( "Format", 0 ); + mPatternSelector->setCurrentItem( QMIN(4,val) ); + patternSelectorChanged( mPatternSelector->currentItem() ); +} + + +CInsertDialog::~CInsertDialog( void ) +{ + KConfig &config = *kapp->config(); + config.setGroup("Insert Pattern Dialog"); + config.writeEntry( "RepeatPattern", mCheckPattern->isChecked() ); + config.writeEntry( "InsertOnCursor", mCheckOnCursor->isChecked() ); + config.writeEntry( "Format", mPatternSelector->currentItem() ); + config.sync(); +} + + +void CInsertDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + mPatternInput->setFocus(); +} + + +void CInsertDialog::patternSelectorChanged( int index ) +{ + mPatternValidator->setState( (CHexValidator::EState)index ); + mPatternInput->setText( mPatternString[ index ] ); +} + + +void CInsertDialog::patternInputChanged( const QString &text ) +{ + mPatternString[ mPatternSelector->currentItem() ] = text; + mPatternValidator->convert( mPatternData, + mPatternString[ mPatternSelector->currentItem() ] ); +} + + +void CInsertDialog::slotOk( void ) +{ + if( mPatternData.isEmpty() == true ) + { + showEntryFailure( this, QString("") ); + return; + } + + SInsertData id; + id.size = mSizeBox->value(); + id.repeatPattern = mCheckPattern->isChecked(); + id.onCursor = mCheckOnCursor->isChecked(); + id.pattern = mPatternData; + + if( id.onCursor == false ) + { + bool success = stringToOffset( mOffsetInput->text(), id.offset ); + if( success == false ) + { + showEntryFailure( this, QString("") ); + return; + } + } + + hide(); + execute( id ); +} + + +void CInsertDialog::cursorCheck( void ) +{ + bool state = mCheckOnCursor->isChecked() == true ? false : true; + mOffsetLabel->setEnabled( state ); + mOffsetInput->setEnabled( state ); +} + + + + +void centerDialog( QWidget *widget, QWidget *centerParent ) +{ + if( centerParent == 0 || widget == 0 ) + { + return; + } + + QPoint point = centerParent->mapToGlobal( QPoint(0,0) ); + QRect pos = centerParent->geometry(); + + widget->setGeometry( point.x() + pos.width()/2 - widget->width()/2, + point.y() + pos.height()/2 - widget->height()/2, + widget->width(), widget->height() ); +} + + +void centerDialogBottom( QWidget *widget, QWidget *centerParent ) +{ + if( centerParent == 0 || widget == 0 ) + { + return; + } + + QPoint point = centerParent->mapToGlobal( QPoint(0,0) ); + QRect pos = centerParent->geometry(); + + widget->setGeometry( point.x() + pos.width()/2 - widget->width()/2, + point.y() + pos.height() - widget->height(), + widget->width(), widget->height() ); +} + + +void comboMatchText( QComboBox *combo, const QString &text ) +{ + for( int i=0; i < combo->count(); i++ ) + { + if( combo->text(i) == text ) + { + combo->setCurrentItem(i); + return; + } + } + combo->setCurrentItem(0); +} + + + + + +void showEntryFailure( QWidget *parent, const QString &msg ) +{ + QString message; + message += i18n("Your request can not be processed."); + message += "\n"; + if( msg.isNull() == true || msg.isEmpty() == true ) + { + message += i18n("Examine argument(s) and try again."); + } + else + { + message += msg; + } + KMessageBox::sorry( parent, message, i18n("Invalid argument(s)") ); +} + + +bool verifyFileDestnation( QWidget *parent, const QString &title, + const QString &path ) +{ + if( path.isEmpty() == true ) + { + QString msg = i18n("You must specify a destination file."); + KMessageBox::sorry( parent, msg, title ); + return( false ); + } + + QFileInfo info( path ); + if( info.exists() == true ) + { + if( info.isDir() == true ) + { + QString msg = i18n("You have specified an existing folder."); + KMessageBox::sorry( parent, msg, title ); + return( false ); + } + + if( info.isWritable() == false ) + { + QString msg = i18n("You do not have write permission to this file."); + KMessageBox::sorry( parent, msg, title ); + return( false ); + } + + QString msg = i18n( "" + "You have specified an existing file.\n" + "Overwrite current file?" ); + int reply = KMessageBox::warningContinueCancel( parent, msg, title, i18n("Overwrite") ); + if( reply != KMessageBox::Continue ) + { + return( false ); + } + } + + return( true ); +} + + + +bool stringToOffset( const QString & text, uint &offset ) +{ + if( text.isEmpty() ) + { + return( false ); + } + + const char * p = text.ascii(); // ####: Is this correct? + + // + // Skip any whitespaces in front of string + // + for( ; *p != 0 && isspace( *p ) ; p++ ); + + int match = 0; + bool space = false; + if( strncmp( p, "0x", 2 ) == 0 || strncmp( p, "0X", 2 ) == 0 ) + { + for( const char *q = p+2; *q != 0; q++ ) + { + if( isxdigit( *q ) == 0 || space == true ) + { + if( isspace( *q ) == 0 ) + { + return( false ); + } + space = true; + } + } + match = sscanf( p+2, "%x", &offset ); + } + else + { + for( const char *q = p; *q != 0; q++ ) + { + if( isdigit( *q ) == 0 || space == true ) + { + if( isspace( *q ) == 0 ) + { + return( false ); + } + space = true; + } + } + match = sscanf( p, "%u", &offset ); + } + + if( match == 0 ) + { + return( false ); + } + + return( true ); +} + + +static const QStringList &formatStrings( void ) +{ + static QStringList list; + if( list.isEmpty() == true ) + { + list.append( i18n( "Hexadecimal" ) ); + list.append( i18n( "Decimal" ) ); + list.append( i18n( "Octal" ) ); + list.append( i18n( "Binary" ) ); + list.append( i18n( "Regular Text" ) ); + } + return( list ); +} + + +static const QStringList &operationStrings( void ) +{ + static QStringList list; + if( list.isEmpty() == true ) + { + list.append( i18n( "operand AND data" ) ); + list.append( i18n( "operand OR data" ) ); + list.append( i18n( "operand XOR data" ) ); + list.append( i18n( "INVERT data" ) ); + list.append( i18n( "REVERSE data" ) ); + list.append( i18n( "ROTATE data" ) ); + list.append( i18n( "SHIFT data" ) ); + list.append( i18n( "Swap Individual Bits" ) ); + } + + return( list ); +} + + + + + +#include "dialog.moc" diff --git a/khexedit/dialog.h b/khexedit/dialog.h new file mode 100644 index 0000000..6a6aae1 --- /dev/null +++ b/khexedit/dialog.h @@ -0,0 +1,350 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _DIALOG_H_ +#define _DIALOG_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qdialog.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qradiobutton.h> +#include <qspinbox.h> +#include <qstring.h> +#include <qwidgetstack.h> + +#include <kdialogbase.h> + +#include "bitswapwidget.h" +#include "hexbuffer.h" +#include "hexvalidator.h" + +const int repYes = QDialog::Accepted; +const int repNo = 11; +const int repAll = 12; +const int repClose = QDialog::Rejected; +const int repNext = 13; +const int repPrevious = 14; +const int repNewKey = 15; + +const uint Replace_All = 1; +const uint Replace_AllInit = 2; +const uint Replace_First = 3; +const uint Replace_Next = 4; +const uint Replace_Ignore = 5; +const uint Find_First = 6; +const uint Find_Next = 7; + + + + +class CGotoDialog : public KDialogBase +{ + Q_OBJECT + + public: + CGotoDialog( QWidget *parent, const char *name = 0, bool modal = false ); + ~CGotoDialog( void ); + + protected: + virtual void showEvent( QShowEvent *e ); + + private slots: + void slotOk( void ); + + signals: + void gotoOffset( uint offset, uint bit, bool fromCursor, bool forward ); + + private: + QComboBox *mComboBox; + QCheckBox *mCheckBackward; + QCheckBox *mCheckFromCursor; + QCheckBox *mCheckVisible; +}; + + + +class CFindDialog : public KDialogBase +{ + Q_OBJECT + + public: + enum EOperation + { + find_Again = 0, + find_Next, + find_Previous + }; + + public: + CFindDialog( QWidget *parent=0, const char *name=0, bool modal=false ); + ~CFindDialog( void ); + bool isEmpty( void ); + + public slots: + void findAgain( EOperation operation ); + + protected: + virtual void showEvent( QShowEvent *e ); + + private slots: + void slotOk( void ); + void selectorChanged( int index ); + void inputChanged( const QString &text ); + + signals: + void findData( SSearchControl &sc, uint mode, bool navigator ); + + private: + QComboBox *mSelector; + QLineEdit *mInput; + QCheckBox *mCheckBackward; + QCheckBox *mCheckFromCursor; + QCheckBox *mCheckInSelection; + QCheckBox *mCheckUseNavigator; + QCheckBox *mCheckIgnoreCase; + + QString mFindString[5]; + QByteArray mFindData; + CHexValidator *mFindValidator; +}; + + + +class CFindNavigatorDialog : public KDialogBase +{ + Q_OBJECT + + public: + CFindNavigatorDialog( QWidget *parent=0, const char *name=0, + bool modal=false ); + ~CFindNavigatorDialog( void ); + void defineData( SSearchControl &sc ); + + private slots: + void slotUser1( void ); + void slotUser2( void ); + void slotUser3( void ); + void slotClose( void ); + + private: + void done( int returnCode ); + + signals: + void findData( SSearchControl &sc, uint mode, bool navigator ); + void makeKey( void ); + + private: + QLineEdit *mKey; + SSearchControl mSearchControl; +}; + + +class CReplaceDialog : public KDialogBase +{ + Q_OBJECT + + public: + CReplaceDialog( QWidget *parent=0, const char *name=0, bool modal=false ); + ~CReplaceDialog( void ); + + protected: + virtual void showEvent( QShowEvent *e ); + + private slots: + void slotOk( void ); + void findSelectorChanged( int index ); + void findInputChanged( const QString &text ); + void replaceSelectorChanged( int index ); + void replaceInputChanged( const QString &text ); + + signals: + void replaceData( SSearchControl &sc, uint mode ); + + private: + QComboBox *mFindSelector; + QComboBox *mReplaceSelector; + QLineEdit *mFindInput; + QLineEdit *mReplaceInput; + + QCheckBox *mCheckBackward; + QCheckBox *mCheckFromCursor; + QCheckBox *mCheckInSelection; + QCheckBox *mCheckPrompt; + QCheckBox *mCheckIgnoreCase; + + QString mFindString[5]; + QString mReplaceString[5]; + QByteArray mFindData; + QByteArray mReplaceData; + CHexValidator *mFindValidator; + CHexValidator *mReplaceValidator; +}; + + + +class CReplacePromptDialog : public KDialogBase +{ + Q_OBJECT + + public: + CReplacePromptDialog( QWidget *parent=0, const char *name=0, + bool modal=false ); + ~CReplacePromptDialog( void ); + void defineData( SSearchControl &sc ); + + private slots: + void slotUser1( void ); + void slotUser2( void ); + void slotUser3( void ); + void slotClose( void ); + + private: + void done( int returnCode ); + + signals: + void replaceData( SSearchControl &sc, uint mode ); + + private: + SSearchControl mSearchControl; +}; + + + + +class CFilterDialog : public KDialogBase +{ + Q_OBJECT + + public: + enum EStackMode + { + EmptyPage = 0, + OperandPage, + BitSwapPage, + RotatePage + }; + + public: + CFilterDialog( QWidget *parent=0, const char *name=0, bool modal=false ); + ~CFilterDialog( void ); + + protected: + virtual void showEvent( QShowEvent *e ); + + private: + void makeEmptyLayout( void ); + void makeOperandLayout( void ); + void makeBitSwapLayout( void ); + void makeRotateLayout( void ); + + private slots: + void slotOk( void ); + void operandSelectorChanged( int index ); + void operandInputChanged( const QString &text ); + void operationSelectorChanged( int index ); + + signals: + void filterData( SFilterControl &fc ); + + private: + QWidgetStack *mWidgetStack; + QLabel *mOperandFormatLabel; + QLabel *mOperandInputLabel; + QComboBox *mOperandSelector; + QLineEdit *mOperandInput; + QComboBox *mOperationSelector; + QSpinBox *mGroupSpin; + QSpinBox *mBitSpin; + CByteWidget *mByteWidget; + + QCheckBox *mCheckBackward; + QCheckBox *mCheckFromCursor; + QCheckBox *mCheckInSelection; + QCheckBox *mCheckVisible; + + QString mOperandString[5]; + QByteArray mOperandData; + CHexValidator *mOperandValidator; +}; + + + + +class CInsertDialog : public KDialogBase +{ + Q_OBJECT + + public: + CInsertDialog( QWidget *parent=0, const char *name=0, bool modal=false ); + ~CInsertDialog( void ); + + protected: + virtual void showEvent( QShowEvent *e ); + + private slots: + void slotOk( void ); + void cursorCheck( void ); + void patternSelectorChanged( int index ); + void patternInputChanged( const QString &text ); + + signals: + void execute( SInsertData &id ); + + private: + QSpinBox *mSizeBox; + QLabel *mOffsetLabel; + QComboBox *mPatternSelector; + QLineEdit *mPatternInput; + QLineEdit *mOffsetInput; + QCheckBox *mCheckPattern; + QCheckBox *mCheckOnCursor; + + QString mPatternString[5]; + QByteArray mPatternData; + CHexValidator *mPatternValidator; +}; + + + + +void centerDialog( QWidget *widget, QWidget *centerParent ); +void centerDialogBottom( QWidget *widget, QWidget *centerParent ); +void comboMatchText( QComboBox *combo, const QString &text ); +bool stringToOffset( const QString & text, uint &offset ); + +void showEntryFailure( QWidget *parent, const QString &msg ); +bool verifyFileDestnation( QWidget *parent, const QString &title, + const QString &path ); + + + +#endif + + + + + diff --git a/khexedit/draglabel.cc b/khexedit/draglabel.cc new file mode 100644 index 0000000..e20088c --- /dev/null +++ b/khexedit/draglabel.cc @@ -0,0 +1,149 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <stdlib.h> + +#include <qbitmap.h> +#include <qpainter.h> + +#include <kurldrag.h> + +#include "draglabel.h" + + +CDragLabel::CDragLabel( QWidget *parent ) + : QLabel( "draglabel", parent, "kde toolbar widget" ) +{ + mValid = true; + mDragPending = false; + setBackgroundMode( Qt::PaletteButton ); +} + + +CDragLabel::~CDragLabel( void ) +{ +} + + +void CDragLabel::mousePressEvent( QMouseEvent *e ) +{ + if( mValid == false || e->button() != LeftButton || mUrl.isEmpty() == true ) + { + return; + } + + mDragOrigin = e->pos(); + mDragPending = true; +} + + +void CDragLabel::mouseMoveEvent( QMouseEvent *e ) +{ + if( mDragPending == true ) + { + if( abs(e->x() - mDragOrigin.x()) + abs(e->y() - mDragOrigin.y()) > 5 ) + { + mDragPending = false; + + // + // Make drag object, assign pixmap and grab keyboard. The grabbing + // will allow ESC to abort the drag + // + KURL::List uris; + uris.append(KURL(mUrl)); + KURLDrag *uriDrag = new KURLDrag( uris, this ); + if( uriDrag == 0 ) { return; } + prepPixmap( *uriDrag ); + grabKeyboard(); + uriDrag->drag(); + releaseKeyboard(); + } + } +} + +void CDragLabel::mouseReleaseEvent( QMouseEvent * ) +{ + mDragPending = false; +} + + +void CDragLabel::setUrl( const QString &url ) +{ + mUrl = url; +} + + +void CDragLabel::setDragMask( const QPixmap pix ) +{ + mDragMask = pix; +} + + +void CDragLabel::prepPixmap( KURLDrag &uriDrag ) +{ + if( pixmap() == 0 ) + { + return; + } + + QString text; + int index = mUrl.findRev( '/', mUrl.length() ); + if( index < 0 ) + { + text = mUrl; + } + else + { + text = mUrl.right( mUrl.length() - index - 1 ); + } + + int sep = 2; + QRect rect = fontMetrics().boundingRect(text); + int w = pixmap()->width() + rect.width() + sep + 2; + int h = fontMetrics().lineSpacing(); + if( pixmap()->height() > h ) { h = pixmap()->height(); } + + QBitmap mask( w, h, TRUE ); + QPixmap dragPixmap( w, h ); + dragPixmap.fill( black ); + + QPainter p; + p.begin( &mask ); + p.setPen( white ); + p.drawPixmap( 0, 0, mDragMask ); + p.drawText( pixmap()->width()+sep, 0, w-pixmap()->width()+sep, + h, AlignVCenter|AlignLeft, text ); + p.end(); + + p.begin( &dragPixmap ); + p.drawPixmap( 0, 0, *pixmap() ); + p.end(); + + dragPixmap.setMask( mask ); + + QPoint hotspot( pixmap()->width(), pixmap()->height()/2 ); + uriDrag.setPixmap( dragPixmap, hotspot ); +} + + + + + +#include "draglabel.moc" diff --git a/khexedit/draglabel.h b/khexedit/draglabel.h new file mode 100644 index 0000000..d90b5ed --- /dev/null +++ b/khexedit/draglabel.h @@ -0,0 +1,60 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * 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 _DRAG_SOURCE_H_ +#define _DRAG_SOURCE_H_ + +#include <qdropsite.h> +#include <qlabel.h> +#include <qbitmap.h> +#include <qstring.h> +#include <qstrlist.h> + +class KURLDrag; + +class CDragLabel: public QLabel +{ + Q_OBJECT + + public: + CDragLabel( QWidget *parent ); + ~CDragLabel( void ); + + void setUrl( const QString &url ); + void setDragMask( const QPixmap pix ); + + protected: + void mousePressEvent( QMouseEvent * ); + void mouseMoveEvent( QMouseEvent * ); + void mouseReleaseEvent( QMouseEvent * ); + + private: + void prepPixmap( KURLDrag &uriDrag ); + + private: + bool mValid; + QString mUrl; + QBitmap mDragMask; + bool mDragPending; + QPoint mDragOrigin; + +}; + +#endif diff --git a/khexedit/exportdialog.cc b/khexedit/exportdialog.cc new file mode 100644 index 0000000..a178319 --- /dev/null +++ b/khexedit/exportdialog.cc @@ -0,0 +1,696 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <limits.h> +#include <qbuttongroup.h> +#include <qlineedit.h> + +#include <kfiledialog.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include "dialog.h" +#include "exportdialog.h" +#include <qpushbutton.h> + + +CExportDialog::CExportDialog( QWidget *parent, char *name, bool modal ) + :KDialogBase( Tabbed, i18n("Export Document"), Help|Ok|Cancel, Ok, + parent, name, modal ) +{ + setHelp( "khexedit/khexedit.html", QString::null ); + + mFrame[ page_destination ] = addPage( i18n("Destination") ); + mFrame[ page_option ] = addPage( i18n("Options") ); + + setupDestinationPage(); + setupOptionPage(); + + mConfig = 0; + readConfiguration(); + + QString path = mDestination.fileInput->text(); + int index = path.findRev( '/' ); + if( index != -1 ) { mWorkDir = path.left( index+1 ); } +} + + +CExportDialog::~CExportDialog( void ) +{ + writeConfiguration(); + delete mConfig; mConfig = 0; +} + + +void CExportDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + showPage(0); + mDestination.fileInput->setFocus(); +} + + +void CExportDialog::readConfiguration( void ) +{ + if( mConfig != 0 ) { return; } + + mConfig = new KSimpleConfig( QString("hexexport") ); + if( mConfig == 0 ) { return; } + + mConfig->setGroup( "Destination" ); + + int val = mConfig->readNumEntry( "Format", 0 ); + mDestination.formatCombo->setCurrentItem( val ); + formatChanged( val < 0 || val > option_html ? 0 : val ); + + mConfig->setGroup( "Option" ); + val = mConfig->readNumEntry( "HtmlLine", 80 ); + mHtml.lineSpin->setValue( val ); + QString text = mConfig->readEntry( "HtmlPrefix", "table" ); + mHtml.prefixInput->setText( text ); + val = mConfig->readNumEntry( "HtmlHeader", 1 ); + mHtml.topCombo->setCurrentItem( val < 0 || val >= 4 ? 0 : val ); + val = mConfig->readNumEntry( "HtmlFooter", 3 ); + mHtml.bottomCombo->setCurrentItem( val < 0 || val >= 4 ? 0 : val ); + + bool state = mConfig->readBoolEntry( "HtmlSymlink", true ); + mHtml.symlinkCheck->setChecked( state ); + state = mConfig->readBoolEntry( "HtmlNavigatorBar", true ); + mHtml.navigatorCheck->setChecked( state ); + state = mConfig->readBoolEntry( "HtmlBlackWhite", false ); + mHtml.bwCheck->setChecked( state ); + + text = mConfig->readEntry( "ArrayName", "buffer" ); + mArray.nameInput->setText( text ); + text = mConfig->readEntry( "ArrayElementType", "char" ); + for( int i=0; i < mArray.typeCombo->count(); i++ ) + { + if( mArray.typeCombo->text(i) == text ) + { + mArray.typeCombo->setCurrentItem(i); + break; + } + } + val = mConfig->readNumEntry( "ArrayElementPerLine", 20 ); + val = QMAX( val, mArray.lineSizeSpin->minValue() ); + val = QMIN( val, mArray.lineSizeSpin->maxValue() ); + mArray.lineSizeSpin->setValue( val ); + state = mConfig->readBoolEntry( "ArrayUnsignedAsHex", true ); + mArray.hexadecimalCheck->setChecked( state ); +} + + +void CExportDialog::writeConfiguration( void ) +{ + if( mConfig == 0 ) + { + return; + } + + mConfig->setGroup( "Destination" ); + mConfig->writeEntry( "Format", mDestination.formatCombo->currentItem() ); + + mConfig->setGroup( "Option" ); + mConfig->writeEntry( "HtmlLine", mHtml.lineSpin->value() ); + mConfig->writeEntry( "HtmlPrefix", mHtml.prefixInput->text() ); + mConfig->writeEntry( "HtmlHeader", mHtml.topCombo->currentItem() ); + mConfig->writeEntry( "HtmlFooter", mHtml.bottomCombo->currentItem() ); + mConfig->writeEntry( "HtmlSymlink", mHtml.symlinkCheck->isChecked()); + mConfig->writeEntry( "HtmlNavigatorBar",mHtml.navigatorCheck->isChecked()); + mConfig->writeEntry( "HtmlBlackWhite", mHtml.bwCheck->isChecked() ); + + + mConfig->writeEntry( "ArrayName", mArray.nameInput->text() ); + mConfig->writeEntry( "ArrayElementType", mArray.typeCombo->currentText() ); + mConfig->writeEntry( "ArrayElementPerLine", mArray.lineSizeSpin->value() ); + mConfig->writeEntry( "ArrayUnsignedAsHex", + mArray.hexadecimalCheck->isChecked() ); + mConfig->sync(); +} + + +void CExportDialog::setupDestinationPage( void ) +{ + QString text; + QFrame *page = mFrame[ page_destination ]; + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + QStringList formatList; + formatList.append( i18n("Plain Text") ); + formatList.append( i18n("HTML Tables") ); + formatList.append( i18n("Rich Text (RTF)") ); + formatList.append( i18n("C Array") ); + + mDestination.formatCombo = new QComboBox( false, page ); + mDestination.formatCombo->insertStringList( formatList ); + mDestination.formatCombo->setMinimumWidth( fontMetrics().maxWidth()*10 ); + connect( mDestination.formatCombo, SIGNAL(activated(int)), + SLOT(formatChanged(int)) ); + + text = i18n("&Format:"); + QLabel *label = new QLabel( mDestination.formatCombo, text, page ); + topLayout->addWidget( label ); + topLayout->addWidget( mDestination.formatCombo ); + + QHBoxLayout *hbox = new QHBoxLayout(); + topLayout->addLayout( hbox ); + + text = i18n("&Destination:"); + label = new QLabel( text, page ); + hbox->addWidget( label ); + + text = i18n("(Package folder)"); + mDestination.fileExtraLabel = new QLabel( text, page ); + hbox->addWidget( mDestination.fileExtraLabel, 10, AlignLeft|AlignVCenter ); + + hbox = new QHBoxLayout(); + topLayout->addLayout( hbox ); + + mDestination.fileInput = new QLineEdit( page ); + hbox->addWidget( mDestination.fileInput ); + connect(mDestination.fileInput, SIGNAL(textChanged ( const QString & )),this,SLOT(destinationChanged(const QString &))); + text = i18n("Choose..."); + QPushButton *browseButton = new QPushButton( text, page, "browse" ); + hbox->addWidget( browseButton ); + connect( browseButton, SIGNAL(clicked()), SLOT(browserClicked()) ); + mDestination.fileInput->setMinimumWidth( fontMetrics().maxWidth()*15 ); + + label->setBuddy(mDestination.fileInput); + + hbox = new QHBoxLayout(); + topLayout->addLayout( hbox, 10 ); + + mDestination.rangeBox = new QButtonGroup( i18n("Export Range"), page ); + hbox->addWidget( mDestination.rangeBox ); + + QButtonGroup *group = mDestination.rangeBox; // convenience + + QVBoxLayout *vbox = new QVBoxLayout( group, spacingHint() ); + vbox->addSpacing( fontMetrics().lineSpacing() ); + + QRadioButton *radio1 = new QRadioButton( i18n("&Everything"), group ); + radio1->setFixedSize( radio1->sizeHint() ); + mDestination.rangeBox->insert( radio1, 0 ); + vbox->addWidget( radio1, 0, AlignLeft ); + + QRadioButton *radio2 = new QRadioButton( i18n("&Selection"), group ); + radio2->setFixedSize( radio2->sizeHint() ); + mDestination.rangeBox->insert( radio2, 1 ); + vbox->addWidget( radio2, 0, AlignLeft ); + + QRadioButton *radio3 = new QRadioButton( i18n("&Range"), group ); + radio3->setFixedSize( radio3->sizeHint() ); + mDestination.rangeBox->insert( radio3, 2 ); + vbox->addWidget( radio3, 0, AlignLeft ); + + QGridLayout *gbox = new QGridLayout( 2, 2, spacingHint() ); + vbox->addLayout( gbox ); + + mDestination.fromInput = new QLineEdit( group ); + text = i18n("&From offset:"); + mDestination.fromLabel = new QLabel( mDestination.fromInput, text, group ); + gbox->addWidget( mDestination.fromLabel, 0, 0 ); + gbox->addWidget( mDestination.fromInput, 0, 1 ); + + mDestination.toInput = new QLineEdit( group ); + text = i18n("&To offset:"); + mDestination.toLabel = new QLabel( mDestination.toInput, text, group ); + gbox->addWidget( mDestination.toLabel, 1, 0 ); + gbox->addWidget( mDestination.toInput, 1, 1 ); + + connect( group, SIGNAL(clicked(int)), SLOT(rangeChanged(int)) ); + group->setButton(0); + rangeChanged(0); + enableButtonOK( !mDestination.fileInput->text().isEmpty() ); +} + +void CExportDialog::destinationChanged(const QString &_text) +{ + enableButtonOK( !_text.isEmpty() ); +} + +void CExportDialog::setupOptionPage( void ) +{ + QFrame *page = mFrame[ page_option ]; + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + mOptionStack = new QWidgetStack( page, "stack" ); + if( mOptionStack == 0 ) { return; } + topLayout->addWidget( mOptionStack ); + + makeTextOption(); + makeHtmlOption(); + makeRtfOption(); + makeCArrayOption(); + mOptionStack->raiseWidget( (int)option_text ); + + QSize size = mOptionStack->sizeHint(); + size += QSize(spacingHint()*2, spacingHint()*2); + page->setMinimumSize( size ); +} + + +void CExportDialog::makeTextOption( void ) +{ + QFrame *page = new QFrame( mFrame[ page_option ] ); + if( page == 0 ) { return; } + mOptionStack->addWidget( page, option_text ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + QString text = i18n("No options for this format."); + QLabel *label = new QLabel( text, page ); + topLayout->addWidget( label, 0, AlignCenter ); +} + + +void CExportDialog::makeHtmlOption( void ) +{ + QFrame *page = new QFrame( mFrame[ page_option ] ); + if( page == 0 ) { return; } + mOptionStack->addWidget( page, option_html ); + + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + text = i18n("HTML Options (one table per page)"); + QLabel *label = new QLabel( text, page ); + topLayout->addWidget( label ); + + QFrame *hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + topLayout->addWidget( hline ); + + QFrame *frame = new QFrame( page ); + if( frame == 0 ) { return; } + topLayout->addWidget( frame ); + + QGridLayout *gbox = new QGridLayout( frame, 4, 2, 0, spacingHint() ); + if( gbox == 0 ) { return; } + gbox->setColStretch( 1, 10 ); + + mHtml.lineSpin = new QSpinBox( frame ); + mHtml.lineSpin->setMinimumWidth( fontMetrics().maxWidth()*10 ); + mHtml.lineSpin->setRange( 5, INT_MAX ); + gbox->addWidget( mHtml.lineSpin, 0, 1 ); + + text = i18n("&Lines per table:"); + label = new QLabel( mHtml.lineSpin, text, frame ); + gbox->addWidget( label, 0, 0 ); + + mHtml.prefixInput = new QLineEdit( frame, "prefix" ); + mHtml.prefixInput->setMinimumWidth( fontMetrics().maxWidth()*10 ); + gbox->addWidget( mHtml.prefixInput, 1, 1 ); + + text = i18n("Filename &prefix (in package):"); + label = new QLabel( mHtml.prefixInput, text, frame ); + gbox->addWidget( label, 1, 0 ); + + QStringList headerList; + headerList.append( i18n("None") ); + headerList.append( i18n("Filename with Path") ); + headerList.append( i18n("Filename") ); + headerList.append( i18n("Page Number") ); + + mHtml.topCombo = new QComboBox( false, frame ); + mHtml.topCombo->insertStringList( headerList ); + gbox->addWidget( mHtml.topCombo, 2, 1 ); + + text = i18n("Header &above text:"); + label = new QLabel( mHtml.topCombo, text, frame ); + gbox->addWidget( label, 2, 0 ); + + mHtml.bottomCombo = new QComboBox( false, frame ); + mHtml.bottomCombo->insertStringList( headerList ); + gbox->addWidget( mHtml.bottomCombo, 3, 1 ); + + text = i18n("&Footer below text:"); + label = new QLabel( mHtml.bottomCombo, text, frame ); + gbox->addWidget( label, 3, 0 ); + + text = i18n("Link \"index.html\" to &table of contents file"); + mHtml.symlinkCheck = new QCheckBox( text, page ); + topLayout->addWidget( mHtml.symlinkCheck ); + + text = i18n("&Include navigator bar"); + mHtml.navigatorCheck = new QCheckBox( text, page ); + topLayout->addWidget( mHtml.navigatorCheck ); + + text = i18n("&Use black and white only"); + mHtml.bwCheck = new QCheckBox( text, page ); + topLayout->addWidget( mHtml.bwCheck ); + + topLayout->addStretch(10); +} + + +void CExportDialog::makeRtfOption( void ) +{ + QFrame *page = new QFrame( mFrame[ page_option ] ); + if( page == 0 ) { return; } + mOptionStack->addWidget( page, option_rtf ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + QString text = i18n("No options for this format."); + QLabel *label = new QLabel( text, page ); + topLayout->addWidget( label, 0, AlignCenter ); +} + + +void CExportDialog::makeCArrayOption( void ) +{ + QFrame *page = new QFrame( mFrame[ page_option ] ); + mOptionStack->addWidget( page, option_carray ); + + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + text = i18n("C Array Options"); + QLabel *label = new QLabel( text, page ); + topLayout->addWidget( label, 0, AlignLeft ); + + QFrame *hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + topLayout->addWidget( hline ); + + QGridLayout *gbox = new QGridLayout( 3, 2, spacingHint() ); + topLayout->addLayout( gbox ); + gbox->setColStretch( 1, 10 ); + + mArray.nameInput = new QLineEdit( page ); + gbox->addWidget( mArray.nameInput, 0, 1 ); + text = i18n("Array name:"); + label = new QLabel( mArray.nameInput, text, page ); + gbox->addWidget( label, 0, 0 ); + + QStringList typeList; + typeList.append( i18n("char") ); + typeList.append( i18n("unsigned char") ); + typeList.append( i18n("short") ); + typeList.append( i18n("unsigned short") ); + typeList.append( i18n("int") ); + typeList.append( i18n("unsigned int") ); + typeList.append( i18n("float") ); + typeList.append( i18n("double") ); + mArray.typeCombo = new QComboBox( false, page ); + mArray.typeCombo->insertStringList( typeList ); + mArray.typeCombo->setMinimumWidth( fontMetrics().maxWidth()*10 ); + gbox->addWidget( mArray.typeCombo, 1, 1 ); + text = i18n("Element type:"); + label = new QLabel( mArray.typeCombo, text, page ); + gbox->addWidget( label, 1, 0 ); + + mArray.lineSizeSpin = new QSpinBox( page ); + mArray.lineSizeSpin->setMinimumWidth( fontMetrics().maxWidth()*10 ); + mArray.lineSizeSpin->setRange( 1, INT_MAX ); + gbox->addWidget( mArray.lineSizeSpin, 2, 1 ); + text = i18n("Elements per line:"); + label = new QLabel( mArray.lineSizeSpin, text, page ); + gbox->addWidget( label, 2, 0 ); + + text = i18n("Print unsigned values as hexadecimal"); + mArray.hexadecimalCheck = new QCheckBox( text, page ); + topLayout->addWidget( mArray.hexadecimalCheck ); + + topLayout->addStretch(10); +} + + + + + +void CExportDialog::formatChanged( int index ) +{ + mDestination.formatCombo->setCurrentItem(index); + mDestination.fileExtraLabel->setEnabled( index == option_html ); + mOptionStack->raiseWidget( index ); +} + + +void CExportDialog::rangeChanged( int id ) +{ + bool state = id == 2 ? true : false; + mDestination.toLabel->setEnabled( state ); + mDestination.fromLabel->setEnabled( state ); + mDestination.toInput->setEnabled( state ); + mDestination.fromInput->setEnabled( state ); +} + + +void CExportDialog::browserClicked( void ) +{ + QString url; + if( mDestination.formatCombo->currentItem() == option_html ) + { + url = KFileDialog::getExistingDirectory( mWorkDir, topLevelWidget() ); + } + else + { + url = KFileDialog::getSaveFileName( mWorkDir, "*", topLevelWidget() ); + } + + if( url.isEmpty() ) + { + return; + } + + int index = url.findRev( '/' ); + if( index != -1 ) + { + mWorkDir = url.left( index+1 ); + } + mDestination.fileInput->setText( url ); +} + + +void CExportDialog::slotOk( void ) +{ + QString path( mDestination.fileInput->text() ); + + int format = mDestination.formatCombo->currentItem(); + if( format == option_text ) + { + if( verifyFileDestnation( this, i18n("Export Document"), path ) == false ) + { + return; + } + + SExportText e; + uint mode; + if( collectRange( mode, e.range.start, e.range.stop ) == false ) + { + showEntryFailure( this, QString("") ); + return; + } + e.range.mode = (SExportRange::EMode)mode; // FIXME + e.destFile = path; + + hide(); + emit exportText(e); + } + else if( format == option_html ) + { + SExportHtml e; + uint mode; + if( collectRange( mode, e.range.start, e.range.stop ) == false ) + { + showEntryFailure( this, QString("") ); + return; + } + e.range.mode = (SExportRange::EMode)mode; // FIXME + + const QString str = mHtml.prefixInput->text().stripWhiteSpace(); + mHtml.prefixInput->setText( str ); + if( mHtml.prefixInput->text().isEmpty() == true ) + { + mHtml.prefixInput->setText( "table" ); + } + + const QString prefix = mHtml.prefixInput->text(); + for( uint i=0; i<prefix.length(); i++ ) + { + QChar c = prefix[i]; + if( c.isSpace() == true || c.isPunct() == true ) + { + QString msg = i18n("The filename prefix can not contain empty letters " + "or punctuation marks."); + KMessageBox::sorry( this, msg, i18n("Export Document") ); + return; + } + } + + if( verifyPackage( path ) == false ) + { + return; + } + + e.package = path; + e.prefix = prefix; + e.linePerPage = mHtml.lineSpin->value(); + e.topCaption = mHtml.topCombo->currentItem(); + e.bottomCaption = mHtml.bottomCombo->currentItem(); + e.symLink = mHtml.symlinkCheck->isChecked(); + e.navigator = mHtml.navigatorCheck->isChecked(); + e.blackWhite = mHtml.bwCheck->isChecked(); + + hide(); + emit exportHtml(e); + } + else if( format == option_rtf ) + { + QString msg = i18n("This format is not yet supported."); + KMessageBox::sorry( this, msg ); + } + else if( format == option_carray ) + { + if( verifyFileDestnation( this, i18n("Export Document"), path ) == false ) + { + return; + } + + SExportCArray e; + uint mode; + if( collectRange( mode, e.range.start, e.range.stop ) == false ) + { + showEntryFailure( this, QString("") ); + return; + } + e.range.mode = (SExportRange::EMode)mode; // FIXME + e.destFile = path; + e.arrayName = mArray.nameInput->text(); + e.elementType = mArray.typeCombo->currentItem(); + e.elementPerLine = mArray.lineSizeSpin->value(); + e.unsignedAsHexadecimal = mArray.hexadecimalCheck->isChecked(); + + emit exportCArray( e ); + } +} + + + + +bool CExportDialog::collectRange( uint &mode, uint &start, uint &stop ) +{ + QButton *b = mDestination.rangeBox->selected(); + if( b == 0 ) + { + return( false ); + } + + int id = mDestination.rangeBox->id( b ); + if( id == 0 ) + { + mode = SExportRange::All; + } + else if( id == 1 ) + { + mode = SExportRange::Selection; + } + else if( id == 2 ) + { + mode = SExportRange::Range; + bool ok1 = stringToOffset( mDestination.fromInput->text(), start ); + bool ok2 = stringToOffset( mDestination.toInput->text(), stop ); + if( ok1 == false || ok2 == false || start >= stop ) + { + return( false ); + } + } + else + { + return( false ); + } + + return( true ); +} + + +// +// This one will attempt to create a directory if 'path' +// specifies a nonexistent name. +// +bool CExportDialog::verifyPackage( const QString &path ) +{ + const QString title = i18n("Export Document"); + + if( path.isEmpty() == true ) + { + QString msg = i18n("You must specify a destination."); + KMessageBox::sorry( this, msg, title ); + return( false ); + } + + QFileInfo info( path ); + if( info.exists() == false ) + { + QDir directory; + if( directory.mkdir( path ) == false ) + { + QString msg; + msg += i18n("Unable to create a new folder"); + msg += "\n"; + msg += path; + KMessageBox::sorry( this, msg, title ); + return( false ); + } + } + else + { + if( info.isDir() == false ) + { + QString msg = i18n("You have specified an existing file"); + KMessageBox::sorry( this, msg, title ); + return( false ); + } + else + { + if( info.isWritable() == false ) + { + QString msg = i18n( "" + "You do not have write permission to this folder."); + KMessageBox::sorry( this, msg, title ); + return( false ); + } + + const QString prefix = mHtml.prefixInput->text(); + QString f1 = QString("%1%2.html").arg(prefix).arg("00000000"); + QString f2 = QString("%1%2.html").arg(prefix).arg("99999999"); + + QString msg = i18n( "" + "You have specified an existing folder.\n" + "If you continue, any existing file in the range " + "\"%1\" to \"%2\" can be lost.\n" + "Continue?").arg(f1).arg(f2); + int reply = KMessageBox::warningContinueCancel( this, msg, title ); + if( reply != KMessageBox::Continue ) + { + return( false ); + } + + } + } + + return( true ); +} + +#include "exportdialog.moc" diff --git a/khexedit/exportdialog.h b/khexedit/exportdialog.h new file mode 100644 index 0000000..6d89ac3 --- /dev/null +++ b/khexedit/exportdialog.h @@ -0,0 +1,138 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _EXPORT_DIALOG_H_ +#define _EXPORT_DIALOG_H_ + + +class QButtonGroup; +class QComboBox; +class QCheckBox; +class QFrame; +class QLabel; +class QLineEdit; +class QSpinBox; +class QWidgetStack; +class KSimpleConfig; + +#include <kdialogbase.h> +#include "hexbuffer.h" + + +class CExportDialog : public KDialogBase +{ + Q_OBJECT + + public: + enum EPage + { + page_destination = 0, + page_option, + page_max + }; + + enum OptionPage + { + option_text = 0, + option_html, + option_rtf, + option_carray, + option_max + }; + + CExportDialog( QWidget *parent = 0, char *name = 0, bool modal = false ); + ~CExportDialog( void ); + void writeConfiguration( void ); + + protected: + void showEvent( QShowEvent *e ); + + protected slots: + virtual void slotOk( void ); + void destinationChanged(const QString &); + private: + struct SDestinationWidgets + { + QComboBox *formatCombo; + QLabel *fileExtraLabel; + QLineEdit *fileInput; + QLabel *fromLabel; + QLabel *toLabel; + QButtonGroup *rangeBox; + QLineEdit *fromInput; + QLineEdit *toInput; + }; + + struct SHtmlWidgets + { + QSpinBox *lineSpin; + QLineEdit *prefixInput; + QComboBox *topCombo; + QComboBox *bottomCombo; + QCheckBox *navigatorCheck; + QCheckBox *symlinkCheck; + QCheckBox *bwCheck; + }; + + struct SArrayWidgets + { + QLineEdit *nameInput; + QComboBox *typeCombo; + QSpinBox *lineSizeSpin; + QCheckBox *hexadecimalCheck; + }; + + private slots: + void rangeChanged( int id ); + void formatChanged( int index ); + void browserClicked( void ); + + private: + void setupDestinationPage( void ); + void setupOptionPage( void ); + void makeTextOption( void ); + void makeHtmlOption( void ); + void makeRtfOption( void ); + void makeCArrayOption( void ); + void readConfiguration( void ); + bool collectRange( uint &mode, uint &start, uint &stop ); + bool verifyPackage( const QString &path ); + + signals: + void exportText( const SExportText &e ); + void exportHtml( const SExportHtml &e ); + void exportCArray( const SExportCArray &e ); + + private: + QFrame *mFrame[ page_max ]; + QWidgetStack *mOptionStack; + SDestinationWidgets mDestination; + SHtmlWidgets mHtml; + SArrayWidgets mArray; + KSimpleConfig *mConfig; + + QString mWorkDir; +}; + + + + + +#endif diff --git a/khexedit/fileinfodialog.cc b/khexedit/fileinfodialog.cc new file mode 100644 index 0000000..b9dff60 --- /dev/null +++ b/khexedit/fileinfodialog.cc @@ -0,0 +1,330 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <qheader.h> +#include <qlabel.h> +#include <qlayout.h> + +#include <kglobalsettings.h> +#include <kglobal.h> +#include <klocale.h> + +#include "fileinfodialog.h" +#include "listview.h" + +// quick'n'dirty hack to have the occurrence column sorted correctly +class CStatisticListViewItem : public QListViewItem +{ + public: + CStatisticListViewItem( QListView * parent, QListViewItem * after, + QString label1, QString label2, QString label3, QString label4, + QString label5, QString label6, QString label7, int i, int o) + : QListViewItem( parent, after, label1, label2, label3, label4, label5, label6, label7), + item( i ), + occurrence( o ) + {} + + virtual int compare( QListViewItem *i, int col, bool ascending/*Qt doc says: ignore this one*/ ) const + { + // occurrence column (or the percent one)? + if( col == 5 || col == 6 ) + { + const int otherOccurrence = ((CStatisticListViewItem*)i)->occurrence; + return occurrence < otherOccurrence ? -1 : occurrence == otherOccurrence ? 0 : 1; + } + // char column? + else if( col == 4 ) + { + const int otherItem = ((CStatisticListViewItem*)i)->item; + return item < otherItem ? -1 : item == otherItem ? 0 : 1; + } + // default + else + return QListViewItem::compare(i,col,ascending); + } + + protected: + // no of byte + int item; + // number of the byte's occurrence + int occurrence; +}; + + + +CFileInfoDialog::CFileInfoDialog( QWidget *parent,const char *name,bool modal) + :KDialogBase( Plain, i18n("Statistics"), Help|User1|Cancel, User1, + parent, name, modal, true, i18n("&Update") ), + mBusy(false), mDirty(false) +{ + setHelp( "khexedit/khexedit.html", QString::null ); + + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + if( topLayout == 0 ) { return; } + + + QGridLayout *gbox = new QGridLayout( 2, 2, spacingHint() ); + if( gbox == 0 ) { return; } + topLayout->addLayout( gbox ); + gbox->setColStretch( 1, 10 ); + + text = i18n("File name: "); + QLabel *label = new QLabel( text, plainPage() ); + gbox->addWidget( label, 0, 0 ); + + text = i18n("Size [bytes]: "); + label = new QLabel( text, plainPage() ); + gbox->addWidget( label, 1, 0 ); + + mFileNameLabel = new QLabel( plainPage() ); + mFileSizeLabel = new QLabel( plainPage() ); + gbox->addWidget( mFileNameLabel, 0, 1 ); + gbox->addWidget( mFileSizeLabel, 1, 1 ); + + mFrequencyList = new CListView( plainPage(), "stringList" ); + mFrequencyList->setFont( KGlobalSettings::fixedFont() ); + + mFrequencyList->addColumn( i18n("Hexadecimal") ); + mFrequencyList->addColumn( i18n("Decimal") ); + mFrequencyList->addColumn( i18n("Octal") ); + mFrequencyList->addColumn( i18n("Binary") ); + mFrequencyList->addColumn( i18n("Text") ); + mFrequencyList->addColumn( i18n("Occurrence") ); + mFrequencyList->addColumn( i18n("Percent") ); + mFrequencyList->setAllColumnsShowFocus( true ); + mFrequencyList->setFrameStyle( QFrame::WinPanel + QFrame::Sunken ); + topLayout->addWidget( mFrequencyList, 10 ); + + mDirtyLabel = new QLabel( plainPage() ); + mDirtyLabel->setFixedHeight( fontMetrics().height() ); + topLayout->addWidget( mDirtyLabel ); + + setStatistics(); + setColumnWidth(); + mFrequencyList->setVisibleItem( 15 ); + + // + // Load the first set of data when this timer expires. I do it this + // way so that the dialog will be visible when the load operation starts. + // + startTimer( 0 ); +} + + +CFileInfoDialog::~CFileInfoDialog( void ) +{ +} + + +void CFileInfoDialog::slotUser1( void ) // Update +{ + if( mBusy ) + return; + + SStatisticControl *sc = new SStatisticControl; + if( sc == 0 ) { return; } + + mBusy = true; + emit collectStatistic( *sc ); + mBusy = false; + + delete sc; + +} + + +void CFileInfoDialog::setDirty( void ) +{ + if( mDirty ) + return; + + mDirtyLabel->setText( + i18n("Warning: Document has been modified since last update")); + mDirty = true; +} + + +void CFileInfoDialog::setClean( void ) +{ + if( !mDirty ) + return; + + mDirtyLabel->setText(""); + mDirty = false; +} + + +const char *printBin( uint val ) +{ + static char buf[9]; + for( int i = 0; i < 8; i++ ) + buf[7-i] = (val&(1<<i)) ? '1' : '0'; + buf[8] = 0; + return( buf ); +} + + +void CFileInfoDialog::setStatistics() // Default +{ + setClean(); + mFrequencyList->clear(); + mFileNameLabel->clear(); + mFileSizeLabel->clear(); + + static const QString u("?"); + QString d, h, o, b, c; + QListViewItem *item = 0; + + char buf[10]; + memset( buf, 0, sizeof( buf ) ); + + for( uint i=0; i<256; i++ ) + { + h.sprintf("0x%02x", i ); + d.sprintf("%03d", i ); + o.sprintf("%03o", i ); + b.sprintf("%s", printBin(i) ); + + const QChar _i((char)i); + c = _i.isPrint() ? _i : QChar('.'); + + item = new CStatisticListViewItem( mFrequencyList, item, h, d, o, b, c, u, u, i, -1 ); + if( i == 0 ) + mFrequencyList->setSelected( item, true ); + } +} + + + +void CFileInfoDialog::setStatistics( SStatisticControl &sc ) +{ + setClean(); + mFrequencyList->clear(); + mFileNameLabel->setText( sc.documentName ); + mFileSizeLabel->setText( KGlobal::locale()->formatNumber(sc.documentSize, 0) ); + + QString d, h, o, b, c, n, p; + QListViewItem *item = 0; + + uint size, pre, i; + // find width of occurrence + for( i=size=0; i<256; i++ ) + if( sc.occurrence[i] > size ) + size = sc.occurrence[i]; + for( pre = 1; size > 0 ; pre++ ) + size /= 10; + + for( i=0; i<256; i++ ) + { + h.sprintf("0x%02x", i ); + d.sprintf("%03d", i ); + o.sprintf("%03o", i ); + b.sprintf("%s", printBin(i) ); + + n = QString("%1").arg( sc.occurrence[i], pre ); + if( sc.documentSize == 0 ) + p = "0.00"; + else + { + double val = 100.0*((double)sc.occurrence[i]/(double)sc.documentSize); + p = QString("%1").arg( val, 6, 'f', 2 ); + } + + const QChar _i((char)i); + c = _i.isPrint() ? _i : QChar('.'); + + item = new CStatisticListViewItem( mFrequencyList, item, h, d, o, b, c, n, p, i, sc.occurrence[i] ); + if( i == 0 ) + mFrequencyList->setSelected( item, true ); + } +} + + + +void CFileInfoDialog::setColumnWidth( void ) +{ + const QFontMetrics &fm = mFrequencyList->fontMetrics(); + int w0, w1, w2, w3, w4; + + w0 = -fm.minLeftBearing() - fm.minRightBearing() + 8 + fm.maxWidth(); + w3 = 0; + + w1 = fm.width( mFrequencyList->header()->label(0) ) + w0; + w2 = fm.width('0')*6; + w3 += w1 > w2 ? w1 : w2; + mFrequencyList->setColumnWidth( 0, w1 > w2 ? w1 : w2 ); + + w1 = fm.boundingRect( mFrequencyList->header()->label(1) ).width() + w0; + w2 = fm.width('0')*5; + w3 += w1 > w2 ? w1 : w2; + mFrequencyList->setColumnWidth( 1, w1 > w2 ? w1 : w2 ); + + w1 = fm.boundingRect( mFrequencyList->header()->label(2) ).width() + w0; + w2 = fm.width('0')*5; + w3 += w1 > w2 ? w1 : w2; + mFrequencyList->setColumnWidth( 2, w1 > w2 ? w1 : w2 ); + + w1 = fm.boundingRect( mFrequencyList->header()->label(3) ).width() + w0; + w2 = fm.width('0')*10; + w3 += w1 > w2 ? w1 : w2; + mFrequencyList->setColumnWidth( 3, w1 > w2 ? w1 : w2 ); + + w1 = fm.boundingRect( mFrequencyList->header()->label(4) ).width() + w0; + w2 = fm.width('0')*3; + w3 += w1 > w2 ? w1 : w2; + mFrequencyList->setColumnWidth( 4, w1 > w2 ? w1 : w2 ); + + w1 = fm.boundingRect( mFrequencyList->header()->label(5) ).width() + w0; + w2 = fm.width('0')*10; + w3 += w1 > w2 ? w1 : w2; + mFrequencyList->setColumnWidth( 5, w1 > w2 ? w1 : w2 ); + + w4 = mFrequencyList->viewport()->width() - w3; + w1 = fm.boundingRect( mFrequencyList->header()->label(6) ).width() + w0; + w2 = fm.width('0')*3; + w1 = w1 > w2 ? w1 : w2; + mFrequencyList->setColumnWidth( 6, w1 > w4 ? w1 : w4 ); +} + + +void CFileInfoDialog::resizeEvent( QResizeEvent * ) +{ + setColumnWidth(); +} + + +void CFileInfoDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + setColumnWidth(); + mFrequencyList->setFocus(); +} + + +void CFileInfoDialog::timerEvent( QTimerEvent * ) +{ + killTimers(); + slotUser1(); +} + + + +#include "fileinfodialog.moc" diff --git a/khexedit/fileinfodialog.h b/khexedit/fileinfodialog.h new file mode 100644 index 0000000..c994d48 --- /dev/null +++ b/khexedit/fileinfodialog.h @@ -0,0 +1,74 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _FILE_INFO_DIALOG_H_ +#define _FILE_INFO_DIALOG_H_ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +class QLabel; + +#include <kdialogbase.h> + +class CListView; +#include "hexbuffer.h" + +class CFileInfoDialog : public KDialogBase +{ + Q_OBJECT + + public: + CFileInfoDialog( QWidget *parent=0, const char *name=0,bool modal=false ); + ~CFileInfoDialog( void ); + + void setStatistics( void ); + void setStatistics( SStatisticControl &sc ); + + public slots: + void setDirty( void ); + void setClean( void ); + + protected slots: + virtual void slotUser1( void ); + + protected: + virtual void resizeEvent( QResizeEvent * ); + virtual void showEvent( QShowEvent * ); + virtual void timerEvent( QTimerEvent * ); + + private: + void setColumnWidth( void ); + + signals: + void collectStatistic( SStatisticControl &sc ); + + private: + bool mBusy; + bool mDirty; + CListView *mFrequencyList; + QLabel *mFileNameLabel; + QLabel *mFileSizeLabel; + QLabel *mDirtyLabel; +}; + +#endif diff --git a/khexedit/hexbuffer.cc b/khexedit/hexbuffer.cc new file mode 100644 index 0000000..0c1d598 --- /dev/null +++ b/khexedit/hexbuffer.cc @@ -0,0 +1,5099 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <ctype.h> +#include <errno.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#include <qfileinfo.h> + +#include <klocale.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <knotifyclient.h> + +#include "hexbuffer.h" +#include "hexerror.h" + +// +// There are some comments marked with a "// ##" at various places. +// These indicate a patch from Sergey A. Sukiyazov which I have applied +// "as is" for now. The number of QString::fromLocal8Bit in this modification +// indicates that I should perhaps modify code elsewhere as well +// (espen 2000-11-26) +// + +// #define DEBUG_FIXED_SIZE 1024 +// #define PRINTER_TEST + + +CHexAction::CHexAction( HexAction action, uint offset ) +{ + mAction = action; + mOffset = offset; + mSize = 0; + mData = 0; + mDataSize = 0; + mNext = 0; +} + +CHexAction::~CHexAction( void ) +{ + delete [] mData; +} + +void CHexAction::setData( uint size, char *data, uint dataSize ) +{ + + if( data != 0 && dataSize > 0 ) + { + mData = new char[ dataSize ]; + if( mData == 0 ) + { + return; + } + memcpy( mData, data, dataSize ); + mDataSize = dataSize; + } + else + { + mDataSize = 0; + mData = 0; + } + mSize = size; +} + + +CHexActionGroup::CHexActionGroup( uint startOffset, uint startBit ) +{ + mStartOffset = startOffset; + mStartBit = startBit; + mHexAction = 0; +} + +CHexActionGroup::~CHexActionGroup( void ) +{ + CHexAction *ptr = mHexAction; + while( ptr != 0 ) + { + CHexAction *next = ptr->mNext; + delete ptr; + ptr = next; + } +} + +void CHexActionGroup::insertAction( CHexAction *hexAction ) +{ + hexAction->mNext = mHexAction; + mHexAction = hexAction; +} + + + +int SFilterControl::execute( uchar *dest, uchar *src, uint size ) +{ + if( size == 0 ) + { + return( Err_IllegalArgument ); + } + + uint numElement = operand.size(); + if( operation == OperandAndData ) + { + if( numElement == 0 ) { return( Err_IllegalArgument ); } + if( forward == true ) + { + for( uint i = 0; i < size; ) + { + for( uint j = 0; i < size && j < numElement; j++, i++ ) + { + dest[i] = src[i] & operand[j]; + } + } + } + else + { + for( uint i = size; i > 0; ) + { + for( uint j = numElement; i > 0 && j > 0; j--, i-- ) + { + dest[i-1] = src[i-1] & operand[j-1]; + } + } + } + } + else if( operation == OperandOrData ) + { + if( numElement == 0 ) { return( Err_IllegalArgument ); } + if( forward == true ) + { + for( uint i = 0; i < size; ) + { + for( uint j = 0; i < size && j < numElement; j++, i++ ) + { + dest[i] = src[i] | operand[j]; + } + } + } + else + { + for( uint i = size; i > 0; ) + { + for( uint j = numElement; i > 0 && j > 0; j--, i-- ) + { + dest[i-1] = src[i-1] | operand[j-1]; + } + } + } + } + else if( operation == OperandXorData ) + { + if( numElement == 0 ) { return( Err_IllegalArgument ); } + if( forward == true ) + { + for( uint i = 0; i < size; ) + { + for( uint j = 0; i < size && j < numElement; j++, i++ ) + { + dest[i] = src[i] ^ operand[j]; + } + } + } + else + { + for( uint i = size; i > 0; ) + { + for( uint j = numElement; i > 0 && j > 0; j--, i-- ) + { + dest[i-1] = src[i-1] ^ operand[j-1]; + } + } + } + } + else if( operation == InvertData ) + { + for( uint i = 0; i < size; i++ ) + { + dest[i] = ~src[i]; + } + } + else if( operation == ReverseData ) + { + for( uint i = 0; i < size; i++ ) + { + uchar flag = src[i]; + uchar rev = 0; + for( uint j = 0; j < 8; j++ ) + { + rev |= (((flag & 0x80) >> (7-j))); + flag <<= 1; + } + dest[i] = rev; + } + } + else if( operation == RotateData || operation == ShiftData ) + { + // + // Only forward here + // + bool up = rotate[1] > 0 ? true : false; + int range = rotate[0]; + int shift = abs(rotate[1]); + if( range == 0 || shift == 0 ) { return( Err_IllegalArgument ); } + shift = shift % (range*8); + + int b = shift / 8; + int s = shift - b * 8; + + for( uint i = 0; i < size; ) + { + if( up == true ) + { + int j; + if( operation == RotateData ) + { + for( j=0; j < b && i+range < size ; i++, j++ ) + { + dest[i] = src[i+range-b]; + } + } + else + { + for( j=0; j < b && i < size ; dest[i] = 0, i++, j++ ); + } + for( ; j < range && i < size ; i++, j++ ) + { + dest[i] = src[i-b]; + } + + uchar last = dest[i-1]; + for( int k=1; k <= j; k++ ) + { + dest[i-k] >>= s; + if( k < j ) + { + dest[i-k] |= dest[i-k-1]<<(8-s); + } + else if( j == range && operation == RotateData ) + { + dest[i-k] |= last<<(8-s); + } + } + } + else + { + int j; + for( j=0; j+b < range && i+b < size ; i++, j++ ) + { + dest[i] = src[i+b]; + } + for( ; j < range && i < size ; i++, j++ ) + { + dest[i] = operation == RotateData ? src[i+b-range] : 0; + } + + uchar first = dest[i-j]; + for( int k=j; k>0; k-- ) + { + dest[i-k] <<= s; + if( k>1 ) + { + dest[i-k] |= dest[i-k+1]>>(8-s); + } + else if( j == range && operation == RotateData ) + { + dest[i-k] |= first>>(8-s); + } + } + } + } + } + else if( operation == SwapBits ) + { + // + // Swap bits. Based on Leon Lessing's work. + // + + // + // Make non swapped version first. + // + for( uint i = 0; i < size; i++ ) + { + dest[i] = src[i]; + } + + // + // Swap the pairs the have been defined + // Format of operand (example): + // 7 2 5 0 0 0 0 0 + // Swap bit 7 with bit 2 and swap bit 5 with bit 0 + // + for( uint j=0; j<4; j++ ) + { + uchar b1 = 1 << (uchar)operand[j*2]; + uchar b2 = 1 << (uchar)operand[j*2+1]; + if( b1 == b2 ) { continue; } // Equal, no need to swap. + + for( uint i = 0; i < size; i++ ) + { + uchar b = 0; + if( dest[i] & b1 ) { b |= b2; } + if( dest[i] & b2 ) { b |= b1; } + + // + // A short description so that I will understand what the + // h... is going on five minutes from now. + // + // Destination byte is masked (AND'ed) with the inverse bitmap + // (the noninversed bitmap contains position of the + // two swap bits, eg 7-2 gives 10000100). Then the destination + // is OR'ed with the swapped bitmap. + // + dest[i] = (dest[i] & ~(b1 | b2)) | b; + } + } + } + else + { + return( Err_IllegalArgument ); + } + + return( Err_Success ); +} + + +const char *SExportCArray::printFormatted( const char *b, uint maxSize ) const +{ + static char buf[12]; + if( elementType == Char ) + { + char e = 0; + memcpy( &e, b, QMIN(sizeof(e),maxSize) ); + sprintf( buf, "%d", e ); + return( buf ); + } + else if( elementType == Uchar ) + { + unsigned char e = 0; + memcpy( &e, b, QMIN(sizeof(e),maxSize) ); + if( unsignedAsHexadecimal == true ) + { + sprintf( buf, "0x%02x", e ); + } + else + { + sprintf( buf, "%u", e ); + } + return( buf ); + } + else if( elementType == Short ) + { + short e = 0; + memcpy( &e, b, QMIN(sizeof(e),maxSize) ); + sprintf( buf, "%d", e ); + return( buf ); + + } + else if( elementType == Ushort ) + { + unsigned short e = 0; + memcpy( &e, b, QMIN(sizeof(e),maxSize) ); + if( unsignedAsHexadecimal == true ) + { + sprintf( buf, "0x%04x", e ); + } + else + { + sprintf( buf, "%u", e ); + } + return( buf ); + } + else if( elementType == Int ) + { + int e = 0; + memcpy( &e, b, QMIN(sizeof(e),maxSize) ); + sprintf( buf, "%u", e ); + return( buf ); + } + else if( elementType == Uint ) + { + unsigned int e = 0; + memcpy( &e, b, QMIN(sizeof(e),maxSize) ); + if( unsignedAsHexadecimal == true ) + { + sprintf( buf, "0x%08x", e ); + } + else + { + sprintf( buf, "%u", e ); + } + return( buf ); + } + else if( elementType == Float ) + { + float e = 0; + memcpy( &e, b, QMIN(sizeof(e),maxSize) ); + sprintf( buf, "%f", e ); + return( buf ); + } + else if( elementType == Double ) + { + double e = 0; + memcpy( &e, b, QMIN(sizeof(e),maxSize) ); + sprintf( buf, "%f", e ); + return( buf ); + } + + else + { + return(""); + } +} + + +QString SExportCArray::variableName( uint range ) const +{ + const char *typeString[] = + { + "char", + "unsigned char", + "short", + "unsigned short", + "int", + "unsigned int", + "float", + "double" + }; + + uint es = elementSize(); + uint numElement = range / es + ((range % es) ? 1 : 0); + + return( QString("%1 %2[%2]").arg(typeString[elementType]). + arg(arrayName).arg(numElement) ); +} + + + +int SExportCArray::elementSize( void ) const +{ + if( elementType == Char || elementType == Uchar ) + { + return( sizeof(char) ); + } + else if( elementType == Short || elementType == Ushort ) + { + return( sizeof(short) ); + } + else if( elementType == Int || elementType == Uint ) + { + return( sizeof(int) ); + } + else if( elementType == Float ) + { + return( sizeof(float) ); + } + else if( elementType == Double ) + { + return( sizeof(double) ); + } + else + { + return(1); + } +} + + +char CHexBuffer::mHexBigBuffer[16]= +{ + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' +}; + +char CHexBuffer::mHexSmallBuffer[16]= +{ + '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' +}; + +char CHexBuffer::mDecBuffer[10]= +{ + '0','1','2','3','4','5','6','7','8','9' +}; + +char CHexBuffer::mOctBuffer[8]= +{ + '0','1','2','3','4','5','6','7' +}; + + +SCursorState CHexBuffer::mCursorState; +SFileState CHexBuffer::mFileState; + + + + +CHexBuffer::CHexBuffer( void ) + :QByteArray() +{ + mColorIndex = 0; + mPrintBuf = 0; + mLoadingData = false; + mEditMode = EditReplace; + mActiveEditor = edit_primary; + + mDocumentModified = false; + + #ifdef DEBUG_FIXED_SIZE + setMaximumSize( DEBUG_FIXED_SIZE ); + #else + setMaximumSize( ~0 ); + #endif + + setDocumentSize(0); + + #ifdef PRINTER_TEST + puts("<CHexBuffer> Printer test is activated"); + #endif + + + setInputMode( mInputMode ); + + int errCode = setLayout( mLayout ); + if( errCode != 0 ) + { + return; + } + setColor( mColor ); + setFont( mFontInfo.init() ); + setShowCursor( true ); + setDisableCursor( false ); + setEditMode( EditReplace, false, false ); + setSoundState( false, false ); + + mUndoLimit = 10; + mUndoIndex = 0; + mUndoList.setAutoDelete( TRUE ); + mBookmarkList.setAutoDelete( TRUE ); +} + + +CHexBuffer::~CHexBuffer( void ) +{ + //debug("CHexBuffer::~CHexBuffer"); + delete [] mColorIndex; + delete [] mPrintBuf; +} + + + +bool CHexBuffer::hasFileName( void ) +{ + // + // FIXME: Files can be called "Untitled" so this must be corrected. + // + if( mUrl.isEmpty() || mUrl.contains( i18n( "Untitled" ), false ) ) + { + return( false ); + } + else + { + return( true ); + } +} + + + +int CHexBuffer::setLayout( SDisplayLayout &layout ) +{ + mLayout = layout; + mLayout.verify(); + + if( mLayout.primaryMode == SDisplayLayout::textOnly ) + { + mActiveEditor = edit_primary; + setEditMode( mEditMode ); + } + + mCursor.setLineSize( mLayout.lineSize ); + mCursor.addOffset( 0 ); // This will only reset the cell position + + computeLineWidth(); + cursorCompute(); + + delete [] mColorIndex; mColorIndex = 0; + delete [] mPrintBuf; mPrintBuf = 0; + + mColorIndex = new unsigned char[ mLayout.lineSize ]; + if( mColorIndex == 0 ) + { + return( Err_NoMemory ); + } + setColor( mColor ); + + // + // The 'mPrintBuf' is used to store formatted text. It is used for all + // print operations and must have the size of the 'mDpyState.lineSize' which + // is the number of bytes in one single display line. + // + mPrintBuf = new char[ mLayout.lineSize < 12 ? 12 : mLayout.lineSize ]; + if( mPrintBuf == 0 ) + { + delete [] mColorIndex; mColorIndex = 0; + return( Err_NoMemory ); + } + + return( Err_Success ); +} + + +void CHexBuffer::setColor( SDisplayColor &color ) +{ + mColor = color; + + // + // Test... + // + //mColor.secondTextBg = Qt::yellow; + //mColor.offsetBg = Qt::lightGray; + //mColor.gridFg = Qt::darkCyan; + + /* + mColor.secondTextBg = mColor.textBg; + mColor.offsetBg = mColor.textBg; + mColor.gridFg = mColor.textBg; + */ + + if( mColorIndex != 0 ) + { + uint columnSize = mLayout.columnSize == 0 ? 1 : mLayout.columnSize; + for( uint i = 0, entry = 0; i < mLayout.lineSize; i++ ) + { + if( i > 0 && i % columnSize == 0 ) { entry = entry == 0 ? 1 : 0; } + mColorIndex[i] = entry; + } + } +} + +void CHexBuffer::setInputMode( SDisplayInputMode &mode ) +{ + mInputMode = mode; + if( mInputMode.allowResize == false && mEditMode != EditReplace ) + { + setEditMode( EditReplace ); + } +} + + +bool CHexBuffer::toggleEditor( void ) +{ + bool changed; + if( mLayout.secondaryMode == SDisplayLayout::hide ) + { + changed = mActiveEditor == edit_secondary ? true : false; + mActiveEditor = edit_primary; + } + else + { + changed = true; + mActiveEditor = mActiveEditor == edit_primary ? + edit_secondary : edit_primary; + } + + setEditMode( mEditMode ); // Sets the cursor shapes as well + + if( changed == true ) + { + mCursor.resetCell(); + cursorCompute(); + } + + return( changed ); +} + + + + + + + +bool CHexBuffer::matchWidth( uint width ) +{ + if( documentPresent() == false || (uint)mFixedWidth >= width ) + { + return( false ); + } + + width -= mFixedWidth; + + uint g = mLayout.columnSpacing == 0 ? 1 : mLayout.columnSize; + uint n = g * mNumCell; + uint u = mUnitWidth; + uint s = mLayout.secondaryMode == SDisplayLayout::hide ? 0 : g; + uint o = mLayout.columnSpacing == 0 ? 0 : mSplitWidth; + float x = (float)(width+o)/(float)(u*(n+s)+o); + + uint lineSize = (uint)x * g; + + if( mLayout.lockColumn == false ) + { + // + // Examine if we can add one or more entries from the next column. This + // will make the rightmost column smaller than the rest but we will + // utilize as much of the available space (ie., width) as possible. + // (Note that the entry itself (which represents one byte of filedata) + // can not be splitted, eg., in binary mode the entry is eight byte + // wide and will not be splitted). + // + int w = (int)((float)((int)x)* (float)(u*(n+s)+o) - (float)o); + if( w > 0 && (uint)w < width ) + { + width -= w; + if( width > o ) + { + x = (float)(width-o) / (float)(u*(mNumCell+1)); + lineSize += (uint)x; + } + } + } + + if( lineSize == 0 || lineSize == mLayout.lineSize ) + { + // + // We have to redraw all text if a change occurs so we avoid it if + // possible. + // + return( false ); + } + + mLayout.lineSize = lineSize; + setLayout( mLayout ); + return( true ); +} + + +void CHexBuffer::setNonPrintChar( QChar nonPrintChar ) +{ + mFontInfo.nonPrintChar = nonPrintChar; +} + + +void CHexBuffer::setShowCursor( bool showCursor ) +{ + mShowCursor = showCursor; +} + + +void CHexBuffer::setDisableCursor( bool disableCursor ) +{ + mDisableCursor = disableCursor; +} + + +void CHexBuffer::setCursorShapeModifier( bool alwaysBlock, bool thickInsert ) +{ + mCursor.setShapeModifier( alwaysBlock, thickInsert ); + setEditMode( mEditMode ); +} + +void CHexBuffer::setEditMode( EEditMode editMode, bool alwaysBlock, + bool thickInsert ) +{ + mCursor.setShapeModifier( alwaysBlock, thickInsert ); + setEditMode( editMode ); +} + +void CHexBuffer::setEditMode( EEditMode editMode ) +{ + mEditMode = editMode; + if( mEditMode == EditInsert ) + { + if( mActiveEditor == edit_primary ) + { + mCursor.setShape( SCursorSpec::thin, SCursorSpec::frame, mUnitWidth, + mNumCell ); + } + else + { + mCursor.setShape( SCursorSpec::frame, SCursorSpec::thin, mUnitWidth, + mNumCell ); + } + + } + else + { + if( mActiveEditor == edit_primary ) + { + mCursor.setShape( SCursorSpec::solid, SCursorSpec::frame, mUnitWidth, + mNumCell ); + } + else + { + mCursor.setShape( SCursorSpec::frame, SCursorSpec::solid, mUnitWidth, + mNumCell ); + } + } +} + + + +void CHexBuffer::setMaximumSize( uint maximumSize ) +{ + if( maximumSize == 0 ) { maximumSize = ~0; } + + mMaximumSize = maximumSize; + mFixedSizeMode = maximumSize == (uint)~0 ? false : true; + mCursor.setFixedSizeMode( mFixedSizeMode ); + + if( mLayout.offsetVisible == false ) + { + mOffsetSize = 0; + mOffsetIndex = 0; + printOffset = &CHexBuffer::printDummyOffset; + } + else + { + if( mLayout.offsetMode == SDisplayLayout::decimal ) + { + printOffset = &CHexBuffer::printDecimalOffset; + for( mOffsetSize=0; maximumSize > 0; mOffsetSize += 1 ) + { + maximumSize = maximumSize / 10; + } + mOffsetIndex = 10 - mOffsetSize; + } + else if( mLayout.offsetMode == SDisplayLayout::hexadecimal ) + { + if( mLayout.offsetUpperCase == true ) + { + printOffset = &CHexBuffer::printHexadecimalBigOffset; + } + else + { + printOffset = &CHexBuffer::printHexadecimalSmallOffset; + } + for( mOffsetSize=0; maximumSize > 0; mOffsetSize += 1 ) + { + maximumSize = maximumSize / 16; + } + if( mOffsetSize > 4 ) { mOffsetSize += 1; } // Space for the ':' sign + mOffsetIndex = 9 - mOffsetSize; + } + else + { + mLayout.offsetVisible = false; + mOffsetSize = 0; + mOffsetIndex = 0; + printOffset = &CHexBuffer::printDummyOffset; + } + } +} + + +void CHexBuffer::setDocumentSize( uint size ) +{ + if( size > mMaximumSize ) { size = mMaximumSize; } + mDocumentSize = size; + mCursor.setDocumentSize( size ); + updateBookmarkMap(true); +} + + +void CHexBuffer::setUndoLevel( uint level ) +{ + if( level < 10 ) { level = 10; } + + if( level >= mUndoLimit ) + { + mUndoLimit = level; + return; + } + else + { + // + // The maximum size decreases. If the list is larger than the the new + // limit, then reduce the list size starting with the oldest elements. + // + mUndoLimit = level; + while( mUndoList.count() >= mUndoLimit ) + { + mUndoList.removeFirst(); + mUndoIndex -= (mUndoIndex > 0 ? 1 : 0); + } + } +} + + +void CHexBuffer::setSoundState( bool inputSound, bool fatalSound ) +{ + mInputErrorSound = inputSound; + mFatalErrorSound = fatalSound; +} + + +void CHexBuffer::setBookmarkVisibility( bool showInColumn, bool showInEditor ) +{ + mShowBookmarkInOffsetColumn = showInColumn; + mShowBookmarkInEditor = showInEditor; +} + +int CHexBuffer::writeFile( QFile &file, CProgress &p ) +{ + uint offset = 0; + uint remaining = documentSize(); + + do + { + const uint blockSize = QMIN( 131072 /* == 1024 * 128 */ , remaining ); + const int writeSize = file.writeBlock( data() + offset, blockSize ); + if( writeSize == -1 ) + { + p.finish(); + return( Err_ReadFailed ); + } + offset += blockSize; + remaining -= blockSize; + + if( p.expired() == true ) + { + int errCode = p.step( (float)offset/(float)documentSize() ); + if( errCode == Err_Stop && remaining > 0 ) + { + p.finish(); + return( Err_Success ); + } + } + } + while( remaining > 0 ); + + p.finish(); + mDocumentModified = false; + registerDiskModifyTime( file ); + + return( Err_Success ); +} + + +int CHexBuffer::readFile( QFile &file, const QString &url, CProgress &p ) +{ + if( resize( file.size() + 100 ) == false ) + { + p.finish(); + return( Err_NoMemory ); + } + + if( file.size() > 0 ) + { + mLoadingData = true; + uint offset = 0; + uint remaining = file.size(); + while( remaining > 0 ) + { + const uint blockSize = QMIN( 131072 /* == 1024 * 128 */ , remaining ); + const int readSize = file.readBlock( data() + offset, blockSize ); + if( readSize == -1 ) + { + p.finish(); + mLoadingData = false; + return( Err_ReadFailed ); + } + for( uint i=0; i<blockSize; i++) + { + data()[offset+i] = mEncode[ (unsigned char) data()[offset+i] ]; + } + + offset += blockSize; + remaining -= blockSize; + + if( p.expired() == true ) + { + int errCode = p.step( (float)offset/(float)file.size() ); + if( errCode == Err_Stop && remaining > 0 ) + { + p.finish(); + return( Err_OperationAborted ); + } + } + } + mLoadingData = false; + } + + p.finish(); + + mDocumentModified = false; + setDocumentSize( file.size() ); + registerDiskModifyTime( file ); + setUrl( url ); + computeNumLines(); + mSelect.reset(); + mMark.reset(); + mUndoList.clear(); + mUndoIndex = 0; + + return( Err_Success ); +} + + +int CHexBuffer::insertFile( QFile &file, CProgress &p ) +{ + if( file.size() == 0 ) + { + p.finish(); + return( Err_Success ); + } + + QByteArray array( file.size() ); + if( array.isNull() == true ) + { + p.finish(); + return( Err_NoMemory ); + } + + uint offset = 0; + uint remaining = file.size(); + while( remaining > 0 ) + { + const uint blockSize = QMIN( 131072 /* == 1024 * 128 */ , remaining ); + const int readSize = file.readBlock( array.data() + offset, blockSize ); + if( readSize == -1 ) + { + p.finish(); + return( Err_ReadFailed ); + } + for( uint i=0; i<blockSize; i++) + { + array[offset+i] = mEncode[ (unsigned char) array[offset+i] ]; + } + + offset += blockSize; + remaining -= blockSize; + + if( p.expired() == true ) + { + int errCode = p.step( (float)offset/(float)file.size() ); + if( errCode == Err_Stop && remaining > 0 ) + { + p.finish(); + return( Err_OperationAborted ); + } + } + } + + p.finish(); + + int errCode = inputAtCursor( array, 0 ); + return( errCode ); +} + + +int CHexBuffer::newFile( const QString &url ) +{ + if( resize( 100 ) == 0 ) + { + return( Err_NoMemory ); + } + + mDocumentModified = false; + setDocumentSize( 0 ); + setUrl( url ); + computeNumLines(); + mSelect.reset(); + + return( Err_Success ); +} + + +void CHexBuffer::closeFile( void ) +{ + resize(0); + computeNumLines(); + + mUndoList.clear(); + mUndoIndex = 0; + + setDocumentSize(0); + mDocumentModified = false; + + QString emptyUrl; + setUrl( emptyUrl ); + + mSelect.reset(); + mMark.reset(); + + removeBookmark(-1); // Negative index - All bookmarks +} + + +void CHexBuffer::registerDiskModifyTime( const QFile &file ) +{ + QFileInfo fileInfo( file ); + mDiskModifyTime = fileInfo.lastModified(); +} + + + +void CHexBuffer::setFont( const SDisplayFontInfo &fontInfo ) +{ + mFontInfo = fontInfo; + QFontMetrics fm( mFontInfo.font ); + mFontHeight = fm.height(); + mFontAscent = fm.ascent(); + computeLineWidth(); + + for( int i=0; i < 256; i++ ) + { + mCharValid[i] = QChar(i).isPrint(); + } + + /* + QFontInfo info( mFontInfo.font ); + puts("CHexBuffer mCharValid broken"); + + KCharset charset( info.charSet() ); + for( int i=0; i < 256; i++ ) + { + mCharValid[i] = charset.printable(i); + } + */ +} + + +int CHexBuffer::setEncoding( CConversion::EMode mode, CProgress &p ) +{ + int errCode = mEncode.convert( *this, mode, p ); + if( errCode == Err_Success ) + { + // + // The cursor stores the byte it is "covering", so this information + // must be updated. + // + cursorCompute(); + } + + return( errCode ); +} + + + + +void CHexBuffer::computeLineWidth( void ) +{ + QFontMetrics fm( mFontInfo.font ); + mUnitWidth = fm.width( "M" ); + + if( mLayout.primaryMode == SDisplayLayout::textOnly ) + { + mSplitWidth = 0; + } + else if( mLayout.columnCharSpace == true ) + { + mSplitWidth = mUnitWidth; + } + else + { + mSplitWidth = mLayout.columnSpacing; + } + + setMaximumSize( mMaximumSize ); + + if( mLayout.primaryMode == SDisplayLayout::hexadecimal ) + { + mNumCell = 2; + mCursor.setCellWeight( 4 ); + if( mLayout.primaryUpperCase == true ) + { + printCell = &CHexBuffer::printHexadecimalBigCell; + inputCell = &CHexBuffer::inputHexadecimal; + } + else + { + printCell = &CHexBuffer::printHexadecimalSmallCell; + inputCell = &CHexBuffer::inputHexadecimal; + } + } + else if( mLayout.primaryMode == SDisplayLayout::decimal ) + { + mNumCell = 3; + printCell = &CHexBuffer::printDecimalCell; + inputCell = &CHexBuffer::inputDecimal; + mCursor.setCellWeight( 3 ); + } + else if( mLayout.primaryMode == SDisplayLayout::octal ) + { + mNumCell = 3; + printCell = &CHexBuffer::printOctalCell; + inputCell = &CHexBuffer::inputOctal; + mCursor.setCellWeight( 3 ); + } + else if( mLayout.primaryMode == SDisplayLayout::binary ) + { + mNumCell = 8; + printCell = &CHexBuffer::printBinaryCell; + inputCell = &CHexBuffer::inputBinary; + mCursor.setCellWeight( 1 ); + } + else if( mLayout.primaryMode == SDisplayLayout::textOnly ) + { + mNumCell = 1; + printCell = &CHexBuffer::printAsciiCell; + inputCell = &CHexBuffer::inputAscii; + mCursor.setCellWeight( 8 ); + } + else + { + mNumCell = 2; + mLayout.primaryMode = SDisplayLayout::hexadecimal; + mLayout.primaryUpperCase = false; + printCell = &CHexBuffer::printHexadecimalSmallCell; + inputCell = &CHexBuffer::inputHexadecimal; + mCursor.setCellWeight( 4 ); + } + + // + // 'mPrimaryWidth' is the number of pixels that are needed to display a + // line in the primary field. + // + mPrimaryWidth = mLayout.lineSize * mNumCell * mUnitWidth; + + if( mLayout.columnSpacing != 0 ) + { + int numSplit = mLayout.lineSize / mLayout.columnSize; + numSplit -= mLayout.lineSize % mLayout.columnSize == 0 ? 1 : 0; + mPrimaryWidth += numSplit * mSplitWidth; + } + + // + // 'mSecondaryWidth' is the number of pixels that are needed to display a + // line in the secondary field (there are no spaces). + // + if( mLayout.secondaryMode == SDisplayLayout::hide ) + { + mSecondaryWidth = 0; + } + else + { + mSecondaryWidth = mLayout.lineSize * mUnitWidth; + } + + // + // 'mLineWidth' is the total number of pixels required to display + // offset data, separators, primary and secondary data on a line. + // + mLineWidth = mPrimaryWidth + mSecondaryWidth + mOffsetSize * mUnitWidth; + + // + // The 'mFixedWidth' is the number of pixels of the width that stays the + // same regardless of how many characters that are displayed. + // This entity consists of the edge margins, the inner margins and the + // separators. + // + mFixedWidth = mOffsetSize * mUnitWidth; + + // + // The edge margin is always present in both ends. + // + mLineWidth += mLayout.edgeMarginWidth * 2; + mFixedWidth += mLayout.edgeMarginWidth * 2; + + // + // 'mTextStart1' is the number of pixels from the left edge where the + // primary field starts. + // + mTextStart1 = mLayout.edgeMarginWidth; + if( mLayout.offsetVisible == true ) + { + int width; + if( mLayout.leftSeparatorWidth > 0 ) + { + width = mLayout.separatorMarginWidth * 2 + mLayout.leftSeparatorWidth; + } + else + { + width = (mLayout.separatorMarginWidth * 3) / 2; + } + + mLineWidth += width; + mFixedWidth += width; + mTextStart1 += width + mOffsetSize * mUnitWidth; + } + + // + // 'mTextStart2' is the number of pixels from the left edge where the + // secondary fields start. + // + mTextStart2 = mTextStart1; + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + int width; + if( mLayout.rightSeparatorWidth > 0 ) + { + width = mLayout.separatorMarginWidth * 2 + mLayout.rightSeparatorWidth; + } + else + { + width = (mLayout.separatorMarginWidth * 3) / 2; + } + + mLineWidth += width; + mFixedWidth += width; + mTextStart2 += width + mPrimaryWidth; + } + + setEditMode( mEditMode ); + computeNumLines(); +} + + +void CHexBuffer::computeNumLines( void ) +{ + if( mLayout.lineSize == 0 ) + { + mNumLines = 1; + } + else + { + uint s = mFixedSizeMode == true ? mMaximumSize : documentSize() + 1; + mNumLines = s / mLayout.lineSize + (s % mLayout.lineSize ? 1 : 0); + } +} + + + +void CHexBuffer::drawSelection( QPainter &paint, QColor &color, uint start, + uint stop, int sx ) +{ + if( start >= stop ) { return; } + uint width = stop - start; + + uint addStart, addWidth; + addStart = (start / mLayout.columnSize) * mSplitWidth; + if( width == 0 ) + { + addWidth = 0; + } + else + { + uint g = mLayout.columnSize; + addWidth = (((start % g) + width - 1) / g) * mSplitWidth; + } + + int offset = mTextStart1 - sx; + paint.fillRect( offset + start * mNumCell * mUnitWidth + addStart, + 0, width * mNumCell * mUnitWidth + addWidth, + mFontHeight, color ); + + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + offset = mTextStart2 - sx; + paint.fillRect( offset + start * mUnitWidth, + 0, width * mUnitWidth, + mFontHeight, color ); + } +} + + + + + +void CHexBuffer::drawText( QPainter &paint, uint line, int sx, int x1, int x2 ) +{ + uint fileOffset = line * mLayout.lineSize; + if( documentPresent() == false || mLoadingData == true ) + { + paint.fillRect( x1, 0, x2-x1, lineHeight(), mColor.inactiveBg ); + return; + } + + bool outsideText; + if( size() == 0 || fileOffset > documentSize() || fileOffset >= mMaximumSize) + { + outsideText = true; + } + else + { + outsideText = false; + } + + if( (line+1) % 2 || outsideText == true ) + { + paint.fillRect( x1, 0, x2-x1, lineHeight(), mColor.textBg ); + } + else + { + paint.fillRect( x1, 0, x2-x1, lineHeight(), mColor.secondTextBg ); + } + if( mLayout.horzGridWidth > 0 && outsideText == false ) + { + paint.setPen( mColor.gridFg ); + paint.drawLine( x1, mFontHeight, x2, mFontHeight ); + } + + if( mSelect.inside( fileOffset, mLayout.lineSize ) == true ) + { + uint start = mSelect.start( fileOffset ); + uint stop = mSelect.stop( fileOffset, mLayout.lineSize ); + drawSelection( paint, mColor.selectBg, start, stop, sx ); + } + + // + // A marked area will be displayed "above" a selcted area (given + // the mark background color is different) + // + if( mMark.inside( fileOffset, mLayout.lineSize ) == true ) + { + uint start = mMark.start( fileOffset ); + uint stop = mMark.stop( fileOffset, mLayout.lineSize ); + drawSelection( paint, mColor.markBg, start, stop, sx ); + } + + uint dataSize; + unsigned char *fileData; + if( outsideText == true ) + { + if( size() == 0 ) + { + return; + } + dataSize = 0; + fileData = 0; + } + else + { + dataSize = documentSize() - fileOffset; + if( dataSize > mLayout.lineSize ) { dataSize = mLayout.lineSize; } + fileData = (unsigned char*)&(data()[ fileOffset ]); + } + + // + // Compute the offset area size. We postpose the actual drawing + // until we have drawn any bookmark indicators in the editor areas. + // because we may want to draw an indicator in the offset area as well. + // + int offset = mLayout.edgeMarginWidth - sx; + if( mLayout.offsetVisible == true ) + { + offset += mOffsetSize * mUnitWidth; + if( mLayout.leftSeparatorWidth > 0 ) + { + offset += mLayout.leftSeparatorWidth + mLayout.separatorMarginWidth*2; + } + else + { + offset += (mLayout.separatorMarginWidth * 3) / 2; + } + } + + + #if 0 + int offset = mLayout.edgeMarginWidth - sx; + if( mLayout.offsetVisible == true ) + { + int s0 = mOffsetSize * mUnitWidth; + int s1 = s0 + mLayout.separatorMarginWidth + mLayout.edgeMarginWidth - sx; + if( x1 < s1 && x2 > 0 ) + { + if( outsideText == true ) + { + paint.fillRect( 0, 0, s1, lineHeight(), mColor.offsetBg ); + } + else + { + // + // I want to display the grid here so I cant use lineHeight() + // + paint.fillRect( 0, 0, s1, mFontHeight, mColor.offsetBg ); + } + } + + if( x1 < offset + s0 && x2 >= offset && fileData != 0 ) + { + paint.setPen( mColor.offsetFg ); + THIS_FPTR(printOffset)( mPrintBuf, fileOffset ); + // ## paint.drawText(offset,mFontAscent,&mPrintBuf[mOffsetIndex], + // mOffsetSize); + paint.drawText( offset, mFontAscent, + QString::fromLocal8Bit(&mPrintBuf[mOffsetIndex]), + mOffsetSize ); + } + offset += s0; + + if( mLayout.leftSeparatorWidth > 0 ) + { + offset += mLayout.separatorMarginWidth; + + int s2 = mLayout.leftSeparatorWidth + mLayout.separatorMarginWidth; + if( x1 < offset + s2 && x2 >= offset ) + { + QPen pen( mColor.leftSeparatorFg, mLayout.leftSeparatorWidth ); + paint.setPen( pen ); + int center = offset + mLayout.leftSeparatorWidth/2; + paint.drawLine( center, 0, center, lineHeight() ); + } + offset += s2; + } + else + { + offset += (mLayout.separatorMarginWidth * 3) / 2; + } + } + #endif + + + // + // Draw the primary area + // + int localOffset = offset; + for( uint i = 0; i < dataSize; i++ ) + { + int s = mNumCell * mUnitWidth + + ((i+1) % mLayout.columnSize == 0) * mSplitWidth; + if( x1 < localOffset + s && x2 >= localOffset ) + { + int flag = THIS_FPTR(printCell)( mPrintBuf, fileData[i] ); + if( mSelect.inside( fileOffset+i ) ) + { + paint.setPen( mColor.selectFg ); + } + else if( mMark.inside( fileOffset+i ) ) + { + paint.setPen( mColor.markFg ); + } + else + { + paint.setPen( flag == 0 ? foregroundColor( i ) : mColor.nonPrintFg ); + } + + // ## paint.drawText( localOffset, mFontAscent, mPrintBuf, mNumCell ); + paint.drawText( localOffset, mFontAscent, + QString::fromLocal8Bit(mPrintBuf), mNumCell ); + } + localOffset += s; + + if( mLayout.vertGridWidth > 0 && i+1 < dataSize ) + { + if( (i+1) % mLayout.columnSize == 0 ) + { + paint.setPen( mColor.gridFg ); + int x = localOffset - (mSplitWidth+1) / 2; + paint.drawLine( x, 0, x, mFontHeight ); + } + } + } + + // + // Draw the secondary area + // + offset += mPrimaryWidth; + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + if( mLayout.rightSeparatorWidth > 0 ) + { + offset += mLayout.separatorMarginWidth; + int s = mLayout.separatorMarginWidth + mLayout.rightSeparatorWidth; + if( x1 < offset + s && x2 >= offset ) + { + QPen pen( mColor.rightSeparatorFg, mLayout.rightSeparatorWidth ); + paint.setPen( pen ); + int center = offset + mLayout.rightSeparatorWidth/2; + paint.drawLine( center, 0, center, lineHeight() ); + } + offset += s; + } + else + { + offset += (mLayout.separatorMarginWidth * 3) / 2; + } + + int s = mUnitWidth; + for( uint i = 0; i < dataSize; i++ ) + { + if( x1 < offset + s && x2 >= offset ) + { + int flag = printAsciiCell( mPrintBuf, fileData[i] ); + if( mSelect.inside( fileOffset+i ) ) + { + paint.setPen( mColor.selectFg ); + } + else if( mMark.inside( fileOffset+i ) ) + { + paint.setPen( mColor.markFg ); + } + else + { + paint.setPen( flag == 0 ? mColor.secondaryFg : mColor.nonPrintFg ); + } + + // ## paint.drawText( offset, mFontAscent, mPrintBuf, 1 ); + paint.drawText( offset, mFontAscent, + QString::fromLocal8Bit(mPrintBuf), 1 ); + } + offset += s; + } + } + + // + // Draw the bookmark identifiers on this line (if any). We use the + // bitmask to minimize the number of times we try to draw the bookmarks. + // + int bookmarkPosition = 0; + if( mBookmarkMap.testBit(fileOffset/200) || + mBookmarkMap.testBit((fileOffset+mLayout.lineSize-1)/200 ) ) + { + // Returns a bookmark postion state + bookmarkPosition = drawBookmarks( paint, line, sx ); + } + + // + // Draw the offset area. We have delayed the drawing until now because + // it is possible to draw a bookmark indicator in this area. + // + offset = mLayout.edgeMarginWidth - sx; + if( mLayout.offsetVisible == true ) + { + int s0 = mOffsetSize * mUnitWidth; + int s1 = s0 + mLayout.separatorMarginWidth + mLayout.edgeMarginWidth - sx; + if( x1 < s1 && x2 > 0 ) + { + QColor bg = mShowBookmarkInOffsetColumn && + (bookmarkPosition & BookmarkOnLine) ? + mColor.bookmarkBg : mColor.offsetBg; + if( outsideText == true ) + { + paint.fillRect( 0, 0, s1, lineHeight(), bg ); + } + else + { + // + // I want to display the grid here so I cant use lineHeight() + // + paint.fillRect( 0, 0, s1, mFontHeight, bg ); + } + } + + if( x1 < offset + s0 && x2 >= offset && fileData != 0 ) + { + paint.setPen( mShowBookmarkInOffsetColumn && + bookmarkPosition & BookmarkOnLine ? + mColor.bookmarkFg : mColor.offsetFg ); + THIS_FPTR(printOffset)( mPrintBuf, fileOffset ); + // ## paint.drawText(offset,mFontAscent,&mPrintBuf[mOffsetIndex], + // mOffsetSize); + paint.drawText( offset, mFontAscent, + QString::fromLocal8Bit(&mPrintBuf[mOffsetIndex]), + mOffsetSize ); + } + + offset += s0; + + if( mLayout.leftSeparatorWidth > 0 ) + { + offset += mLayout.separatorMarginWidth; + + int s2 = mLayout.leftSeparatorWidth + mLayout.separatorMarginWidth; + if( x1 < offset + s2 && x2 >= offset ) + { + QPen pen( mColor.leftSeparatorFg, mLayout.leftSeparatorWidth ); + paint.setPen( pen ); + int center = offset + mLayout.leftSeparatorWidth/2; + paint.drawLine( center, 0, center, lineHeight() ); + } + } + } + + + // + // If the cursors are located on the line we have drawn we redraw + // them unless they have been disabled. + // + if( mDisableCursor == false ) + { + if( mCursor.curr.inside( fileOffset, fileOffset + mLayout.lineSize ) ) + { + drawCursor( paint, line, sx, bookmarkPosition & BookmarkOnCursor ); + } + } + +} + + + + +void CHexBuffer::drawText( QPainter &paint, uint line, int x1, int x2, int y, + bool useBlackWhite ) +{ + uint fileOffset = line * mLayout.lineSize; + + bool outsideText; + if( size() == 0 || fileOffset > documentSize() || fileOffset >= mMaximumSize) + { + outsideText = true; + } + else + { + outsideText = false; + } + + if( (line+1) % 2 || outsideText == true ) + { + paint.fillRect( x1, y, x2, lineHeight(), + useBlackWhite == true ? Qt::white : mColor.textBg ); + } + else + { + paint.fillRect( x1, y, x2, lineHeight(), + useBlackWhite == true ? Qt::white : mColor.secondTextBg ); + } + + if( mLayout.horzGridWidth > 0 && outsideText == false ) + { + QPen pen( useBlackWhite == true ? Qt::black : mColor.gridFg, + mLayout.horzGridWidth ); + paint.setPen( pen ); + paint.drawLine( x1, y+mFontHeight, x2+x1, y+mFontHeight ); + } + + uint dataSize; + unsigned char *fileData; + if( outsideText == true ) + { + if( size() == 0 ) + { + return; + } + dataSize = 0; + fileData = 0; + } + else + { + dataSize = documentSize() - fileOffset; + if( dataSize > mLayout.lineSize ) { dataSize = mLayout.lineSize; } + fileData = (unsigned char*)&(data()[ fileOffset ]); + } + + int offset = mLayout.edgeMarginWidth + x1; + + if( mLayout.offsetVisible == true ) + { + int s1 = mOffsetSize * mUnitWidth; + if( fileData != 0 ) + { + paint.setPen( useBlackWhite == true ? Qt::black : mColor.offsetFg ); + THIS_FPTR(printOffset)( mPrintBuf, fileOffset ); + // ## paint.drawText( offset, mFontAscent+y, &mPrintBuf[mOffsetIndex], + // mOffsetSize ); + paint.drawText( offset, mFontAscent+y, + QString::fromLocal8Bit(&mPrintBuf[mOffsetIndex]), + mOffsetSize ); + } + offset += s1; + + if( mLayout.leftSeparatorWidth > 0 ) + { + offset += mLayout.separatorMarginWidth; + + int s2 = mLayout.leftSeparatorWidth + mLayout.separatorMarginWidth; + QPen pen( useBlackWhite == true ? Qt::black : mColor.leftSeparatorFg, + mLayout.leftSeparatorWidth ); + paint.setPen( pen ); + int center = offset + mLayout.leftSeparatorWidth/2; + paint.drawLine( center, y, center, mFontHeight+y ); + offset += s2; + } + else + { + offset += (mLayout.separatorMarginWidth * 3) / 2; + } + } + + int localOffset = offset; + for( uint i = 0; i < dataSize; i++ ) + { + int s = mNumCell * mUnitWidth + + ((i+1) % mLayout.columnSize == 0) * mSplitWidth; + int flag = THIS_FPTR(printCell)( mPrintBuf, fileData[i] ); + if( useBlackWhite == true ) + { + paint.setPen( Qt::black ); + } + else + { + paint.setPen( flag == 0 ? foregroundColor( i ) : mColor.nonPrintFg ); + } + // ## paint.drawText( localOffset, mFontAscent+y, mPrintBuf, mNumCell ); + paint.drawText( localOffset, mFontAscent+y, + QString::fromLocal8Bit(mPrintBuf), mNumCell ); + localOffset += s; + + if( mLayout.vertGridWidth > 0 && i+1 < dataSize ) + { + if( (i+1) % mLayout.columnSize == 0 ) + { + QPen pen( useBlackWhite == true ? Qt::black : mColor.gridFg, + mLayout.vertGridWidth ); + paint.setPen( pen ); + int x = localOffset - (mSplitWidth+1) / 2; + paint.drawLine( x, y, x, y+mFontHeight ); + } + } + + } + + offset += mPrimaryWidth; + + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + if( mLayout.rightSeparatorWidth > 0 ) + { + offset += mLayout.separatorMarginWidth; + int s = mLayout.separatorMarginWidth + mLayout.rightSeparatorWidth; + QPen pen( useBlackWhite == true ? Qt::black : mColor.rightSeparatorFg, + mLayout.rightSeparatorWidth ); + paint.setPen( pen ); + int center = offset + mLayout.rightSeparatorWidth/2; + paint.drawLine( center, y, center, mFontHeight+y ); + offset += s; + } + else + { + offset += (mLayout.separatorMarginWidth * 3) / 2; + } + + + int s = mUnitWidth; + for( uint i = 0; i < dataSize; i++ ) + { + int flag = printAsciiCell( mPrintBuf, fileData[i] ); + if( useBlackWhite == true ) + { + paint.setPen( Qt::black ); + } + else + { + paint.setPen( flag == 0 ? mColor.secondaryFg : mColor.nonPrintFg ); + } + // ## paint.drawText( offset, mFontAscent+y, mPrintBuf, 1 ); + paint.drawText( offset, mFontAscent+y, + QString::fromLocal8Bit(mPrintBuf), 1 ); + offset += s; + } + } + +} + + +int CHexBuffer::headerHeight( QPainter &paint ) +{ + QFont font( paint.font() ); + paint.setFont( KGlobalSettings::generalFont() ); + const QFontMetrics &fm = paint.fontMetrics(); + + int height = fm.height(); + paint.setFont( font ); + return( height ); +} + +int CHexBuffer::headerMargin( QPainter &paint ) +{ + QFont font( paint.font() ); + paint.setFont( KGlobalSettings::generalFont() ); + const QFontMetrics &fm = paint.fontMetrics(); + + int margin = fm.height() / 2; + paint.setFont( font ); + return( margin ); +} + + +void CHexBuffer::drawHeader( QPainter &paint, int sx, int width, int y, + bool isFooter, const SPageHeader &header, + const SPagePosition &position ) +{ + QFont font( paint.font() ); + paint.setFont( KGlobalSettings::generalFont() ); + const QFontMetrics &fm = paint.fontMetrics(); + + paint.fillRect( sx, y, width, fm.height(), Qt::white ); + paint.setPen( Qt::black ); + if( header.line == SPageHeader::SingleLine ) + { + if( isFooter == false ) + { + paint.drawLine( sx, y+fm.height(), sx+width, y+fm.height() ); + } + else + { + paint.drawLine( sx, y, sx+width, y ); + } + } + else if( header.line == SPageHeader::Rectangle ) + { + paint.drawRect( sx, y, width, fm.height() ); + } + + int pos[3] = + { + QPainter::AlignLeft, QPainter::AlignHCenter, QPainter::AlignRight + }; + + QString msg; + for( int i=0; i<3; i++ ) + { + if( header.pos[i] == SPageHeader::DateTime ) + { + QDateTime datetime; + datetime.setTime_t( position.now ); + msg = KGlobal::locale()->formatDateTime(datetime); + } + else if( header.pos[i] == SPageHeader::PageNumber ) + { + msg = i18n("Page %1 of %2") + .arg(KGlobal::locale()->formatNumber(position.curPage, 0)) + .arg(KGlobal::locale()->formatNumber(position.maxPage, 0)); + } + else if( header.pos[i] == SPageHeader::FileName ) + { + msg = mUrl; + } + else + { + continue; + } + + if( 0 && pos[i] == QPainter::AlignRight ) + { + //const QFontMetrics &f = QFontMetrics( KGlobalSettings::generalFont() ); + //QRect r = paint.boundingRect(sx, y, width, fm.height(), pos[i], msg ); + //printf("R: %d, %d, %d, %d\n", r.x(), r.y(), r.width(), r.height() ); + + int x = sx + width - /*r.width();*/ fm.width(msg); + paint.drawText( x, y+fm.height(), msg ); + //printf("paint at %d\n", x ); + } + else + { + paint.drawText( sx, y, width, fm.height(), pos[i], msg ); + } + } + + // + // restore original font. + // + paint.setFont( font ); +} + + + + +int CHexBuffer::drawBookmarks( QPainter &paint, uint line, int startx ) +{ + if( documentPresent() == false || mLoadingData == true ) + { + return( 0 ); + } + + uint start = line*mLayout.lineSize; + uint stop = start+mLayout.lineSize; + QColor bg = mColor.bookmarkBg; + QColor fg = mColor.bookmarkFg; + + int bookmarkPosition = 0; + + for( SCursorOffset *c=mBookmarkList.first(); c!=0; c=mBookmarkList.next() ) + { + if( c->offset >= start && c->offset < stop ) + { + int x = c->offset - start; + int x1 = mTextStart1 + x * mUnitWidth * mNumCell; + x1 += (x / mLayout.columnSize) * mSplitWidth; + int x2 = mTextStart2 + x * mUnitWidth; + + bookmarkPosition |= BookmarkOnLine; + + if( mShowBookmarkInEditor == false ) + { + continue; + } + + uint offset = line*mLayout.lineSize+x; + if( offset == mCursor.curr.offset ) + { + bookmarkPosition |= BookmarkOnCursor; + } + + if( mSelect.inside( offset ) || mMark.inside( offset ) ) + { + paint.fillRect( x1-startx, 2, mUnitWidth*mNumCell, mFontHeight-4, bg ); + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + paint.fillRect( x2-startx, 2, mUnitWidth, mFontHeight-4, bg ); + } + } + else + { + paint.fillRect( x1-startx, 1, mUnitWidth*mNumCell, mFontHeight-2, bg ); + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + paint.fillRect( x2-startx, 1, mUnitWidth, mFontHeight-2, bg ); + } + } + + unsigned char c = (data()[ line*mLayout.lineSize+x]); + + int flag = THIS_FPTR(printCell)( mPrintBuf, c ); + paint.setPen( flag == 0 ? fg : mColor.nonPrintFg ); + // ## paint.drawText( x1-startx, mFontAscent, mPrintBuf, mNumCell ); + paint.drawText( x1-startx, mFontAscent, + QString::fromLocal8Bit(mPrintBuf), mNumCell ); + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + flag = printAsciiCell( mPrintBuf, c ); + paint.setPen( flag == 0 ? fg : mColor.nonPrintFg ); + // ## paint.drawText( x2-startx, mFontAscent, mPrintBuf, 1 ); + paint.drawText( x2-startx, mFontAscent, + QString::fromLocal8Bit(mPrintBuf), 1 ); + } + } + } + + return bookmarkPosition; +} + + + +void CHexBuffer::drawCursor( QPainter &paint, uint line, int startx, + bool onBookmark ) +{ + if( documentPresent() == false || mLoadingData == true ) + { + return; + } + + SCursorSpec &c = mCursor.curr; + + // + // Draw the cursor in primary edit area. + // + QColor bg, fg; + bool useFg; + if( mMark.inside( c.offset ) == true ) + { + bg = mColor.markBg; + fg = mSelect.inside( c.offset ) ? mColor.selectFg : mColor.markFg; + useFg = true; + } + else if( mSelect.inside( c.offset ) == true ) + { + bg = mColor.selectBg; + fg = mColor.selectFg; + useFg = true; + } + else + { + bg = (line+1) % 2 ? mColor.textBg : mColor.secondTextBg; + fg = foregroundColor( c.offset % mLayout.lineSize ); + useFg = false; // Can be true later. + } + + QColor cbg = mColor.cursorBg; + QColor cfg = mColor.cursorFg; + + // + // Fill in the general backround color + // + paint.fillRect( c.x1 - startx, 0, mUnitWidth, mFontHeight, bg ); + if( onBookmark == true ) + { + int w = mUnitWidth * (mNumCell-c.cell); // Rest of cell + if( useFg == true ) + { + paint.fillRect( c.x1-startx, 2, w, mFontHeight-4, mColor.bookmarkBg ); + } + else + { + paint.fillRect( c.x1-startx, 1, w, mFontHeight-2, mColor.bookmarkBg ); + } + } + + // + // Draw the cursor shape + // + bool transparent = false; + if( mActiveEditor == edit_primary ) + { + if( mShowCursor == true ) // Cursor blink on + { + if( c.mPrimaryShape == SCursorSpec::thin ) + { + paint.setPen( cbg ); + int center = c.x1 - startx - 1; + transparent = true; + + if( c.thickState == true ) + { + paint.drawLine( center, 0, center, mFontHeight - 1 ); + paint.drawLine( center+1, 0, center+1, mFontHeight - 1 ); + } + else + { + paint.drawLine( center, 0, center, mFontHeight - 1 ); + paint.drawLine( center-2, 0, center+2, 0 ); + paint.drawLine( center-2, mFontHeight-1, center+2, mFontHeight-1 ); + } + } + else // Solid block shape + { + paint.fillRect( c.x1 - startx, 0, mUnitWidth, mFontHeight, cbg ); + useFg = true; + fg = cfg; + } + } + } + else + { + transparent = true; + paint.setPen( cbg ); + paint.drawRect( c.x1 - startx, 0, mUnitWidth*mNumCell, mFontHeight ); + } + + // + // Draw the text on the cursor position and to the end of the cell. + // + if( c.offset < documentSize() ) + { + int flag = THIS_FPTR(printCell)( mPrintBuf, (unsigned char)c.data ); + if( onBookmark == true ) + { + // Inside bookmark. Draw text with bookmark foreground. + paint.setPen( mColor.bookmarkFg ); + // ## paint.drawText( c.x1-startx, mFontAscent, &mPrintBuf[c.cell], + // mNumCell-c.cell ); + paint.drawText( c.x1-startx, mFontAscent, + QString::fromLocal8Bit(&mPrintBuf[c.cell]), + mNumCell-c.cell ); + } + + if( transparent == false || onBookmark == false ) + { + paint.setPen( flag == 0 || useFg == true ? fg : mColor.nonPrintFg ); + // ## paint.drawText( c.x1 - startx, mFontAscent, &mPrintBuf[c.cell], 1); + paint.drawText( c.x1 - startx, mFontAscent, + QString::fromLocal8Bit(&mPrintBuf[c.cell]), 1 ); + } + } + + // + // Draw the cursor in secodary edit area. + // + if( mLayout.secondaryMode == SDisplayLayout::hide ) + { + return; + } + + + if( mMark.inside( c.offset ) == true ) + { + bg = mColor.markBg; + fg = mSelect.inside( c.offset ) ? mColor.selectFg : mColor.markFg; + useFg = true; + } + else if( mSelect.inside( c.offset ) == true ) + { + bg = mColor.selectBg; + fg = mColor.selectFg; + useFg = true; + } + else + { + bg = (line+1) % 2 ? mColor.textBg : mColor.secondTextBg; + fg = mColor.secondaryFg; + useFg = false; // Can be true later. + } + + + + // + // Fill in the general backround color + // + if( onBookmark == true ) + { + if( useFg == true ) + { + paint.fillRect( c.x2-startx, 2, mUnitWidth, mFontHeight-4, + mColor.bookmarkBg ); + } + else + { + paint.fillRect( c.x2-startx, 1, mUnitWidth, mFontHeight-2, + mColor.bookmarkBg ); + } + } + else + { + paint.fillRect( c.x2 - startx, 0, mUnitWidth, mFontHeight, bg ); + } + + // + // Draw the cursor shape + // + transparent = false; + if( mActiveEditor == edit_secondary ) + { + if( mShowCursor == true ) // Cursor blink on + { + if( c.mSecondaryShape == SCursorSpec::thin ) + { + paint.setPen( cbg ); + int center = c.x2 - startx - 1; + transparent = true; + + if( c.thickState == true ) + { + paint.drawLine( center, 0, center, mFontHeight - 1 ); + paint.drawLine( center+1, 0, center+1, mFontHeight - 1 ); + } + else + { + paint.drawLine( center, 0, center, mFontHeight - 1 ); + paint.drawLine( center-2, 0, center+2, 0 ); + paint.drawLine( center-2, mFontHeight-1, center+2, mFontHeight-1 ); + } + } + else + { + paint.fillRect( c.x2 - startx, 0, mUnitWidth, mFontHeight, cbg ); + useFg = true; + fg = cfg; + } + } + } + else + { + transparent = true; + paint.setPen( cbg ); + paint.drawRect( c.x2 - startx, 0, mUnitWidth, mFontHeight ); + } + + // + // Draw the text on the cursor position and to the end of the cell. + // + if( c.offset < documentSize() ) + { + int flag = printAsciiCell( mPrintBuf, (unsigned char)c.data ); + if( onBookmark == true ) + { + // Inside bookmark. Draw text with bookmark foreground. + paint.setPen( flag == 0 ? mColor.bookmarkFg : mColor.nonPrintFg ); + // ## paint.drawText( c.x2-startx, mFontAscent, mPrintBuf, 1 ); + paint.drawText( c.x2-startx, mFontAscent, + QString::fromLocal8Bit(mPrintBuf), 1 ); + } + if( transparent == false || onBookmark == false ) + { + paint.setPen( flag == 0 || useFg == true ? fg : mColor.nonPrintFg ); + // ## paint.drawText( c.x2 - startx, mFontAscent, mPrintBuf, 1 ); + paint.drawText( c.x2 - startx, mFontAscent, + QString::fromLocal8Bit(mPrintBuf), 1 ); + } + } + +} + + + + +void CHexBuffer::cursorReset( void ) +{ + mCursor.reset(); + cursorCompute(); +} + +void CHexBuffer::cursorCompute( void ) +{ + mCursor.prev = mCursor.curr; + + if( mCursor.next.offset >= documentSize() ) + { + if( documentSize() == 0 ) + { + mCursor.curr.offset = 0; + mCursor.curr.data = 0; + mCursor.curr.cell = 0; + mCursor.curr.maxCell = mNumCell; + + int x = mCursor.curr.offset % mLayout.lineSize; + mCursor.curr.x1 = mTextStart1; + mCursor.curr.x1 += (x * mNumCell + mCursor.curr.cell) * mUnitWidth; + mCursor.curr.x1 += (x / mLayout.columnSize) * mSplitWidth; + mCursor.curr.x2 = mTextStart2 + x * mUnitWidth; + mCursor.curr.y = (mCursor.curr.offset/mLayout.lineSize) * + (mFontHeight+mLayout.horzGridWidth); + return; + + } + if( mFixedSizeMode == true ) + { + uint max = mMaximumSize - 1; + uint off = mCursor.curr.offset % mLayout.lineSize; + uint end = max % mLayout.lineSize; + if( off > end ) + { + uint diff = off - end; + if( max + diff > mLayout.lineSize ) + { + mCursor.next.offset = max + diff - mLayout.lineSize; + } + else + { + mCursor.next.offset = 0; + } + } + else + { + uint diff = end - off; + mCursor.next.offset = diff > max ? max : max - diff; + } + } + else + { + mCursor.next.offset = documentSize(); + } + } + + mCursor.curr.offset = mCursor.next.offset; + mCursor.curr.data = data()[ mCursor.curr.offset ]; + mCursor.curr.cell = mCursor.next.cell; + mCursor.curr.maxCell = mNumCell; + + int x = mCursor.curr.offset % mLayout.lineSize; + + mCursor.curr.x1 = mTextStart1; + mCursor.curr.x1 += (x * mNumCell + mCursor.curr.cell) * mUnitWidth; + mCursor.curr.x1 += (x / mLayout.columnSize) * mSplitWidth; + mCursor.curr.x2 = mTextStart2 + x * mUnitWidth; + mCursor.curr.y = (mCursor.curr.offset/mLayout.lineSize) * + (mFontHeight + mLayout.horzGridWidth); +} + + +bool CHexBuffer::setCursorPosition( int x, int y, bool init, bool cellLevel ) +{ + if( documentPresent() == false ) + { + return( false ); + } + + uint line = y < 0 ? 0 : y / lineHeight(); + uint entry = 0; + int bit = 7; + + if( init == false ) + { + if( mCursor.area() == edit_primary ) + { + int start = mTextStart1; + if( x < start - (int)mLayout.separatorMarginWidth ) + { + return( false ); + } + else + { + int stop = mTextStart1 + mPrimaryWidth + mLayout.separatorMarginWidth; + int width = mNumCell * mUnitWidth; + int space = mSplitWidth; + + for( int position = start, i=0; position < stop; i++ ) + { + if( x <= position + width ) + { + if( cellLevel == true ) + { + while( bit > 0 ) + { + if( x <= position + mUnitWidth ) + { + break; + } + bit -= mCursor.cellWeight(); + position += mUnitWidth; + } + } + break; + } + position += width + (((i+1) % mLayout.columnSize) ? 0 : space); + entry += 1; + } + } + } + else + { + int start = mTextStart2; + if( x < start - (int)mLayout.separatorMarginWidth || + mLayout.secondaryMode == SDisplayLayout::hide ) + { + return( false ); + } + int stop = mTextStart2 + mLayout.lineSize * mUnitWidth; + int width = mUnitWidth * 1; + int space = 0; + + for( int position = start; position < stop; ) + { + if( x <= position + width ) + { + break; + } + position += width + space; + entry += 1; + } + } + } + else + { + int start = mTextStart1; + int stop = start + mPrimaryWidth + mLayout.separatorMarginWidth; + if( x >= start - (int)mLayout.separatorMarginWidth && x <= stop ) + { + int width = mUnitWidth * mNumCell; + int space = mSplitWidth; + + for( int position = start, i=0; position < stop; i++ ) + { + if( x <= position + width ) + { + if( cellLevel == true ) + { + while( bit > 0 ) + { + if( x <= position + mUnitWidth ) + { + break; + } + bit -= mCursor.cellWeight(); + position += mUnitWidth; + } + } + break; + } + position += width + (((i+1) % mLayout.columnSize) ? 0 : space); + entry += 1; + } + + mActiveEditor = edit_primary; + } + else if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + start = mTextStart2; + stop = mTextStart2 + mLayout.lineSize * mUnitWidth + + mLayout.edgeMarginWidth; + if( x >= start - (int)mLayout.separatorMarginWidth && x <= stop ) + { + int width = mUnitWidth * 1; + int space = 0; + + for( int position = start; position < stop; ) + { + if( x <= position + width ) + { + break; + } + position += width + space; + entry += 1; + } + + mActiveEditor = edit_secondary; + } + } + else + { + return( false ); + } + } + + uint offset = line * mLayout.lineSize + entry; + if( offset > documentSize() ) + { + offset = documentSize(); + } + + mCursor.setOffset( offset ); + mCursor.setBit( bit < 0 ? 0 : bit ); + + cursorCompute(); + if( mActiveEditor != mCursor.area() ) + { + mCursor.setArea( mActiveEditor ); + setEditMode( mEditMode ); + } + + return( true ); +} + + + + +bool CHexBuffer::inputAtCursor( QChar c ) +{ + if( documentPresent() == false || mInputMode.noInput() == true ) + { + if( mInputMode.noInput() == true ) { inputSound(); } + return( false ); + } + + if( c.isPrint() == false ) + { + inputSound(); + return( false ); + } + + unsigned char dest; + bool insert; + if( mEditMode == EditReplace || mCursor.curr.cell > 0 ) + { + if( mCursor.curr.offset >= documentSize() ) + { + dest = 0; + insert = true; + } + else + { + dest = (unsigned char)data()[ mCursor.curr.offset ]; + insert = false; + } + } + else + { + dest = 0; + insert = true; + } + + if( insert == true && mInputMode.allowResize == false ) + { + inputSound(); + return( false ); + } + + if( mActiveEditor == edit_primary ) + { + // ## if( THIS_FPTR(inputCell)( &dest, c.latin1(), mCursor.curr.cell ) + //== false ) + if( THIS_FPTR(inputCell)( &dest, QString(c).local8Bit()[0], + mCursor.curr.cell ) == false ) + { + inputSound(); + return( false ); + } + } + else if( mActiveEditor == edit_secondary ) + { + // ## if( inputAscii( &dest, c.latin1(), mCursor.curr.cell ) == false ) + if( !inputAscii( &dest, QString(c).local8Bit()[0], mCursor.curr.cell ) ) + { + inputSound(); + return( false ); + } + } + else + { + return( false ); + } + + recordStart( mCursor ); + recordReplace( mCursor, insert == true ? 0 : 1, (char*)&dest, 1 ); + cursorRight( cursorPrimaryEdit() ); + recordEnd( mCursor ); + + computeNumLines(); + return( true ); +} + + + +int CHexBuffer::inputAtCursor( const QByteArray &buf, uint oldSize ) +{ + if( documentPresent() == false ) + { + return( Err_NoActiveDocument ); + } + if( buf.isNull() == true ) + { + return( Err_EmptyArgument ); + } + + if( mInputMode.noInput() == true ) + { + inputSound(); + return( Err_WriteProtect ); + } + + if( mInputMode.allowResize == false ) + { + inputSound(); + return( Err_NoResize ); + } + + recordStart( mCursor ); + recordReplace( mCursor, oldSize, (char*)&buf[0], buf.size() ); + cursorStep( buf.size(), true, false ); + recordEnd( mCursor ); + + computeNumLines(); + return( Err_Success ); +} + + +bool CHexBuffer::removeAtCursor( bool beforeCursor ) +{ + if( documentPresent() == false ) + { + return( false ); + } + + if( mInputMode.noInput() == true || mInputMode.allowResize == false ) + { + inputSound(); + return( false ); + } + + + if( mSelect.valid() == true ) + { + cutSelection(); + return( true ); + } + + + if( beforeCursor == true ) + { + if( mCursor.curr.offset == 0 ) + { + return( false ); + } + + recordStart( mCursor ); + cursorLeft( false ); + recordReplace( mCursor, 1, 0, 0 ); + recordEnd( mCursor ); + + computeNumLines(); + return( true ); + } + else + { + if( mCursor.curr.offset + 1 > documentSize() ) + { + return( false ); + } + + recordStart( mCursor ); + recordReplace( mCursor, 1, 0, 0 ); + recordEnd( mCursor ); + + computeNumLines(); + return( true ); + } +} + + + +int CHexBuffer::locateRange(const SExportRange &range, uint &start, uint &stop) +{ + if( range.mode == SExportRange::All ) + { + start = 0; + stop = documentSize(); + } + else if( range.mode == SExportRange::Selection ) + { + if( mSelect.valid() == false ) + { + return( Err_NoSelection ); + } + start = mSelect.curr.start; + stop = mSelect.curr.stop; + } + else if( range.mode == SExportRange::Range ) + { + start = range.start; + stop = range.stop; + } + else + { + return( Err_IllegalMode ); + } + + if( start >= stop ) + { + return( Err_IllegalRange ); + } + + return( Err_Success ); +} + + +int CHexBuffer::exportText( const SExportText &ex, CProgress &p ) +{ + uint start, stop; + int errCode = locateRange( ex.range, start, stop ); + if( errCode != Err_Success ) + { + p.finish(); + return( errCode ); + } + + QFile file( ex.destFile ); + if( file.open( IO_WriteOnly ) == false ) + { + p.finish(); + return( Err_OpenWriteFailed ); + } + + uint startLine = calculateLine( start ); + if( startLine >= (uint)numLines() ) + { + startLine = numLines() == 0 ? 0 : numLines() - 1; + } + + uint stopLine = calculateLine( stop ); + if( stopLine >= (uint)numLines() ) + { + stopLine = numLines() == 0 ? 0 : numLines() - 1; + } + + uint totalSize = stopLine - startLine + 1; + uint remaining = stopLine - startLine + 1; + uint bytePerLine = mOffsetSize + 1 + (mNumCell + 2)*mLayout.lineSize + 1; + uint linePerStep = 20; + + QByteArray array( bytePerLine * linePerStep + 1 ); // Line is 0 terminated + if( array.isEmpty() == true ) + { + p.finish(); + return( Err_NoMemory ); + } + + while( remaining > 0 ) + { + uint blockSize = remaining > linePerStep ? linePerStep : remaining; + uint printSize = 0; + + for( uint i = 0; i < blockSize; i++, startLine++ ) + { + printSize += printLine( &array[printSize], startLine ); + } + + int writeSize = file.writeBlock( &array[0], printSize ); + if( writeSize == -1 ) + { + p.finish(); + return( Err_WriteFailed ); + } + + remaining -= blockSize; + if( p.expired() == true ) + { + int errCode = p.step( (float)(totalSize-remaining)/(float)totalSize ); + if( errCode == Err_Stop && remaining > 0 ) + { + p.finish(); + return( Err_OperationAborted ); + } + } + } + + p.finish(); + return( Err_Success ); +} + + + +int CHexBuffer::exportHtml( const SExportHtml &ex, CProgress &p ) +{ + uint start, stop; + int errCode = locateRange( ex.range, start, stop ); + if( errCode != Err_Success ) + { + p.finish(); + return( errCode ); + } + + uint startLine = calculateLine( start ); + if( startLine >= (uint)numLines() ) + { + startLine = numLines() == 0 ? 0 : numLines() - 1; + } + + uint stopLine = calculateLine( stop ); + if( stopLine >= (uint)numLines() ) + { + stopLine = numLines() == 0 ? 0 : numLines() - 1; + } + + uint totalSize = stopLine - startLine + 1; + uint remaining = stopLine - startLine + 1; + + if( ex.linePerPage == 0 ) + { + p.finish(); + return( Err_IllegalArgument ); + } + + uint linePerPage = ex.linePerPage; + uint numFiles = remaining/linePerPage + (remaining%linePerPage ? 1 : 0); + uint fileCount = 0; + + QStringList fileNames, offsets; + QString name, offset; + for( uint i=0; i < numFiles; i++ ) + { + name.sprintf( "%08d.html", i+1 ); + fileNames.append( QString("%1/%2%3").arg(ex.package).arg(ex.prefix). + arg(name)); + } + name.sprintf( "%08d.html", 0 ); + QString tocName =QString("%1/%2%3").arg(ex.package).arg(ex.prefix).arg(name); + + QString linkName; + if( ex.symLink == true ) + { + linkName = QString("%1/%2").arg(ex.package).arg("index.html"); + } + + while( remaining > 0 ) + { + THIS_FPTR(printOffset)( mPrintBuf, startLine*mLayout.lineSize ); + mPrintBuf[mOffsetSize]=0; + offset.sprintf("[%s]", mPrintBuf ); + + uint pageSize = remaining > linePerPage ? linePerPage : remaining; + printHtmlDataPage( tocName, fileNames, fileCount, ex, startLine, pageSize); + + remaining -= pageSize; + startLine += pageSize; + fileCount += 1; + + THIS_FPTR(printOffset)( mPrintBuf, (startLine-1)*mLayout.lineSize ); + mPrintBuf[mOffsetSize]=0; + offset += QString(" %1 [%2]").arg(i18n("to")).arg(mPrintBuf); + offsets.append(offset); + + if( p.expired() == true ) + { + int errCode = p.step( (float)(totalSize-remaining)/(float)totalSize ); + if( errCode == Err_Stop && remaining > 0 ) + { + printHtmlTocPage( tocName, linkName, fileNames, offsets, fileCount ); + p.finish(); + return( Err_OperationAborted ); + } + } + } + + printHtmlTocPage( tocName, linkName, fileNames, offsets, fileCount ); + + p.finish(); + return( Err_Success ); +} + + +int CHexBuffer::exportCArray( const SExportCArray &ex, CProgress &p ) +{ + uint start, stop; + int errCode = locateRange( ex.range, start, stop ); + if( errCode != Err_Success ) + { + p.finish(); + return( errCode ); + } + + QFile file( ex.destFile ); + if( file.open( IO_WriteOnly ) == false ) + { + p.finish(); + return( Err_OpenWriteFailed ); + } + + uint startLine = calculateLine( start ); + if( startLine >= (uint)numLines() ) + { + startLine = numLines() == 0 ? 0 : numLines() - 1; + } + + uint stopLine = calculateLine( stop ); + if( stopLine >= (uint)numLines() ) + { + stopLine = numLines() == 0 ? 0 : numLines() - 1; + } + + uint elementSize = ex.elementSize(); + uint elementOnThisLine = 0; + + QTextStream dest( &file ); + + dest << ex.variableName(stop-start).latin1() << "={" << endl; + for( unsigned int i=start; i<stop; i+=elementSize ) + { + dest << ex.printFormatted( (const char*)&data()[i], stop-i ); + if( i + elementSize < stop ) + { + dest << ","; + } + + if( ++elementOnThisLine >= ex.elementPerLine ) + { + dest << endl; + elementOnThisLine = 0; + } + + if( p.expired() == true ) + { + int errCode = p.step( (float)(i-start)/(float)(stop-start) ); + if( errCode == Err_Stop && (i+elementSize) < stop) + { + p.finish(); + return( Err_OperationAborted ); + } + } + } + dest << "};" << endl; + + p.finish(); + return( Err_Success ); +} + + + + + + + +int CHexBuffer::copySelectedText( QByteArray &array, int columnSegment ) +{ + SExportRange range; + range.mode = SExportRange::Selection; + return( copyText( array, range, columnSegment ) ); +} + + +int CHexBuffer::copyAllText( QByteArray &array ) +{ + SExportRange range; + range.mode = SExportRange::All; + return( copyText( array, range, VisibleColumn ) ); +} + + +int CHexBuffer::copyText( QByteArray &array, const SExportRange &range, + int columnSegment ) +{ + uint start, stop; + int errCode = locateRange( range, start, stop ); + if( errCode != Err_Success ) + { + return( errCode ); + } + + uint startLine = calculateLine( start ); + uint stopLine = calculateLine( stop ); + if( startLine >= (uint)numLines() ) + { + startLine = numLines() == 0 ? 0 : numLines() - 1; + } + if( stopLine >= (uint)numLines() ) + { + stopLine = numLines() == 0 ? 0 : numLines() - 1; + } + + uint bytePerLine = mOffsetSize + 1 + (mNumCell + 2)*mLayout.lineSize + 1; + uint size = (stopLine - startLine + 1)*bytePerLine; + if( array.resize( size+1 ) == false ) + { + return( Err_NoMemory ); + } + + if( columnSegment == VisibleColumn ) + { + columnSegment = PrimaryColumn; // Always visible + if( mLayout.offsetVisible == true ) + { + columnSegment |= OffsetColumn; + } + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + columnSegment |= SecondaryColumn; + } + } + + uint offset = 0; + for( uint i = startLine; i <= stopLine; i++ ) + { + offset += printLine( &array[offset], i, columnSegment ); + } + array[size] = 0; + + return( Err_Success ); +} + + +int CHexBuffer::copySelectedData( QByteArray &array ) +{ + uint start = mSelect.start(); + uint stop = mSelect.stop(); + + if( mSelect.valid() == false || start >= stop ) + { + return( Err_IllegalRange ); + } + + uint size = stop - start; + if( array.resize( size ) == false ) + { + return( Err_NoMemory ); + } + + //unsigned char *src = (unsigned char*)data(); + //char *dst = (char*)array.data(); + + memcpy( &array[0], &data()[start], size ); + return( Err_Success ); +} + + +uint CHexBuffer::numPage( CHexPrinter &printer ) +{ + QPainter paint( &printer ); + paint.setFont( font() ); + + SPageMargin margin = printer.pageMargin(); + SPageSize size = printer.pageUsableSize(); + int headHeight, footHeight, headMargin, footMargin, freeHeight; + + headHeight = footHeight = headMargin = footMargin = 0; + if( printer.pageHeader().enable == true ) + { + headHeight = headerHeight( paint ); + headMargin = headerMargin( paint ); + } + if( printer.pageFooter().enable == true ) + { + footHeight = headerHeight( paint ); + footMargin = headerMargin( paint ); + } + freeHeight = size.height - headHeight - footHeight - headMargin - footMargin; + + float scale = 1.0; + if( (uint)mLineWidth > size.width ) + { + scale = (float)size.width / (float)mLineWidth; + } + uint linePerPage = (uint) ((float)freeHeight/((float)lineHeight()*scale)); + + uint remaining = numLines(); + + return( remaining / linePerPage + (remaining % linePerPage ? 1 : 0) ); +} + + + +int CHexBuffer::print( CHexPrinter &printer, CProgress &p ) +{ + printer.setDocName( mUrl ); + + QPainter paint( &printer ); + paint.setFont( font() ); + + SPageMargin margin = printer.pageMargin(); + SPageSize size = printer.pageUsableSize(); + paint.setClipRect( margin.left, margin.top, size.width, size.height ); + + //printf("%d,%d,%d,%d\n", margin.left, margin.top, size.width, size.height ); + + int headHeight, footHeight, headMargin, footMargin, freeHeight; + + headHeight = footHeight = headMargin = footMargin = 0; + if( printer.pageHeader().enable == true ) + { + headHeight = headerHeight( paint ); + headMargin = headerMargin( paint ); + } + if( printer.pageFooter().enable == true ) + { + footHeight = headerHeight( paint ); + footMargin = headerMargin( paint ); + } + freeHeight = size.height - headHeight - footHeight - headMargin - footMargin; + + float scale = 1.0; + if( (uint)mLineWidth > size.width ) + { + scale = (float)size.width / (float)mLineWidth; + paint.scale( scale, scale ); + } + + uint linePerPage = (uint) ((float)freeHeight/((float)lineHeight()*scale)); + uint sx = (uint) ((float)margin.left/scale); + uint sy = (uint) ((float)(margin.top+headHeight+headMargin)/scale); + + uint remaining = numLines(); + uint line = 0; + + #ifdef PRINTER_TEST + remaining = remaining > linePerPage * 10 ? linePerPage * 10 : remaining; + #endif + + + SPagePosition pageData( time(0), remaining, linePerPage ); + while( remaining > 0 ) + { + uint lineInPage = remaining > linePerPage ? linePerPage : remaining; + uint y = sy; + + // + // Draw header and footer. Reset scaling during that operation. + // + paint.scale( 1.0/scale, 1.0/scale ); + if( printer.pageHeader().enable == true ) + { + drawHeader( paint, margin.left, size.width, margin.top, false, + printer.pageHeader(), pageData ); + } + if( printer.pageFooter().enable == true ) + { + drawHeader( paint, margin.left, size.width, + margin.top+size.height-footHeight, true, + printer.pageFooter(), pageData ); + } + paint.scale( scale, scale ); + + // + // Draw actual data + // + for( uint i=0; i < lineInPage; i++, line++ ) + { + drawText( paint, line, sx, mLineWidth, y, false/*printer.printBlackWhite()*/ ); + y += lineHeight();// - mLayout.horzGridWidth; // FIXME not really nice :) + + if( p.expired() == true ) + { + int errCode = p.step( pageData.current(), pageData.max() ); + if( errCode == Err_Stop ) + { + p.finish(); + return( Err_Success ); // Success here, even if we cancel + } + } + } + + if( p.expired() == true ) + { + int errCode = p.step( pageData.current(), pageData.max() ); + if( errCode == Err_Stop ) + { + p.finish(); + return( Err_Success );// Success here, even if we cancel + } + } + + remaining -= lineInPage; + if( remaining > 0 ) + { + printer.newPage(); + } + + pageData.step(); + } + + p.finish(); + return( Err_Success ); +} + + + + + +uint CHexBuffer::printLine( char *dst, uint line ) +{ + uint offset = line * mLayout.lineSize; + unsigned char *src; + char *start = dst; + + uint dataSize; + if( offset >= documentSize() ) + { + src = 0; + dataSize = 0; + } + else + { + src = (unsigned char*)&data()[ offset ]; + dataSize = documentSize() - offset; + } + + if( mLayout.offsetVisible == true ) + { + THIS_FPTR(printOffset)( dst, offset ); dst += mOffsetSize; + sprintf( dst, " " ); dst += 1; + } + for( uint i=0; i < mLayout.lineSize; i++ ) + { + if( i<dataSize ) + { + THIS_FPTR(printCell)( dst, src[i] ); dst += mNumCell; + } + else + { + memset( dst, ' ', mNumCell ); dst += mNumCell; + } + if( mSplitWidth != 0 ) + { + sprintf( dst, " " ); dst += 1; + } + } + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + for( uint i=0; i < mLayout.lineSize; i++ ) + { + if( i < dataSize ) + { + printAsciiCell( dst, src[i] ); dst += 1; + } + else + { + memset( dst, ' ', 1 ); dst += 1; + } + } + } + sprintf( dst, "\n" ); dst += 1; + return( (uint)(dst-start) ); +} + + +uint CHexBuffer::printLine( char *dst, uint line, int columnSegment ) +{ + uint offset = line * mLayout.lineSize; + unsigned char *src; + char *start = dst; + + uint dataSize; + if( offset >= documentSize() ) + { + src = 0; + dataSize = 0; + } + else + { + src = (unsigned char*)&data()[ offset ]; + dataSize = documentSize() - offset; + } + + if( columnSegment & OffsetColumn ) + { + THIS_FPTR(printOffset)( dst, offset ); dst += mOffsetSize; + sprintf( dst, " " ); dst += 1; + } + + if( columnSegment & PrimaryColumn ) + { + for( uint i=0; i < mLayout.lineSize; i++ ) + { + if( i<dataSize ) + { + THIS_FPTR(printCell)( dst, src[i] ); dst += mNumCell; + } + else + { + memset( dst, ' ', mNumCell ); dst += mNumCell; + } + if( mSplitWidth != 0 ) + { + sprintf( dst, " " ); dst += 1; + } + } + } + + if( columnSegment & SecondaryColumn ) + { + for( uint i=0; i < mLayout.lineSize; i++ ) + { + if( i < dataSize ) + { + printAsciiCell( dst, src[i] ); dst += 1; + } + else + { + memset( dst, ' ', 1 ); dst += 1; + } + } + } + + sprintf( dst, "\n" ); dst += 1; + return( (uint)(dst-start) ); +} + + + + + + + + + + + +bool CHexBuffer::cutSelection( void ) +{ + if( documentPresent() == false || mSelect.size() == 0 ) + { + return( false ); + } + + if( mInputMode.noInput() == true || mInputMode.allowResize == false ) + { + inputSound(); + return( false ); + } + + recordStart( mCursor ); + cursorGoto( mSelect.start(), 0 ); + recordReplace( mCursor, mSelect.size(), 0, 0 ); + recordEnd( mCursor ); + + mSelect.reset(); + + computeNumLines(); + return( true ); +} + + + +bool CHexBuffer::undo( void ) +{ + if( documentPresent() == false || mUndoIndex == 0 || + mInputMode.noInput() == true ) + { + if( mInputMode.noInput() == true ) { inputSound(); } + return( false ); + } + + CHexActionGroup *group = mUndoList.at( mUndoIndex-1 ); + if( group == 0 ) + { + return( false ); + } + + mUndoIndex -= 1; + doActionGroup( group ); + + cursorGoto( group->mStartOffset, group->mStartBit ); + + return( true ); +} + + +bool CHexBuffer::redo( void ) +{ + if( documentPresent() == false || mUndoIndex >= mUndoList.count() || + mInputMode.noInput() == true ) + { + if( mInputMode.noInput() == true ) { inputSound(); } + return( false ); + } + + CHexActionGroup *group = mUndoList.at( mUndoIndex ); + if( group == 0 ) + { + return( false ); + } + + mUndoIndex += 1; + doActionGroup( group ); + + cursorGoto( group->mStopOffset, group->mStopBit ); + + return( true ); +} + + +int CHexBuffer::addBookmark( int position ) +{ + if( documentPresent() == false ) + { + return( Err_NoData ); + } + + if( mBookmarkList.count() >= 9 && position == -1 ) + { + return( Err_ListFull ); + } + + SCursorOffset *co = new SCursorOffset; + if( co == 0 ) + { + fatalSound(); + return( Err_NoMemory ); + } + + co->offset = mCursor.curr.offset; + co->bit = mCursor.bit(); + + if( position == -1 || position > (int)mBookmarkList.count() ) + { + mBookmarkList.append( co ); + } + else + { + mBookmarkList.remove( (uint)position ); + mBookmarkList.insert( (uint)position, co ); + } + + updateBookmarkMap(false); + return( Err_Success ); +} + + +bool CHexBuffer::removeBookmark( int position ) +{ + if( position < 0 ) + { + if( mBookmarkList.count() == 0 ) + { + return( false ); + } + mBookmarkList.clear(); + } + else + { + if( (uint)position >= mBookmarkList.count() ) + { + return( false ); + } + mBookmarkList.remove( position ); + } + + updateBookmarkMap(false); + return( true ); +} + + +void CHexBuffer::updateBookmarkMap( bool resize ) +{ + if( resize == true ) + { + mBookmarkMap.resize( documentSize()/200 + 3 ); + } + mBookmarkMap.fill(0); + + int bookmarkMapSize = mBookmarkMap.size(); + for( SCursorOffset *c=mBookmarkList.first(); c!=0; c=mBookmarkList.next() ) + { + int bookmarkOffset = c->offset / 200; + if( bookmarkOffset < bookmarkMapSize ) + { + // + // Espen 2000-05-16: + // I do this test to avoid some Qt warnings when I have closed + // or reduced the size of the documnet while the (now invalid) + // bookmarks still exist. + // + mBookmarkMap.setBit(bookmarkOffset); + } + } +} + + +int CHexBuffer::findFirst( SSearchControl &sc ) +{ + mMark.reset(); + int errCode = scanData( sc, true ); + return( errCode ); +} + +int CHexBuffer::findNext( SSearchControl &sc ) +{ + sc.fromCursor = true; + int errCode = scanData( sc, false ); + return( errCode ); +} + +int CHexBuffer::findWrap( SSearchControl &sc ) +{ + if( sc.wrapValid == false ) + { + return( Err_NoMatch ); + } + sc.wrapValid = false; + + sc.fromCursor = false; + sc.wrapActive = true; + int errCode = scanData( sc, false ); + sc.fromCursor = true; + return( errCode ); +} + + + + +int CHexBuffer::replaceAll( SSearchControl &sc, bool init ) +{ + if( init == true ) + { + initScanData( sc ); + } + + if( sc.key.isEmpty() == true ) + { + return( Err_EmptyArgument ); + } + + if( documentSize() == 0 ) + { + return( Err_EmptyDocument ); + } + + uint head, tail; + if( sc.inSelection == true ) + { + if( mSelect.valid() == false ) + { + return( Err_NoSelection ); + } + + head = mSelect.start(); + tail = mSelect.stop(); + } + else + { + head = 0; + tail = documentSize(); + } + + uint start, stop; + if( sc.fromCursor == false ) + { + if( sc.wrapActive == true ) + { + start = sc.forward == true ? head : sc.wrapMark; + stop = sc.forward == true ? sc.wrapMark+sc.key.size() : tail; + } + else + { + start = head; + stop = tail; + } + } + else if( sc.forward == true ) + { + start = cursorOffset() < head ? head : cursorOffset(); + stop = sc.wrapActive == true ? sc.wrapMark+sc.key.size() : tail; + } + else + { + start = sc.wrapActive == true ? sc.wrapMark : head; + stop = cursorOffset() > tail ? tail : cursorOffset(); + } + + if( sc.forward == true && start + sc.key.size() > stop ) + { + // + // When searching backwards "stop" is the last offset from where + // we do a memcmp() upward in memory. An overflow for that + // situation is taken care of below. + // + return( Err_NoMatch ); + } + + if( stop + sc.key.size() > tail ) + { + uint diff = stop + sc.key.size() - tail; + stop = stop > diff ? stop - diff : 0; + } + + if( mInputMode.noInput() == true ) + { + inputSound(); + return( Err_WriteProtect ); + } + + recordStart( mCursor ); + uint numReplaced = 0; + + if( sc.forward == true ) + { + for( uint i = start; i <= stop ; ) + { + if( memcmp( &data()[i], sc.key.data(), sc.key.size() ) != 0 ) + { + i++; + } + else + { + cursorGoto( i, 7 ); + recordReplace( mCursor, sc.key.size(), sc.val.data(), sc.val.size() ); + numReplaced += 1; + + if( sc.inSelection == true ) + { + if( sc.key.size() > sc.val.size() ) + { + mSelect.shrink( sc.key.size() - sc.val.size() ); + } + else + { + mSelect.expand( sc.val.size() - sc.key.size() ); + } + } + + if( sc.key.size() > sc.val.size() ) + { + uint diff = sc.key.size() - sc.val.size(); + stop -= QMIN( stop, diff ); + } + else if( sc.key.size() < sc.val.size() ) + { + stop += sc.val.size() - sc.key.size(); + } + + i += sc.val.size(); + cursorStep( sc.val.size(), true, false ); + } + } + } + else + { + for( uint i = stop; i >= start; ) + { + if( memcmp( &data()[i], sc.key.data(), sc.key.size() ) != 0 ) + { + if( i == 0 ) { break; } + i--; + } + else + { + cursorGoto( i, 7 ); + recordReplace( mCursor, sc.key.size(), sc.val.data(), sc.val.size() ); + numReplaced += 1; + + if( sc.inSelection == true ) + { + if( sc.key.size() > sc.val.size() ) + { + mSelect.shrink( sc.key.size() - sc.val.size() ); + } + else + { + mSelect.expand( sc.val.size() - sc.key.size() ); + } + } + + i -= QMIN( i, sc.key.size() ); + if( i == 0 ) { break; } + } + } + } + + recordEnd( mCursor ); + computeNumLines(); + + if( numReplaced == 0 ) + { + return( Err_NoMatch ); + } + + sc.numReplace += numReplaced; + sc.match = true; + mMark.reset(); + + return( Err_Success ); +} + + +int CHexBuffer::replaceMarked( SSearchControl &sc ) +{ + if( documentSize() == 0 ) + { + return( Err_EmptyDocument ); + } + + if( mMark.valid() == false ) + { + return( Err_NoMark ); + } + + bool inSelection; + if( mSelect.valid() == true ) + { + if( mMark.start() >= mSelect.start() && mMark.stop() <= mSelect.stop() ) + { + inSelection = true; + } + else + { + inSelection = false; + } + } + else + { + inSelection = false; + } + + if( mInputMode.noInput() == true ) + { + inputSound(); + return( Err_WriteProtect ); + } + + recordStart( mCursor ); + cursorGoto( mMark.start(), 7 ); + recordReplace( mCursor, mMark.size(), sc.val.data(), sc.val.size() ); + sc.numReplace += 1; + + if( inSelection == true ) + { + if( mMark.size() > sc.val.size() ) + { + mSelect.shrink( mMark.size() - sc.val.size() ); + } + else + { + sc.wrapMark += sc.val.size() - mMark.size(); + mSelect.expand( sc.val.size() - mMark.size() ); + } + } + + + if( sc.wrapActive == false ) + { + if( sc.forward == false ) + { + sc.wrapMark += mMark.size() > sc.val.size() ? + mMark.size() - sc.val.size() : sc.val.size() - mMark.size(); + } + } + + + recordEnd( mCursor ); + computeNumLines(); + + if( sc.forward == true ) + { + // + // We must step over the area we have just altered. This is + // vital if the search key contains a pattern that exists in + // the replace data buffer. + // + cursorStep( sc.val.size(), true, false ); + } + mMark.reset(); + return( Err_Success ); +} + + +#if 0 + +int CHexBuffer::replaceAll( SSearchControl &sc, bool init ) +{ + if( init == true ) + { + initScanData( sc ); + } + + if( sc.key.isEmpty() == true ) + { + return( Err_EmptyArgument ); + } + + if( documentSize() == 0 ) + { + return( Err_EmptyDocument ); + } + + uint head, tail; + if( sc.inSelection == true ) + { + if( mSelect.valid() == false ) + { + return( Err_NoSelection ); + } + + head = mSelect.start(); + tail = mSelect.stop(); + } + else + { + head = 0; + tail = documentSize(); + } + + uint start, stop; + if( sc.fromCursor == false ) + { + if( sc.wrapActive == true ) + { + start = sc.forward == true ? head : sc.wrapMark; + stop = sc.forward == true ? sc.wrapMark : tail; + } + else + { + start = head; + stop = tail; + } + } + else if( sc.forward == true ) + { + start = cursorOffset() < head ? head : cursorOffset(); + stop = sc.wrapActive == true ? sc.wrapMark : tail; + } + else + { + start = sc.wrapActive == true ? sc.wrapMark : head; + stop = cursorOffset() > tail ? tail : cursorOffset(); + } + + + if( start + sc.key.size() > stop ) + { + return( Err_NoMatch ); + } + + if( stop + sc.key.size() > tail ) + { + uint diff = stop + sc.key.size() - tail; + stop = stop > diff ? stop - diff : 0; + } + + if( mInputMode.noInput() == true ) + { + inputSound(); + return( Err_WriteProtect ); + } + + recordStart( mCursor ); + uint numReplaced = 0; + + if( sc.forward == true ) + { + for( uint i = start; i <= stop; i++ ) + { + if( memcmp( &data()[i], sc.key.data(), sc.key.size() ) == 0 ) + { + cursorGoto( i, 7 ); + recordReplace( mCursor, sc.key.size(), sc.val.data(), sc.val.size() ); + numReplaced += 1; + + if( sc.inSelection == true ) + { + if( sc.key.size() > sc.val.size() ) + { + mSelect.shrink( sc.key.size() - sc.val.size() ); + } + else + { + mSelect.expand( sc.val.size() - sc.key.size() ); + } + } + + if( sc.key.size() > sc.key.size() ) + { + uint diff = sc.key.size() - sc.val.size(); + i += diff - 1; + } + else if( sc.key.size() < sc.val.size() ) + { + uint diff = sc.val.size() - sc.key.size(); + stop += diff; + } + else + { + i += sc.val.size() - 1; + } + cursorStep( sc.val.size(), true, false ); + } + } + } + else + { + for( uint i = stop; i >= start; i-- ) + { + if( memcmp( &data()[i], sc.key.data(), sc.key.size() ) == 0 ) + { + cursorGoto( i, 7 ); + recordReplace( mCursor, sc.key.size(), sc.val.data(), sc.val.size() ); + numReplaced += 1; + + if( sc.inSelection == true ) + { + if( sc.key.size() > sc.val.size() ) + { + mSelect.shrink( sc.key.size() - sc.val.size() ); + } + else + { + mSelect.expand( sc.val.size() - sc.key.size() ); + } + } + + } + if( i == 0 ) { break; } + } + } + + recordEnd( mCursor ); + computeNumLines(); + + if( numReplaced == 0 ) + { + return( Err_NoMatch ); + } + + sc.numReplace += numReplaced; + sc.match = true; + mMark.reset(); + + return( Err_Success ); +} + + +int CHexBuffer::replaceMarked( SSearchControl &sc ) +{ + if( documentSize() == 0 ) + { + return( Err_EmptyDocument ); + } + + if( mMark.valid() == false ) + { + return( Err_NoMark ); + } + + bool inSelection; + if( mSelect.valid() == false ) + { + if( mMark.start() >= mSelect.start() && mMark.stop() <= mSelect.stop() ) + { + inSelection = true; + } + else + { + inSelection = false; + } + } + else + { + inSelection = false; + } + + if( mInputMode.noInput() == true ) + { + inputSound(); + return( Err_WriteProtect ); + } + + recordStart( mCursor ); + cursorGoto( mMark.start(), 7 ); + recordReplace( mCursor, mMark.size(), sc.val.data(), sc.val.size() ); + sc.numReplace += 1; + + if( inSelection == true ) + { + if( mMark.size() > sc.val.size() ) + { + mSelect.shrink( mMark.size() - sc.val.size() ); + } + else + { + mSelect.expand( sc.val.size() - mMark.size() ); + } + } + + recordEnd( mCursor ); + computeNumLines(); + mMark.reset(); + + return( Err_Success ); +} + +#endif + + +int CHexBuffer::initScanData( SSearchControl &sc ) +{ + sc.wrapValid = false; + sc.wrapActive = false; + sc.wrapMark = 0; + sc.match = false; + sc.numReplace = 0; + + uint head, tail; + if( sc.inSelection == true ) + { + if( mSelect.valid() == false ) + { + return( Err_NoSelection ); + } + + head = mSelect.start(); + tail = mSelect.stop(); + } + else + { + head = 0; + tail = documentSize(); + } + + if( sc.fromCursor == false ) + { + sc.wrapValid = false; + sc.wrapActive = false; + sc.wrapMark = 0; + } + else if( sc.forward == true ) + { + if( cursorOffset() > tail ) + { + sc.wrapValid = true; + sc.wrapActive = false; + sc.wrapMark = tail; + } + else if( cursorOffset() <= head ) + { + sc.wrapValid = false; + sc.wrapActive = false; + sc.wrapMark = 0; + } + else + { + sc.wrapValid = true; + sc.wrapActive = false; + sc.wrapMark = cursorOffset(); + } + } + else + { + if( cursorOffset() >= tail ) + { + sc.wrapValid = false; + sc.wrapActive = false; + sc.wrapMark = 0; + } + else if( cursorOffset() < head ) + { + sc.wrapValid = true; + sc.wrapActive = false; + sc.wrapMark = head; + } + else + { + sc.wrapValid = true; + sc.wrapActive = false; + sc.wrapMark = cursorOffset(); + } + } + + return( Err_Success ); +} + + + +int CHexBuffer::scanData( SSearchControl &sc, bool init ) +{ + if( init == true ) + { + int errCode = initScanData( sc ); + if( errCode != Err_Success ) + { + return( errCode ); + } + } + + if( sc.key.isEmpty() == true ) + { + return( Err_EmptyArgument ); + } + + if( documentSize() == 0 ) + { + return( Err_EmptyDocument ); + } + + uint head, tail; + if( sc.inSelection == true ) + { + if( mSelect.valid() == false ) + { + return( Err_NoSelection ); + } + + head = mSelect.start(); + tail = mSelect.stop(); + } + else + { + head = 0; + tail = documentSize(); + } + + uint start, stop; + if( sc.fromCursor == false ) + { + if( sc.wrapActive == true ) + { + start = sc.forward == true ? head : sc.wrapMark; + stop = sc.forward == true ? sc.wrapMark+sc.key.size() : tail; + } + else + { + start = head; + stop = tail; + } + } + else if( sc.forward == true ) + { + start = cursorOffset() < head ? head : cursorOffset(); + stop = sc.wrapActive == true ? sc.wrapMark : tail; + } + else + { + start = sc.wrapActive == true ? sc.wrapMark : head; + stop = cursorOffset() > tail ? tail : cursorOffset(); + } + + if( sc.forward == true && start + sc.key.size() > stop ) + { + // + // When searching backwards "stop" is the last offset from where + // we do a memcmp() upward in memory. An overflow for that + // situation is taken care of below. + // + return( stop + sc.key.size() < tail ? Err_WrapBuffer : Err_NoData ); + } + + if( stop + sc.key.size() > tail ) + { + uint diff = stop + sc.key.size() - tail; + stop = stop > diff ? stop - diff : 0; + } + + if( sc.forward == true ) + { + for( uint i = start; i <= stop; i++ ) + { + int result; + if( sc.ignoreCase == true ) + { + result = strncasecmp( &data()[i], sc.key.data(), sc.key.size() ); + } + else + { + result = memcmp( &data()[i], sc.key.data(), sc.key.size() ); + } + if( result == 0 ) + { + if( i != cursorOffset() || mMark.size() != sc.key.size() ) + { + sc.match = true; + cursorGoto( i, 7 ); + markSet( i, sc.key.size() ); + return( Err_Success ); + } + } + } + return( start > head ? Err_WrapBuffer : Err_NoData ); + } + else + { + for( uint i = stop; i >= start; i-- ) + { + int result; + if( sc.ignoreCase == true ) + { + result = strncasecmp( &data()[i], sc.key.data(), sc.key.size() ); + } + else + { + result = memcmp( &data()[i], sc.key.data(), sc.key.size() ); + } + if( result == 0 ) + { + if( i != cursorOffset() || mMark.size() != sc.key.size() ) + { + sc.match = true; + cursorGoto( i, 7 ); + markSet( i, sc.key.size() ); + return( Err_Success ); + } + } + if( i == 0 ) { break; } + } + + return( stop + sc.key.size() <= tail ? Err_WrapBuffer : Err_NoData ); + } +} + + + + + +int CHexBuffer::filter( SFilterControl &fc ) +{ + uint head, tail; + if( fc.inSelection == true ) + { + if( mSelect.valid() == false ) + { + return( Err_NoSelection ); + } + + head = mSelect.start(); + tail = mSelect.stop(); + } + else + { + head = 0; + tail = documentSize(); + } + + uint start, stop; + if( fc.fromCursor == false ) + { + start = head; + stop = tail; + } + else if( fc.forward == true ) + { + start = cursorOffset() < head ? head : cursorOffset(); + stop = tail; + } + else + { + start = head; + stop = cursorOffset() > tail ? tail : cursorOffset(); + } + + if( mInputMode.noInput() == true ) + { + inputSound(); + return( Err_WriteProtect ); + } + + if( start >= stop ) { return( Err_IllegalRange ); } + QByteArray buf( stop - start ); + if( buf.isEmpty() == true ) { return( Err_NoMemory ); } + + int errCode = fc.execute((uchar*)&buf[0],(uchar*)&data()[start],buf.size()); + if( errCode == Err_Success ) + { + recordStart( mCursor ); + cursorGoto( start, 7 ); + recordReplace( mCursor, buf.size(), buf.data(), buf.size() ); + recordEnd( mCursor ); + } + + return( errCode ); +} + + + +int CHexBuffer::collectStrings( CStringCollectControl &sc ) +{ + uint startOffset = 0; + uint start, i; + bool on = false; + + if( sc.minLength < 1 ) { sc.minLength = 1; } + + start = startOffset; + for( i = startOffset; i<documentSize(); i++ ) + { + unsigned char item = data()[i]; + if( isprint( item ) == 0 || item >= 128 ) + { + if( on == true && i-start >= sc.minLength ) + { + QByteArray a( i-start ); + for( uint j=0; j<(i-start); a[j]=data()[start+j], j++ ); + sc.add( start, a ); + } + on = false; + } + else + { + if( on == false ) { start = i; } + on = true; + } + } + + if( on == true && i-start >= sc.minLength ) + { + QByteArray a( i-start ); + for( uint j=0; j<(i-start); a[j]=data()[start+j], j++ ); + sc.add( start, a ); + } + + return( Err_Success ); +} + + +int CHexBuffer::collectStatistic( SStatisticControl &sc, CProgress &p ) +{ + sc.documentSize = documentSize(); + sc.documentName = mUrl; + + for( uint i = 0; i<documentSize(); i++ ) + { + sc.occurrence[ (unsigned char)data()[i] ] += 1; + + // + // The expired() function introduces too much overhead in this case + // so it is only executed every 100'th character + // + if( i % 100 == 0 && p.expired() == true ) + { + int errCode = p.step( (float)i/(float)documentSize() ); + if( errCode == Err_Stop && i+1 < documentSize() ) + { + p.finish(); + return( Err_OperationAborted ); + } + } + } + p.finish(); + return( Err_NoErr ); +} + + +void CHexBuffer::doActionGroup( CHexActionGroup *group ) +{ + if( group == 0 ) + { + return; + } + + CHexAction *action = group->mHexAction; + group->mHexAction = 0; + + while( action != 0 ) + { + doAction( action ); + CHexAction *next = action->mNext; + group->insertAction( action ); + action = next; + } + + computeNumLines(); +} + + +void CHexBuffer::doAction( CHexAction *action ) +{ + if( action->mAction == CHexAction::replace ) + { + doReplace( action, true ); + } +} + + + + + +void CHexBuffer::recordStart( SCursor &cursor ) +{ + // + // Step 1: Remove any undo element that is more recent than the + // current undo index + // + while( mUndoList.count() > mUndoIndex ) + { + mUndoList.removeLast(); + } + + // + // Step 2: Make sure the undo list is no larger than the undo limit. + // We remove the oldest elements in the list. + // + while( mUndoList.count() >= mUndoLimit ) + { + mUndoList.removeFirst(); + mUndoIndex -= 1; + } + + CHexActionGroup *group = new CHexActionGroup( cursor.curr.offset, + cursor.bit() ); + if( group == 0 ) + { + return; + } + + mUndoList.append( group ); + mUndoIndex += 1; +} + + +void CHexBuffer::recordReplace( SCursor &cursor, uint size, char *data1, + uint data1Size ) +{ + CHexAction *hexAction = new CHexAction( CHexAction::replace, + cursor.curr.offset ); + if( hexAction == 0 ) + { + return; + } + + hexAction->mSize = size; + hexAction->mData = data1; + hexAction->mDataSize = data1Size; + + doReplace( hexAction, false ); + mUndoList.getLast()->insertAction( hexAction ); + + if( mCursor.curr.offset < documentSize() ) + { + mCursor.curr.data = data()[ mCursor.curr.offset ]; + } + +} + +void CHexBuffer::recordEnd( SCursor &cursor ) +{ + mUndoList.getLast()->mStopOffset = cursor.curr.offset; + mUndoList.getLast()->mStopBit = cursor.bit(); +} + + +// +// This method is the only place where the doucument data can be changed. +// +void CHexBuffer::doReplace( CHexAction *hexAction, bool removeData ) +{ + uint offset = hexAction->mOffset; + uint oldSize = hexAction->mSize; + char *newData = hexAction->mData; + uint newSize = hexAction->mDataSize; + + hexAction->setData( newSize, &data()[offset], oldSize ); + + // + // Input new data. Resize buffer first if necessary. We always mark the + // data as changed (dirty) when the buffer is resized, otherwise only + // when the new data differ from the current. Nice feature :-) + // + int errCode; + if( newSize > oldSize ) + { + errCode = moveBuffer( offset + newSize - oldSize, offset ); + mDocumentModified = true; + } + else if( newSize < oldSize ) + { + errCode = moveBuffer( offset, offset + oldSize - newSize ); + mDocumentModified = true; + } + else + { + errCode = Err_Success; + if( memcmp( &data()[offset], newData, newSize ) != 0 ) + { + mDocumentModified = true; + } + } + + if( errCode == Err_Success ) + { + memcpy( &data()[offset], newData, newSize ); + } + + // + // Data is removed regardless of success or not. Otherwise we will + // have a mmeory leak. The single reason why the operation above could + // fail is because there was that no more memory that could be + // allocated. + // + if( removeData == true ) + { + delete [] newData; + } + +} + + +bool CHexBuffer::inputDummy( unsigned char *dest, int value, uint cell ) +{ + (void)dest; + (void)value; + (void)cell; + return( false ); +} + + +bool CHexBuffer::inputHexadecimal( unsigned char *dest, int value, uint cell ) +{ + if( value >= '0' && value <= '9' ) + { + value = value - '0'; + } + else if( value >= 'A' && value <= 'F' ) + { + value = value - 'A' + 10; + } + else if( value >= 'a' && value <= 'f' ) + { + value = value - 'a' + 10; + } + else + { + return( false ); + } + + if( cell > 1 ) + { + return( false ); + } + + uint shift = 1 - cell; + *dest = (*dest & ~(0xF<<(shift*4)) ) | (value<<(shift*4)); + return( true ); +} + + +bool CHexBuffer::inputDecimal( unsigned char *dest, int value, uint cell ) +{ + // + // 2000-01-22 Espen Sand + // I do the insertion a bit different here since decimal is special + // with respect to bitwidths. + // + if( value < '0' || value > '9' || cell > 2 ) + { + return( false ); + } + + char buf[4]; + printDecimalCell( buf, *dest ); + buf[cell]=value; + buf[3]=0; + + int tmp = atoi(buf); + if( tmp > 255 ) + { + return( false ); + } + + *dest = tmp; + return( true ); +} + + +bool CHexBuffer::inputOctal( unsigned char *dest, int value, uint cell ) +{ + if( value >= '0' && value <= '7' ) + { + value = value - '0'; + if( cell == 0 && value > 3 ) + { + return( false ); + } + } + else + { + return( false ); + } + + if( cell >= 3 ) + { + return( false ); + } + + uint shift = 2 - cell; + *dest = (*dest & ~(0x7<<(shift*3)) ) | (value<<(shift*3)); + return( true ); +} + + +bool CHexBuffer::inputBinary( unsigned char *dest, int value, uint cell ) +{ + if( value >= '0' && value <= '1' ) + { + value = value - '0'; + } + else + { + return( false ); + } + + if( cell > 7 ) + { + return( false ); + } + + uint shift = 7 - cell; + *dest = (*dest & ~(1<<shift)) | (value<<shift); + return( true ); +} + + + +bool CHexBuffer::inputAscii( unsigned char *dest, int value, uint ) +{ + *dest = value; + return( true ); +} + + + +int CHexBuffer::moveBuffer( uint destOffset, uint srcOffset ) +{ + if( srcOffset > documentSize() || destOffset == srcOffset ) + { + return( Err_Success ); + } + + if( destOffset < srcOffset ) + { + char *dest = &data()[ destOffset ]; + char *src = &data()[ srcOffset ]; + + memmove( dest, src, documentSize() - srcOffset ); + setDocumentSize( documentSize() - (srcOffset - destOffset) ); + return( Err_Success ); + } + else + { + uint s = documentSize() - srcOffset; + if( destOffset + s >= size() ) + { + int errCode = resizeBuffer( destOffset + s ); + if( errCode != Err_Success ) + { + fatalSound(); + return( errCode ); + } + } + else + { + setDocumentSize( documentSize() + (destOffset - srcOffset) ); + } + + char *dest = &data()[ destOffset ]; + char *src = &data()[ srcOffset ]; + + memmove( dest, src, s ); + memset( src, 0, destOffset - srcOffset ); + return( Err_Success ); + } +} + + + + +int CHexBuffer::resizeBuffer( uint newSize ) +{ + if( newSize < documentSize() ) + { + return( Err_Success ); + } + + if( newSize >= size() ) + { + QByteArray tmp; + tmp.duplicate( data(), size() ); + if( tmp.isNull() == true ) + { + return( Err_NoMemory ); + } + + if( fill( '\0', newSize + 100 ) == false ) + { + return( Err_NoMemory ); + } + + memcpy( data(), &tmp[0], tmp.size() ); + } + + setDocumentSize( newSize ); + return( Err_Success ); +} + + +void CHexBuffer::inputSound( void ) +{ + if( mInputErrorSound == true ) + { + KNotifyClient::beep( QObject::tr("Edit operation failed") ); + } +} + + +void CHexBuffer::fatalSound( void ) +{ + if( mFatalErrorSound == true ) + { + KNotifyClient::beep( QObject::tr("Could not allocate memory") ); + } +} + + +int CHexBuffer::printHtmlDataPage( const QString &tocName, + const QStringList &fileNames, uint index, + const SExportHtml &ex, + uint line, uint numLine ) +{ + if( fileNames.count() == 0 ) + { + return( Err_NullArgument ); + } + + if( index >= fileNames.count() ) + { + index = fileNames.count()-1; + } + + QFile file( fileNames[index] ); + if( file.open( IO_WriteOnly ) == false ) + { + return( Err_OperationAborted ); + } + + QTextStream os( &file ); + const QString *next = index+1 >= fileNames.count() ? 0 : &fileNames[index+1]; + const QString *prev = index == 0 ? 0 : &fileNames[index-1]; + const QString *toc = tocName.length() == 0 ? 0 : &tocName; + + printHtmlHeader( os, true ); + if( ex.navigator == true ) + { + printHtmlNavigator( os, next, prev, toc ); + } + + printHtmlCaption( os, ex.topCaption, index+1, fileNames.count() ); + printHtmlTable( os, line, numLine, ex.blackWhite ); + printHtmlCaption( os, ex.bottomCaption, index+1, fileNames.count() ); + + if( ex.navigator == true ) + { + printHtmlNavigator( os, next, prev, toc ); + } + printHtmlHeader( os, false ); + + return( Err_Success ); +} + + +void CHexBuffer::printHtmlTocPage( const QString &tocName, + const QString &linkName, + const QStringList &fileNames, + const QStringList &offsets, + uint numPage ) +{ + if( numPage == 0 || fileNames.count() == 0 ) + { + return; + } + if( numPage >= fileNames.count() ) + { + numPage = fileNames.count() - 1; + } + + QFile file( tocName ); + if( file.open( IO_WriteOnly ) == false ) + { + return; + } + + QTextStream os( &file ); + printHtmlHeader( os, true ); + + os << "<P ALIGN=\"CENTER\">" << endl; + os << "<B><FONT COLOR=BLACK>" << endl; + os << mUrl << endl; + os << "</FONT></B></CAPTION>" << endl; + os << "</P>" << endl; + + os << "<P ALIGN=\"CENTER\"><TT>" << endl; + for( uint i=0; i<=numPage; i++ ) + { + QString n( fileNames[i].right( fileNames[i].length() - + fileNames[i].findRev('/') - 1) ); + os << "<A HREF=\"" << n << "\">" << i18n("Page") << i+1; + os << "</A>"; + os << " " << offsets[i]; + os << "<br>" << endl; + } + os << "</P>" << endl; + + printHtmlHeader( os, false ); + + if( linkName.isEmpty() == false ) + { + // + // Make a symlink. We ignore any error here. I don't consider + // it to be fatal. + // + QString n( tocName.right( tocName.length() - tocName.findRev('/') - 1) ); + symlink( n.latin1(), linkName.latin1() ); + } + +} + + + +void CHexBuffer::printHtmlCaption( QTextStream &os, uint captionType, + uint curPage, uint numPage ) +{ + QString caption; + switch( captionType ) + { + case 0: + return; + break; + + case 1: + caption = mUrl; + break; + + case 2: + caption = mUrl.right( mUrl.length() - mUrl.findRev('/') - 1); + break; + + case 3: + caption = i18n("Page %1 of %2").arg(curPage).arg(numPage); + break; + } + + os << "<P ALIGN=\"CENTER\">" << endl; + os << "<B><FONT COLOR=BLACK>" << endl; + os << caption << endl; + os << "</FONT></B></CAPTION>" << endl; + os << "</P>" << endl; +} + + + +void CHexBuffer::printHtmlNavigator( QTextStream &os, const QString *next, + const QString *prev, const QString *toc ) +{ + os << "<TABLE BORDER=\"0\" CELLSPACING=\"0\" WIDTH=\"100%\">" << endl; + os << "<TR>" << endl; + os << "<TD>" << endl; + if( next == 0 ) + { + os << i18n("Next") << " "; + } + else + { + QString n( next->right( next->length() - next->findRev('/') - 1) ); + os << "<A HREF=\"" << n << "\">" << i18n("Next") << "</A>" << " "; + } + + if( prev == 0 ) + { + os << i18n("Previous") << " "; + } + else + { + QString p( prev->right( prev->length() - prev->findRev('/') - 1) ); + os << "<A HREF=\"" << p << "\">" << i18n("Previous") << "</A>" << " "; + } + + if( toc == 0 ) + { + os << i18n("Contents") << " "; + } + else + { + QString t( toc->right( toc->length() - toc->findRev('/') - 1) ); + os << "<A HREF=\"" << t << "\">" << i18n("Contents"); + os << "</A>" << " "; + } + + os << "</TD>" << endl; + + os << "<TD ALIGN=\"RIGHT\">" << endl; + os << "<A HREF=\"" << "http://home.sol.no/~espensa/khexedit" << "\">"; + os << i18n("Generated by khexedit"); + os << "</A>" << " "; + + os << "</TD>" << endl; + os << "</TR>" << endl << "</TABLE>" << endl; +} + + +int CHexBuffer::printHtmlHeader( QTextStream &os, bool isFront ) +{ + if( isFront == true ) + { + os << "<HTML>" << endl << "<HEAD>" << endl; + os << "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; "; + os << "charset=iso-8859-1\">" << endl; + os << "<META NAME=\"hexdata\" CONTENT=\"khexedit dump\">" << endl; + os << "</HEAD>" << endl << "<BODY>" << endl; + } + else + { + os << "</BODY>" << endl << "</HTML>" << endl; + } + + return( Err_Success ); +} + + +int CHexBuffer::printHtmlTable( QTextStream &os, uint line, uint numLine, + bool bw ) +{ + uint i; + QColor color; + + + int numCol = 1; + if( mLayout.offsetVisible == true ) { numCol += 1; } + if( mLayout.secondaryMode != SDisplayLayout::hide ) { numCol += 1; } + + os << "<TABLE BORDER=1 COLS=" << numCol << " WIDTH=\"100%\" "; + os << "CELLSPACING=0 CELLPADDING=2>" << endl; + if( mLayout.offsetVisible == true ) + { + color = bw == true ? Qt::white : mColor.offsetBg; + os << "<TD BGCOLOR=" << color.name().latin1() << ">" << endl; + os << "<TABLE BORDER=0 COLS=1 WIDTH=\"100%\" "; + os << "CELLSPACING=0 CELLPADDING=2>" << endl; + + color = bw == true ? Qt::black : mColor.offsetFg; + for( i=0; i<numLine; i++ ) + { + os << "<TR><TD><TT><b><FONT COLOR=" << color.name().latin1() << ">"; + THIS_FPTR(printOffset)( mPrintBuf, (line+i)*mLayout.lineSize ); + mPrintBuf[mOffsetSize]=0; + os << mPrintBuf << "</TD></TR>" << endl; + } + os << "</TABLE>" << endl << "</TD>" << endl; + } + + color = bw == true ? Qt::white : mColor.textBg; + os << "<TD BGCOLOR=" << color.name().latin1() << ">" << endl; + os << "<TABLE BORDER=0 COLS=1 WIDTH=\"100%\" "; + os << "CELLSPACING=0 CELLPADDING=2>" << endl; + for( i=0; i<numLine; i++ ) + { + printHtmlLine( os, line+i, true, bw ); + } + os << "</TABLE>" << endl << "</TD>" << endl; + + if( mLayout.secondaryMode != SDisplayLayout::hide ) + { + color = bw == true ? Qt::white : mColor.textBg; + os << "<TD BGCOLOR=" << color.name().latin1() << ">" << endl; + os << "<TABLE BORDER=0 COLS=1 WIDTH=\"100%\" "; + os << "CELLSPACING=0 CELLPADDING=2>" << endl; + for( i=0; i<numLine; i++ ) + { + printHtmlLine( os, line+i, false, bw ); + } + os << "</TABLE>" << endl << "</TD>" << endl; + } + + os << "</TR>" << endl << "</TABLE>" << endl; + return( Err_Success ); +} + + +int CHexBuffer::printHtmlLine( QTextStream &os, uint line, bool isPrimary, + bool bw ) +{ + uint offset = line * mLayout.lineSize; + QColor prevColor; + + QColor color; + if( bw == true ) + { + color = Qt::white; + } + else + { + color = (line+1) % 2 ? mColor.textBg : mColor.secondTextBg; + } + + os << "<TR><TD NOWRAP BGCOLOR=" << color.name().latin1() << "><TT><B>" + << endl; + if( offset >= documentSize() ) + { + os << "<BR></TD></TR>" << endl; + return( Err_Success ); + } + + for( uint i=0; i < mLayout.lineSize; i++ ) + { + if( isPrimary == true ) + { + if( offset+i >= documentSize() ) + { + memset(mPrintBuf, ' ', mNumCell ); + mPrintBuf[mNumCell] = 0; + if( i == 0 ) + { + color = bw == true ? Qt::black : foregroundColor(i); + } + else + { + color = prevColor; + } + } + else + { + unsigned char val = (unsigned char)data()[offset+i]; + if( THIS_FPTR(printCell)( mPrintBuf, val ) == 0 ) + { + color = bw == true ? Qt::black : foregroundColor(i); + } + else + { + color = bw == true ? Qt::black : mColor.nonPrintFg; + } + } + mPrintBuf[mNumCell] = 0; + if( i == 0 ) + { + os << "<FONT COLOR=" << color.name().latin1() << ">"; + } + else if( color != prevColor ) + { + os << "</FONT><FONT COLOR=" << color.name().latin1() << ">"; + } + prevColor = color; + + if( mPrintBuf[0] == '<' ) + { + os << "<"; + } + else + { + os << mPrintBuf; + if( (i+1) % mLayout.columnSize == 0 && (i+1) != mLayout.lineSize ) + { + os << " "; + } + } + } + else + { + if( offset+i >= documentSize() ) + { + memset(mPrintBuf, ' ', 1 ); + if( i == 0 ) + { + color = bw == true ? Qt::black : mColor.secondaryFg; + } + else + { + color = prevColor; + } + } + else + { + unsigned char val = (unsigned char)data()[offset+i]; + if( printAsciiCell( mPrintBuf, val ) == 0 ) + { + color = bw == true ? Qt::black : mColor.secondaryFg; + } + else + { + color = bw == true ? Qt::black : mColor.nonPrintFg; + } + mPrintBuf[1] = 0; + + if( i == 0 ) + { + os << "<FONT COLOR=" << color.name().latin1() << ">"; + } + else if( color != prevColor ) + { + os << "</FONT><FONT COLOR=" << color.name().latin1() << ">"; + } + prevColor = color; + + mPrintBuf[1] = 0; + os << (mPrintBuf[0] == '<' ? "<" : mPrintBuf); + } + + } + } + os << "</TD></TR>" << endl; + return( Err_Success ); +} + + + + + diff --git a/khexedit/hexbuffer.h b/khexedit/hexbuffer.h new file mode 100644 index 0000000..ea11d95 --- /dev/null +++ b/khexedit/hexbuffer.h @@ -0,0 +1,2040 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * 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 _HEX_BUFFER_H_ +#define _HEX_BUFFER_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <iostream> +#include <time.h> + +#include <qbitarray.h> +#include <qdatetime.h> +#include <qfile.h> +#include <qfont.h> +#include <qptrlist.h> +#include <qpainter.h> +#include <qstring.h> +#include <qtextstream.h> + +#include <kapplication.h> + +#include "conversion.h" +#include "hexeditstate.h" +#include "hexprinter.h" +#include "progress.h" + +// +// Marco to simplify usage of function pointers +// +#define THIS_FPTR( func ) ((this->*func)) + +struct SSearchControl +{ + QByteArray key; + QByteArray val; + uint keyType; + bool fromCursor; + bool inSelection; + bool forward; + bool ignoreCase; + bool match; + uint numReplace; + + bool wrapValid; + bool wrapActive; + uint wrapMark; +}; + + +struct SFilterControl +{ + enum Operation + { + OperandAndData = 0, + OperandOrData, + OperandXorData, + InvertData, + ReverseData, + RotateData, + ShiftData, + SwapBits + }; + + int execute( uchar *dest, uchar *src, uint size ); + + + QByteArray operand; + int rotate[2]; + Operation operation; + bool fromCursor; + bool inSelection; + bool forward; +}; + + +struct SInsertData +{ + uint size; + QByteArray pattern; + uint offset; + bool repeatPattern; + bool onCursor; +}; + + +struct SExportRange +{ + enum EMode + { + All = 0, + Selection, + Range + }; + + EMode mode; + uint start; + uint stop; +}; + + +struct SExportText +{ + SExportRange range; + QString destFile; +}; + + +struct SExportHtml +{ + SExportRange range; + QString package; + QString prefix; + uint linePerPage; + uint topCaption; + uint bottomCaption; + bool symLink; + bool navigator; + bool blackWhite; +}; + + +struct SExportCArray +{ + enum ElementType + { + Char = 0, + Uchar, + Short, + Ushort, + Int, + Uint, + Float, + Double + }; + + const char *printFormatted( const char *b, uint maxSize ) const; + QString variableName( uint range ) const; + int elementSize( void ) const; + + SExportRange range; + QString destFile; + QString arrayName; + int elementType; + uint elementPerLine; + bool unsignedAsHexadecimal; +}; + + +struct SStatisticControl +{ + SStatisticControl( void ) + { + memset( occurrence, 0, sizeof(occurrence) ); + documentSize = 0; + } + + uint documentSize; + uint occurrence[256]; + QString documentName; +}; + + +struct SPagePosition +{ + SPagePosition( time_t now, uint numLine, uint linePerPage ) + { + init( now, numLine, linePerPage ); + } + + SPagePosition( void ) + { + init( 0, 1, 1 ); + } + + void init( time_t at, uint numLine, uint linePerPage ) + { + if( linePerPage == 0 ) { linePerPage = 1; } + + now = at; + curPage = 1; + maxPage = numLine / linePerPage + (numLine % linePerPage ? 1 : 0); + if( maxPage < curPage ) { maxPage = curPage; } + } + + void step( uint stepSize=1 ) + { + curPage += stepSize; + if( curPage > maxPage ) { curPage = maxPage; } + } + + uint current( void ) + { + return( curPage ); + } + + uint max( void ) + { + return( maxPage ); + } + + uint curPage; + uint maxPage; + time_t now; +}; + + + +class CStringCollectControl +{ + public: + CStringCollectControl( void ) + { + mList.setAutoDelete( true ); + } + + int add( uint offset, const QByteArray &a ) + { + QString *s = new QString(); + if( s == 0 ) + { + return( Err_NoMemory ); + } + + if( decimalOffset == true ) + { + s->sprintf( "%010u", offset ); + } + else + { + s->sprintf( "%04x:%04x", offset>>16, offset&0x0000FFFF ); + } + + *s += QString( a ); + + mList.append( s ); + return( Err_Success ); + } + + uint offsetLen( void ) + { + return( decimalOffset ? 10 : 9 ); + } + + void clear( void ) + { + mList.clear(); + } + + const QString *get( uint index ) + { + return( mList.at( index ) ); + } + + int count( void ) + { + return( mList.count() ); + } + + QPtrList<QString> &list( void ) + { + return( mList ); + } + + public: + uint minLength; + bool decimalOffset; + bool allow8bit; + + private: + QPtrList<QString> mList; +}; + + + + + + +struct SCursorConfig +{ + SCursorConfig( void ) + { + state = 0; + } + + bool selectOn( void ) + { + return( state & Qt::ShiftButton ); + } + + bool removeSelection( void ) + { + return( state & Qt::ShiftButton ? false : true ); + } + + void setKeepSelection( bool val ) + { + state = val == true ? state|Qt::ShiftButton : state&~Qt::ShiftButton; + } + + bool controlButton( void ) + { + return( state & Qt::ControlButton ? true : false ); + } + + bool shiftButton( void ) + { + return( state & Qt::ShiftButton ? true : false ); + } + + bool altButton( void ) + { + return( state & Qt::AltButton ? true : false ); + } + + + void emulateControlButton( bool val ) + { + state = val == true ? state|Qt::ControlButton : state&~Qt::ControlButton; + } + + int state; +}; + + + +struct SCursorSpec +{ + enum EShape + { + solid = 0, + frame, + thin + }; + + void reset( void ) + { + offset = 0; + x1 = x2 = y = cell = maxCell = 0; + } + + void setShape( EShape primaryShape, EShape secondaryShape, uint unitWidth, + uint numCell ) + { + + if( primaryShape == thin ) + { + if( onlyBlock == true ) { primaryShape = solid; } + } + if( secondaryShape == thin ) + { + if( onlyBlock == true ) { secondaryShape = solid; } + } + + mPrimaryShape = primaryShape; + if( mPrimaryShape == solid ) + { + drawWidth1 = unitWidth; + drawOffset1 = 0; + } + else if( mPrimaryShape == frame ) + { + drawWidth1 = unitWidth * numCell; + drawOffset1 = 0; + } + else + { + mPrimaryShape = thin; + if( thickState == true ) + { + drawWidth1 = 2; + drawOffset1 = -1; + } + else + { + drawWidth1 = 5; + drawOffset1 = -3; + } + } + + mSecondaryShape = secondaryShape; + if( mSecondaryShape == solid ) + { + drawWidth2 = unitWidth; + drawOffset2 = 0; + } + else if( mSecondaryShape == frame ) + { + drawWidth2 = unitWidth * numCell; + drawOffset2 = 0; + } + else + { + mSecondaryShape = thin; + if( thickState == true ) + { + drawWidth2 = 2; + drawOffset2 = -1; + } + else + { + drawWidth2 = 5; + drawOffset2 = -3; + } + } + } + + void setShapeModifier( bool alwaysBlock, bool useThick ) + { + onlyBlock = alwaysBlock; + thickState = useThick; + } + + void dump( void ) + { + std::cout << "offset: " << offset << " y: " << y << " x1: " << x1 << std::endl; + std::cout << "x2: " << x2 << " cell: " << cell << std::endl; + } + + bool inside( uint min, uint max ) + { + return( offset >= min && offset < max ); + } + + int drawX1( void ) + { + return( x1 + drawOffset1 ); + } + + int drawX2( void ) + { + return( x2 + drawOffset2 ); + } + + int width1( void ) + { + return( drawWidth1 ); + } + + int width2( void ) + { + return( drawWidth2 ); + } + + uint offset; + int y; + int x1; + int x2; + int cell; + int maxCell; + bool onlyBlock; + bool thickState; + + char data; + + int mPrimaryShape; + int mSecondaryShape; + int drawWidth1; + int drawWidth2; + int drawOffset1; + int drawOffset2; +}; + + +struct SCursor +{ + SCursor( void ) + { + mLineSize = 1; + mDocumentSize = 0; + mFixedSizeMode = false; + mArea = 0; + } + + void reset( void ) + { + prev.reset(); + curr.reset(); + next.reset(); + } + + void setDocumentSize( uint documentSize ) + { + mDocumentSize = documentSize; + } + + void setFixedSizeMode( bool fixedSizeMode ) + { + mFixedSizeMode = fixedSizeMode; + } + + bool incCell( void ) + { + if( curr.cell + 1 >= curr.maxCell ) + { + addOffset( 1 ); + return( true ); + } + else + { + next.cell = curr.cell + 1; + return( false ); + } + } + + bool decCell( void ) + { + if( curr.cell == 0 ) + { + if( curr.offset > 0 ) + { + decOffset( 1, true ); + next.cell = curr.maxCell > 0 ? curr.maxCell - 1 : 0; + } + return( true ); + } + else + { + next.cell = curr.cell - 1; + return( false ); + } + } + + void resetCell( void ) + { + next.cell = 0; + } + + + void addOffset( uint val ) + { + setOffset( curr.offset + val ); + } + + void decOffset( uint val, bool ignoreCell ) + { + if( ignoreCell == true || curr.cell == 0 ) + { + setOffset( val > curr.offset ? curr.offset%mLineSize : curr.offset-val); + } + else + { + setOffset( curr.offset ); + } + } + + void setOffset( uint offset ) + { + /* + if( offset >= mDocumentSize ) + { + if( mFixedSizeMode == true ) + { + offset = mDocumentSize > 0 ? mDocumentSize - 1 : 0; + } + else + { + offset = mDocumentSize; + } + } + */ + + next.offset = offset; + next.cell = 0; + } + + uint getOffset( void ) + { + return( curr.offset ); + } + + void setOffset( uint offset, uint bit, bool backward, bool fromCursor, + uint textSize ) + { + if( fromCursor == true ) + { + if( backward == true ) + { + setOffset( offset > curr.offset ? 0 : curr.offset - offset ); + } + else + { + setOffset( curr.offset + offset ); + } + } + else + { + if( backward == true ) + { + setOffset( offset > textSize ? 0 : textSize - offset ); + } + else + { + setOffset( offset > textSize ? textSize : offset ); + } + } + setBit( bit ); + } + + + void setBit( uint bit ) + { + bit = (bit > 7) ? 0 : 7 - bit; + next.cell = bit / mCellWeight; + } + + + void home( bool toExtreme ) + { + if( toExtreme == true ) + { + setOffset( 0 ); + } + else + { + setOffset( next.offset - curr.offset % mLineSize ); + } + } + + void end( bool toExtreme ) + { + uint maxOffset; + if( mFixedSizeMode == true ) + { + maxOffset = mDocumentSize > 0 ? mDocumentSize-1 : mDocumentSize; + } + else + { + maxOffset = mDocumentSize; + } + + if( toExtreme == true ) + { + setOffset( maxOffset ); + } + else + { + uint newOffset = next.offset + (mLineSize-1) - curr.offset % mLineSize; + setOffset( newOffset > maxOffset ? maxOffset : newOffset ); + } + + } + + void up( uint numLines ) + { + decOffset( numLines * mLineSize, true ); + } + + void down( uint numLines ) + { + addOffset( numLines * mLineSize ); + } + + bool changed( void ) + { + return( prev.offset != curr.offset || prev.cell != curr.cell || + prev.data != curr.data ? true : false ); + } + + uint bit( void ) + { + uint bitValue = mCellWeight*(curr.maxCell - curr.cell) - 1; + return( bitValue > 7 ? 7 : bitValue ); + } + + uint cellWeight( void ) + { + return( mCellWeight ); + } + + void setLineSize( uint lineSize ) + { + mLineSize = lineSize < 1 ? 1 : lineSize; + } + + void setCellWeight( uint cellWeight ) + { + mCellWeight = cellWeight; + } + + int area( void ) + { + return( mArea ); + } + + void setArea( int area ) + { + mArea = area; + } + + void setShape( SCursorSpec::EShape primary, SCursorSpec::EShape secondary, + uint unitWidth, uint numCell ) + { + curr.setShape( primary, secondary, unitWidth, numCell ); + } + + void setShapeModifier( bool alwaysBlock, bool useThick ) + { + curr.setShapeModifier( alwaysBlock, useThick ); + } + + uint mLineSize; + uint mDocumentSize; + uint mCellWeight; + int mArea; + bool mFixedSizeMode; + SCursorSpec prev; + SCursorSpec curr; + SCursorSpec next; +}; + + +struct SCursorPosition +{ + int x; + int y; + int w; + int h; +}; + +struct SCursorOffset +{ + uint offset; + uint bit; +}; + + +struct SSelectSpec +{ + void init( uint offset ) + { + start = stop = anchor = offset; + } + + void set( uint offset ) + { + if( offset < anchor ) + { + start = offset; + stop = anchor; + } + else + { + stop = offset; + start = anchor; + } + } + + void expand( uint value ) + { + if( anchor == stop ) { anchor +=value; } + stop += value; + //set( stop + value ); + } + + void shrink( uint value ) + { + uint newVal = start + value > stop ? start : stop - value; + if( anchor == stop ) { anchor = newVal; } + stop = newVal; + /* + if( start + value > stop ) + { + set( start ); + } + else + { + set( stop - value ); + } + */ + } + + + uint start; + uint stop; + uint anchor; +}; + + +struct SSelect +{ + SSelect( void ) + { + reset(); + } + + bool init( uint offset ) + { + curr.init( offset ); + if( isValid == true ) + { + isValid = false; + return( true ); + } + else + { + return( false ); + } + } + + void reset( void ) + { + curr.init( 0 ); + isValid = false; + } + + bool set( uint offset ) + { + isValid = true; + + curr.set( offset ); + if( curr.start != prev.start || curr.stop != prev.stop ) + { + return( true ); + } + else + { + return( false ); + } + } + + void expand( uint value ) + { + if( isValid == false ) + { + return; + } + curr.expand( value ); + } + + void shrink( uint value ) + { + if( isValid == false ) + { + return; + } + curr.shrink( value ); + } + + + void sync( void ) + { + prev = curr; + } + + bool inside( uint offset ) + { + return( isValid == true && offset >= curr.start && offset < curr.stop ); + } + + bool inside( uint offset, uint range ) + { + return( isValid == true && (offset + range) >= curr.start && + offset < curr.stop ); + } + + bool verify( uint &start, uint &stop ) + { + if( isValid == false ) + { + return( false ); + } + + if( start < curr.start ) { start = curr.start; } + if( stop > curr.stop ) { stop = curr.stop; } + return( true ); + } + + uint start( uint offset ) + { + // + // If 'curr.star' is smaller than 'offset' then the start is at + // the start of line. + // + return( curr.start < offset ? 0 : curr.start - offset ); + } + + uint start( void ) + { + return( curr.start ); + } + + uint stop( uint offset, uint range ) + { + return( curr.stop > offset + range ? range : curr.stop - offset ); + } + + uint stop( void ) + { + return( curr.stop ); + } + + bool valid( void ) + { + return( isValid ); + } + + uint size( void ) + { + if( isValid == false ) + { + return( 0 ); + } + else + { + return( curr.start >= curr.stop ? 0 : curr.stop - curr.start ); + } + } + + void startChange( uint &first, uint &last ) + { + if( curr.start <= prev.start ) + { + first = curr.start; + last = prev.start; + } + else + { + first = prev.start; + last = curr.start; + } + } + + void stopChange( uint &first, uint &last ) + { + if( curr.stop <= prev.stop ) + { + first = curr.stop; + last = prev.stop; + } + else + { + first = prev.stop; + last = curr.stop; + } + } + + + bool isValid; + SSelectSpec prev; + SSelectSpec curr; +}; + + + +class CHexAction +{ + public: + enum HexAction + { + replace + }; + + public: + CHexAction( HexAction action, uint offset ); + ~CHexAction( void ); + void setData( uint size, char *data, uint dataSize ); + + public: + HexAction mAction; + uint mOffset; + uint mSize; + char *mData; + uint mDataSize; + CHexAction *mNext; +}; + +class CHexActionGroup +{ + public: + CHexActionGroup( uint startOffset, uint startBit ); + ~CHexActionGroup( void ); + void insertAction( CHexAction *hexAction ); + + public: + uint mStartOffset; + uint mStopOffset; + uint mStartBit; + uint mStopBit; + CHexAction *mHexAction; +}; + + + +struct SCursorState +{ + bool valid; + uint selectionOffset; + uint selectionSize; + uint offset; + uint cell; + unsigned char data[8]; + uint undoState; + bool charValid; +}; + +struct SFileState +{ + bool valid; + uint size; + bool modified; +}; + + + + + +class CHexBuffer; +typedef int (CHexBuffer::*PrintCellFunc)( char *buf, unsigned char data ); +typedef bool (CHexBuffer::*InputCellFunc)( unsigned char *dest, int value, + uint cell ); +typedef void (CHexBuffer::*PrintOffsetFunc)( char *buf, uint offset ); + + +class CHexBuffer : public QByteArray +{ + public: + enum EColumn + { + VisibleColumn = 0x0, + OffsetColumn = 0x1, + PrimaryColumn = 0x2, + SecondaryColumn = 0x4, + EveryColumn = 0x7 + }; + + enum EEditArea + { + edit_none = 0, + edit_primary, + edit_secondary + }; + + enum ECursorMode + { + cursor_curr = 0, + cursor_prev + }; + + enum EEditMode + { + EditInsert = 0, + EditReplace + }; + + enum EUndoState + { + UndoOk = 1, + RedoOk = 2 + }; + + public: + CHexBuffer( void ); + ~CHexBuffer( void ); + + int setLayout( SDisplayLayout &layout ); + void setColor( SDisplayColor &color ); + void setInputMode( SDisplayInputMode &mode ); + bool toggleEditor( void ); + + bool matchWidth( uint width ); + + void setNonPrintChar( QChar nonPrintChar ); + void setShowCursor( bool showCursor ); + void setDisableCursor( bool disableCursor ); + void setCursorShapeModifier( bool alwaysBlock, bool thickInsert ); + void setEditMode( EEditMode editMode ); + void setEditMode( EEditMode editMode, bool alwaysBlock, bool thickInsert ); + void setMaximumSize( uint size ); + void setDocumentSize( uint size ); + void setUndoLevel( uint level ); + void setSoundState( bool inputSound, bool fatalSound ); + void setBookmarkVisibility( bool showInColumn, bool showInEditor ); + + void setFont( const SDisplayFontInfo &fontInfo ); + int setEncoding( CConversion::EMode mode, CProgress &p ); + + bool setCursorPosition( int x, int y, bool init, bool cellLevel ); + + int readFile( QFile &file, const QString &url, CProgress &p ); + int insertFile( QFile &file, CProgress &p ); + int writeFile( QFile &file, CProgress &p ); + int newFile( const QString &url ); + void closeFile( void ); + void registerDiskModifyTime( const QFile &file ); + + bool changedOnDisk( void ); + + void drawText( QPainter &paint, uint line, int sx, int x, int w ); + void drawText( QPainter &paint, uint line, int x1, int x2, int y, + bool useBlackWhite ); + + void drawHeader( QPainter &paint, int sx, int width, int y, bool isFooter, + const SPageHeader &header,const SPagePosition &position ); + int headerHeight( QPainter &paint ); + int headerMargin( QPainter &paint ); + + bool inputAtCursor( QChar c ); + int inputAtCursor( const QByteArray &buf, uint oldSize ); + bool removeAtCursor( bool beforeCursor ); + + int locateRange( const SExportRange &range, uint &start, uint &stop ); + int exportText( const SExportText &ex, CProgress &p ); + int exportHtml( const SExportHtml &ex, CProgress &p ); + int exportCArray( const SExportCArray &ex, CProgress &p ); + int copySelectedText( QByteArray &array, int columnSegment=VisibleColumn); + int copyAllText( QByteArray &array ); + int copyText( QByteArray &array, const SExportRange &range, + int columnSegment ); + int copySelectedData( QByteArray &array ); + + uint numPage( CHexPrinter &printer ); + int print( CHexPrinter &printer, CProgress &p ); + + uint printLine( char *dst, uint line ); + uint printLine( char *dst, uint line, int columnSegment ); + + bool cutSelection( void ); + bool undo( void ); + bool redo( void ); + int addBookmark( int position ); + bool removeBookmark( int position ); + void updateBookmarkMap( bool resize ); + + int findFirst( SSearchControl &sc ); + int findNext( SSearchControl &sc ); + int findWrap( SSearchControl &sc ); + int replaceAll( SSearchControl &sc, bool init ); + int replaceMarked( SSearchControl &sc ); + int filter( SFilterControl &fc ); + int collectStrings( CStringCollectControl &sc ); + int collectStatistic( SStatisticControl &sc, CProgress &p ); + + void doActionGroup( CHexActionGroup *group ); + void doAction( CHexAction *action ); + + inline SCursorState &cursorState( void ); + inline void valueOnCursor( QByteArray &buf, uint size ); + inline SFileState &fileState( void ); + inline const SDisplayLayout &layout( void ); + + inline const SDisplayInputMode &inputMode( void ); + inline QPtrList<SCursorOffset> &bookmarkList( void ); + + inline bool documentPresent( void ); + inline bool modified( void ); + inline uint undoState( void ); + inline uint documentSize( void ); + inline EEditMode editMode( void ); + inline const SEncodeState &encoding( void ); + inline bool losslessEncoding( CConversion::EMode mode ); + + inline QString &url( void ); + bool hasFileName( void ); + inline void setUrl( const QString &url ); + inline void setModified( bool modified ); + inline const QDateTime &diskModifyTime( void ); + + + + inline uint calculateLine( uint offset ); + inline int lineSize( void ); + inline int lineHeight( void ); + inline int fontAscent( void ); + inline int lineWidth( void ); + inline int unitWidth( void ); + inline int numLines( void ); + inline int totalHeight( void ); + inline const QFont &font( void ); + inline SCursor *textCursor( void ); + inline const QColor &backgroundColor( void ); + inline int startX( void ); + inline int startY( void ); + inline void setStartX( int val ); + inline void setStartY( int val ); + + inline bool selectionSet( uint offset, bool init ); + inline void selectionSyncronize( void ); + inline void selectionStartChange( uint &offset1, uint &offset2 ); + inline void selectionStopChange( uint &offset1, uint &offset2 ); + inline bool cursorInsideSelection( void ); + + inline void markSet( uint offset, uint size ); + inline bool markSet( uint offset, bool init ); + inline bool markRemove( void ); + inline void markSyncronize( void ); + inline void markStartChange( uint &offset1, uint &offset2 ); + inline void markStopChange( uint &offset1, uint &offset2 ); + + inline uint cursorOffset( void ); + inline uint cursorBit( void ); + inline uint cursorLine( void ); + inline uint prevCursorLine( void ); + inline SCursor &cursor( void ); + + inline void currCursor( EEditArea editArea, SCursorPosition &p ); + inline void prevCursor( EEditArea editArea, SCursorPosition &p ); + + inline void cursorUp( uint lines ); + inline void cursorDown( uint lines ); + inline void cursorRight( bool cellLevel ); + inline void cursorLeft( bool cellLevel ); + inline void cursorStep( uint size, bool forward, bool modulo ); + inline void cursorHome( bool toExtreme ); + inline void cursorEnd( bool toExtreme ); + inline void cursorGoto( uint offset, uint bit ); + inline void cursorGoto( uint offset, uint bit, bool backward, + bool fromCursor ); + inline bool cursorChanged( void ); + inline void cursorResetEditArea( void ); + inline bool cursorPrimaryEdit( void ); + inline int cursorFixedPosition( int position, int height ); + inline int cursorChangePosition( int position, int height ); + void cursorReset( void ); + + private: + enum { BookmarkOnLine = 0x01, BookmarkOnCursor = 0x02 }; + + void computeLineWidth( void ); + void computeNumLines( void ); + void cursorCompute( void ); + + void drawSelection( QPainter &paint, QColor &color, uint start, uint stop, + int sx ); + int drawBookmarks(QPainter &paint, uint line, int startx); + void drawCursor( QPainter &paint, uint line, int startx, bool onBookmark ); + + void recordStart( SCursor &cursor ); + void recordReplace( SCursor &cursor, uint size, char *data, uint dataSize); + void recordEnd( SCursor &cursor ); + void doReplace( CHexAction *hexAction, bool removeData ); + int scanData( SSearchControl &sc, bool init ); + int initScanData( SSearchControl &sc ); + + inline const QColor &foregroundColor( uint column ); + inline int printDummyCell( char *buf, unsigned char data ); + inline int printHexadecimalBigCell( char *buf, unsigned char data ); + inline int printHexadecimalSmallCell( char *buf, unsigned char data ); + inline int printDecimalCell( char *buf, unsigned char data ); + inline int printOctalCell( char *buf, unsigned char data ); + inline int printBinaryCell( char *buf, unsigned char data ); + inline int printAsciiCell( char *buf, unsigned char data ); + inline void printDummyOffset( char *buf, uint offset ); + inline void printHexadecimalBigOffset( char *buf, uint offset ); + inline void printHexadecimalSmallOffset( char *buf, uint offset ); + inline void printDecimalOffset( char *buf, uint offset ); + + bool inputDummy( unsigned char *dest, int value, uint cell ); + bool inputHexadecimal( unsigned char *dest, int value, uint cell ); + bool inputDecimal( unsigned char *dest, int value, uint cell ); + bool inputOctal( unsigned char *dest, int value, uint cell ); + bool inputBinary( unsigned char *dest, int value, uint cell ); + bool inputAscii( unsigned char *dest, int value, uint cell ); + + int moveBuffer( uint destOffset, uint srcOffset ); + int resizeBuffer( uint offset ); + + void inputSound( void ); + void fatalSound( void ); + + int printHtmlDataPage( const QString &tocName, + const QStringList &fileNames, uint index, + const SExportHtml &ex, uint line, uint numLine ); + void printHtmlCaption( QTextStream &os, uint captionType, uint curPage, + uint numPage ); + void printHtmlNavigator( QTextStream &os, const QString *next, + const QString *prev, const QString *toc ); + void printHtmlTocPage( const QString &tocName, + const QString &linkName, + const QStringList &fileNames, + const QStringList &offsets, uint numPage ); + int printHtmlHeader( QTextStream &os, bool isFront ); + int printHtmlTable( QTextStream &os, uint line, uint numLine, bool bw ); + int printHtmlLine( QTextStream &os, uint offset, bool isPrimary, bool bw ); + + signals: + void fileSize( uint size ); + + private: + QString mUrl; + QDateTime mDiskModifyTime; + SDisplayLayout mLayout; + SDisplayColor mColor; + SDisplayFontInfo mFontInfo; + CConversion mEncode; + bool mCharValid[256]; + + unsigned char *mColorIndex; + char *mPrintBuf; + bool mLoadingData; + int mStartX; + int mStartY; + + int mFontHeight; + int mFontAscent; + int mLineWidth; + int mFixedWidth; + int mUnitWidth; + int mSplitWidth; + int mNumLines; + int mTextStart1; + int mTextStart2; + int mNumCell; + + uint mDocumentSize; + uint mMaximumSize; + bool mFixedSizeMode; + bool mDocumentModified; + EEditMode mEditMode; + SDisplayInputMode mInputMode; + + int mOffsetSize; + int mOffsetIndex; + int mPrimaryWidth; + int mSecondaryWidth; + int mActiveEditor; + + SSelect mSelect; + SSelect mMark; + + SCursor mCursor; + bool mShowCursor; + bool mDisableCursor; + + bool mInputErrorSound; + bool mFatalErrorSound; + + bool mShowBookmarkInOffsetColumn; + bool mShowBookmarkInEditor; + + uint mUndoLimit; + uint mUndoIndex; + QPtrList<CHexActionGroup> mUndoList; + QPtrList<SCursorOffset> mBookmarkList; + QBitArray mBookmarkMap; + + PrintCellFunc printCell; + PrintOffsetFunc printOffset; + InputCellFunc inputCell; + + static char mHexBigBuffer[16]; + static char mHexSmallBuffer[16]; + static char mDecBuffer[10]; + static char mOctBuffer[8]; + static SCursorState mCursorState; + static SFileState mFileState; +}; + + + +inline SCursorState &CHexBuffer::cursorState( void ) +{ + if( size() == 0 ) + { + mCursorState.valid = false; + mCursorState.selectionOffset = 0; + mCursorState.selectionSize = 0; + mCursorState.offset = 0; + mCursorState.cell = 0; + mCursorState.undoState = 0; + memset( mCursorState.data, 0, sizeof(mCursorState.data) ); + mCursorState.charValid = false; + } + else + { + mCursorState.valid = true; + mCursorState.selectionOffset = mSelect.start(); + mCursorState.selectionSize = mSelect.size(); + mCursorState.offset = cursorOffset(); + mCursorState.cell = cursorBit(); + mCursorState.undoState = undoState(); + + for( uint i = 0; i < sizeof( mCursorState.data ); i++ ) + { + mCursorState.data[i] = (mCursorState.offset+i >= mDocumentSize) ? 0 : + (unsigned char)data()[mCursorState.offset+i]; + } + + mCursorState.charValid = mCharValid[ mCursorState.data[0] ]; + } + return( mCursorState ); +} + + +inline void CHexBuffer::valueOnCursor( QByteArray &buf, uint size ) +{ + int offset = cursorOffset(); + if( offset + size >= mDocumentSize ) + { + size = mDocumentSize - offset; + } + + buf.resize(size); + for( uint i=0; i<buf.size(); i++) + { + buf[i] = (unsigned char)data()[offset+i]; + } +} + + +inline const SDisplayLayout &CHexBuffer::layout( void ) +{ + return( mLayout ); +} + + + +inline const SDisplayInputMode &CHexBuffer::inputMode( void ) +{ + return( mInputMode ); +} + +inline QPtrList<SCursorOffset> &CHexBuffer::bookmarkList( void ) +{ + return( mBookmarkList ); +} + + + + +inline SFileState &CHexBuffer::fileState( void ) +{ + if( size() == 0 ) + { + mFileState.valid = false; + mFileState.size = 0; + mFileState.modified = false; + + } + else + { + mFileState.valid = true; + mFileState.size = mDocumentSize; + mFileState.modified = mDocumentModified; + } + + return( mFileState ); +} + + + + + + + + +inline bool CHexBuffer::modified( void ) +{ + return( mDocumentModified ); +} + +inline void CHexBuffer::setModified( bool modified ) +{ + mDocumentModified = modified; +} + +inline uint CHexBuffer::undoState( void ) +{ + return( (mUndoIndex > 0 ? UndoOk : 0) | + (mUndoIndex < mUndoList.count() ? RedoOk : 0) ); +} + + +inline uint CHexBuffer::documentSize( void ) +{ + return( mDocumentSize ); +} + + +inline CHexBuffer::EEditMode CHexBuffer::editMode( void ) +{ + return( mEditMode ); +} + + +inline const SEncodeState &CHexBuffer::encoding( void ) +{ + return( mEncode.state() ); +} + +inline bool CHexBuffer::losslessEncoding( CConversion::EMode mode ) +{ + return( mEncode.lossless(mode) ); +} + +inline QString &CHexBuffer::url( void ) +{ + return( mUrl ); +} + +inline bool CHexBuffer::documentPresent( void ) +{ + return( size() == 0 ? false : true ); +} + +inline void CHexBuffer::setUrl( const QString &url ) +{ + mUrl = url; +} + +inline const QDateTime &CHexBuffer::diskModifyTime( void ) +{ + return( mDiskModifyTime ); +} + +inline uint CHexBuffer::calculateLine( uint offset ) +{ + return( mLayout.lineSize == 0 ? 0 : offset / mLayout.lineSize ); +} + +inline const QColor &CHexBuffer::foregroundColor( uint column ) +{ + if( column > mLayout.lineSize ) + { + return( Qt::black ); + } + else + { + return( mColor.primaryFg[ mColorIndex[ column ] ] ); + } +} + +inline bool CHexBuffer::selectionSet( uint offset, bool init ) +{ + if( offset >= size() ) { offset = size() > 0 ? size() - 1 : 0; } + + if( init == true ) + { + return( mSelect.init( offset ) ); + } + else + { + return( mSelect.set( offset ) ); + } +} + +inline void CHexBuffer::selectionSyncronize( void ) +{ + mSelect.sync(); +} + +inline void CHexBuffer::selectionStartChange( uint &offset1, uint &offset2 ) +{ + mSelect.startChange( offset1, offset2 ); +} + +inline void CHexBuffer::selectionStopChange( uint &offset1, uint &offset2 ) +{ + mSelect.stopChange( offset1, offset2 ); +} + +inline bool CHexBuffer::cursorInsideSelection( void ) +{ + return( mSelect.inside( cursorOffset() ) ); +} + +inline void CHexBuffer::markSet( uint offset, uint size ) +{ + markSet( offset, true ); + markSet( offset+size, false ); + mMark.sync(); +} + +inline bool CHexBuffer::markSet( uint offset, bool init ) +{ + if( offset >= size() ) { offset = size() > 0 ? size() - 1 : 0; } + + if( init == true ) + { + return( mMark.init( offset ) ); + } + else + { + return( mMark.set( offset ) ); + } +} + +inline bool CHexBuffer::markRemove( void ) +{ + return( mMark.init( mMark.start() ) ); +} + + +inline void CHexBuffer::markSyncronize( void ) +{ + mMark.sync(); +} + +inline void CHexBuffer::markStartChange( uint &offset1, uint &offset2 ) +{ + mMark.startChange( offset1, offset2 ); +} + +inline void CHexBuffer::markStopChange( uint &offset1, uint &offset2 ) +{ + mMark.stopChange( offset1, offset2 ); +} + + +inline uint CHexBuffer::cursorOffset( void ) +{ + return( mCursor.curr.offset ); +} + +inline uint CHexBuffer::cursorBit( void ) +{ + return( mCursor.bit() ); +} + + +inline uint CHexBuffer::cursorLine( void ) +{ + return( mCursor.curr.y / lineHeight() ); +} + +inline uint CHexBuffer::prevCursorLine( void ) +{ + return( mCursor.prev.y / lineHeight() ); +} + +inline SCursor &CHexBuffer::cursor( void ) +{ + return( mCursor ); +} + + +inline void CHexBuffer::currCursor( EEditArea editArea, SCursorPosition &p ) +{ + if( editArea == edit_primary ) + { + if( mActiveEditor == edit_primary ) + { + p.x = mCursor.curr.drawX1(); + p.w = mCursor.curr.width1(); + } + else + { + p.x = mCursor.curr.drawX2(); + p.w = mUnitWidth; + } + } + else + { + if( mActiveEditor == edit_primary ) + { + p.x = mCursor.curr.drawX2(); + p.w = mUnitWidth; + } + else + { + p.x = mCursor.curr.drawX1(); + p.w = mUnitWidth * mNumCell; + } + } + + p.x -= mStartX; + p.y = mCursor.curr.y - mStartY; + p.h = lineHeight(); + +} + +inline void CHexBuffer::prevCursor( EEditArea editArea, SCursorPosition &p ) +{ + if( editArea == edit_primary ) + { + if( mActiveEditor == edit_primary ) + { + p.x = mCursor.prev.drawX1(); + p.w = mUnitWidth * mNumCell; + } + else + { + p.x = mCursor.prev.drawX2(); + p.w = mUnitWidth; + } + } + else + { + if( mActiveEditor == edit_primary ) + { + p.x = mCursor.prev.drawX2(); + p.w = mUnitWidth; + } + else + { + p.x = mCursor.prev.drawX1(); + p.w = mUnitWidth * mNumCell; + } + } + + p.x -= mStartX; + p.y = mCursor.prev.y - mStartY; + p.h = lineHeight(); +} + + + + + + +inline void CHexBuffer::cursorUp( uint lines ) +{ + mCursor.up( lines ); + cursorCompute(); +} + +inline void CHexBuffer::cursorDown( uint lines ) +{ + mCursor.down( lines ); + cursorCompute(); +} + + +inline void CHexBuffer::cursorRight( bool cellLevel ) +{ + if( cellLevel == true && mActiveEditor == edit_primary ) + { + mCursor.incCell(); + } + else + { + mCursor.addOffset( 1 ); + } + cursorCompute(); +} + + +inline void CHexBuffer::cursorStep( uint size, bool forward, bool modulo ) +{ + if( forward == true ) + { + if( modulo == true ) + { + uint offset = mCursor.getOffset() + size; + mCursor.setOffset( offset - offset % size ); + } + else + { + mCursor.addOffset( size ); + } + } + else + { + if( modulo == true ) + { + uint offset = mCursor.getOffset(); + if( offset % size ) + { + mCursor.decOffset( offset % size, false ); + } + else + { + mCursor.setOffset( offset < size ? 0 : offset - size ); + } + } + else + { + mCursor.decOffset( size, false ); + } + } + cursorCompute(); +} + + +inline void CHexBuffer::cursorLeft( bool cellLevel ) +{ + if( cellLevel == true && mActiveEditor == edit_primary ) + { + mCursor.decCell(); + } + else + { + mCursor.decOffset( 1, false ); + } + cursorCompute(); +} + +inline void CHexBuffer::cursorHome( bool toExtreme ) +{ + mCursor.home( toExtreme ); + cursorCompute(); +} + +inline void CHexBuffer::cursorEnd( bool toExtreme ) +{ + mCursor.end( toExtreme ); + cursorCompute(); +} + + +inline void CHexBuffer::cursorGoto( uint offset, uint bit, bool backward, + bool fromCursor ) +{ + uint maxOffset = mFixedSizeMode == true ? mMaximumSize-1 : documentSize(); + mCursor.setOffset( offset, bit, backward, fromCursor, maxOffset ); + cursorCompute(); +} + +inline void CHexBuffer::cursorGoto( uint offset, uint bit ) +{ + mCursor.setOffset( offset ); + mCursor.setBit( bit ); + cursorCompute(); +} + +inline bool CHexBuffer::cursorChanged( void ) +{ + return( mCursor.changed() ); +} + +inline void CHexBuffer::cursorResetEditArea( void ) +{ + mCursor.setArea( edit_none ); +} + +inline bool CHexBuffer::cursorPrimaryEdit( void ) +{ + return( mActiveEditor == edit_primary ? true : false ); +} + +inline int CHexBuffer::cursorFixedPosition( int position, int height ) +{ + position += mCursor.curr.y - mCursor.prev.y; + if( position < 0 ) + { + return( 0 ); + } + else if( position + height > totalHeight() ) + { + return( height > totalHeight() ? 0 : totalHeight() - height ); + } + else + { + if( mCursor.curr.y < position ) + { + return( mCursor.curr.y ); + } + else if( mCursor.curr.y > position + height ) + { + return( mCursor.curr.y - height + lineHeight() ); + } + else + { + return( position ); + } + } +} + +inline int CHexBuffer::cursorChangePosition( int position, int height ) +{ + if( mCursor.curr.y < position || mCursor.curr.y > position + height ) + { + // When cursor is at top of window + position = mCursor.curr.y; + } + else if( mCursor.curr.y > position + height - lineHeight() ) + { + // When cursor is at bottom of window + position = mCursor.curr.y - height + lineHeight(); + } + + return( position ); +} + +inline int CHexBuffer::printDummyCell( char *buf, unsigned char ) +{ + buf[0] = 0; + return( 0 ); +} + +inline int CHexBuffer::printHexadecimalBigCell( char *buf, unsigned char data ) +{ + buf[0] = mHexBigBuffer[ (data>>4)&0x0F ]; + buf[1] = mHexBigBuffer[ data&0x0F ]; + return( 0 ); +} + +inline int CHexBuffer::printHexadecimalSmallCell( char *buf, + unsigned char data ) +{ + buf[0] = mHexSmallBuffer[ (data>>4)&0x0F ]; + buf[1] = mHexSmallBuffer[ data&0x0F ]; + return( 0 ); +} + + +inline int CHexBuffer::printDecimalCell( char *buf, unsigned char data ) +{ + buf[0] = mDecBuffer[ data/100 ]; + data -= (data/100) * 100; + buf[1] = mDecBuffer[ data/10 ]; + data -= (data/10) * 10; + buf[2] = mDecBuffer[ data ]; + return( 0 ); +} + +inline int CHexBuffer::printOctalCell( char *buf, unsigned char data ) +{ + buf[0] = mOctBuffer[ (data>>6)&0x07 ]; + buf[1] = mOctBuffer[ (data>>3)&0x07 ]; + buf[2] = mOctBuffer[ data&0x07 ]; + return( 0 ); +} + +inline int CHexBuffer::printBinaryCell( char *buf, unsigned char data ) +{ + for( int i = 0; i < 8; i++ ) + { + buf[7-i] = (data&(1<<i)) ? '1' : '0'; + } + return( 0 ); +} + +inline int CHexBuffer::printAsciiCell( char *buf, unsigned char data ) +{ + if( mCharValid[data] == 0 ) + { + buf[0] = mFontInfo.nonPrintChar; + return( 1 ); + } + else + { + buf[0] = data; + return( 0 ); + } +} + +inline void CHexBuffer::printDummyOffset( char *buf, uint /*offset*/ ) +{ + buf[0] = 0; +} + +inline void CHexBuffer::printHexadecimalBigOffset( char *buf, uint offset ) +{ + sprintf( buf, "%04X:%04X", offset>>16, offset&0x0000FFFF ); +} + +inline void CHexBuffer::printHexadecimalSmallOffset( char *buf, uint offset ) +{ + sprintf( buf, "%04x:%04x", offset>>16, offset&0x0000FFFF ); +} + +inline void CHexBuffer::printDecimalOffset( char *buf, uint offset ) +{ + sprintf( buf, "%010u", offset ); +} + +inline int CHexBuffer::lineSize( void ) +{ + return( mLayout.lineSize ); +} + +inline int CHexBuffer::lineHeight( void ) +{ + return( mFontHeight + mLayout.horzGridWidth ); +} + +inline int CHexBuffer::fontAscent( void ) +{ + return( mFontAscent ); +} + +inline int CHexBuffer::lineWidth( void ) +{ + return( mLineWidth ); +} + +inline int CHexBuffer::unitWidth( void ) +{ + return( mUnitWidth ); +} + +inline int CHexBuffer::numLines( void ) +{ + return( mNumLines ); +} + +inline int CHexBuffer::totalHeight( void ) +{ + return( mNumLines * (mFontHeight+mLayout.horzGridWidth) ); +} + +inline const QFont &CHexBuffer::font( void ) +{ + return( mFontInfo.font ); +} + +inline SCursor *CHexBuffer::textCursor( void ) +{ + return( &mCursor ); +} + +inline const QColor &CHexBuffer::backgroundColor( void ) +{ + return( documentPresent() == true ? mColor.textBg : mColor.inactiveBg ); +} + +inline int CHexBuffer::startX( void ) +{ + return( mStartX ); +} + +inline int CHexBuffer::startY( void ) +{ + return( mStartY ); +} + +inline void CHexBuffer::setStartX( int val ) +{ + mStartX = val; +} + +inline void CHexBuffer::setStartY( int val ) +{ + mStartY = val; +} + + + +#endif + diff --git a/khexedit/hexclipboard.cc b/khexedit/hexclipboard.cc new file mode 100644 index 0000000..0de70d6 --- /dev/null +++ b/khexedit/hexclipboard.cc @@ -0,0 +1,254 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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. + * + */ + +// +// This is a VERY crude implementation, which serves my requirements and +// nothing more. +// + + +#include <string.h> +#include "hexclipboard.h" + + +static const uchar *base64EncodeTable( void ) +{ + static uchar table[64] = + { + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', + }; + + return( table ); +} + +static const uchar *base64DecodeTable( void ) +{ + static uchar table[255]; + static bool init = false; + if( init == false ) + { + uint i; + for( i = 0; i < 255; i++ ) { table[i] = 0x80; } + for( i = 'A'; i <= 'Z'; i++ ) { table[i] = 0 + (i - 'A'); } + for( i = 'a'; i <= 'z'; i++ ) { table[i] = 26 + (i - 'a'); } + for( i = '0'; i <= '9'; i++ ) { table[i] = 52 + (i - '0'); } + table[(uchar)'+'] = 62; + table[(uchar)'/'] = 63; + table[(uchar)'='] = 0; + init = true; + } + return( table ); +} + + +static const char *mimeHeader( void ) +{ + static const char *data = + "Content-Type: application/octet-stream; " \ + "name=\"khexedit_copy\"\r\n" \ + "Content-Transfer-Encoding: base64\r\n\r\n"; + return( data ); +} + + + + + + + + +CHexClipboard::CHexClipboard( void ) +{ +} + + +CHexClipboard::~CHexClipboard( void ) +{ +} + + +bool CHexClipboard::encode( QByteArray &dst, QByteArray &src ) +{ + if( src.size() == 0 ) + { + return( false ); + } + + uint srcSize = src.size(); + uint mimeSize = strlen( mimeHeader() ); + uint lineSize = 72; + uint dstSize = (srcSize / 3 + (srcSize % 3 ? 1 : 0)) * 4; + dstSize += ((dstSize/lineSize) + 1)*2 + 1; + + dst.resize( dstSize + mimeSize + 1 ); + if( dst.isNull() == true ) + { + return( false ); + } + + unsigned char inBuf[3], outBuf[4]; + uint lineLen = 0; + + memcpy( dst.data(), mimeHeader(), mimeSize ); + uint j = mimeSize; + + + const uchar *table = base64EncodeTable(); + for( uint i=0; i < srcSize; i += 3 ) + { + memset( inBuf, 0, sizeof(inBuf) ); + uint n; + for( n=0; n < 3; n++ ) + { + if( i+n >= srcSize ) + { + break; + } + inBuf[n] = src[i+n]; + } + + if( n > 0 ) + { + outBuf[0] = table[ inBuf[0] >> 2 ]; + outBuf[1] = table[ ((inBuf[0] & 0x3) << 4) | (inBuf[1] >> 4) ]; + outBuf[2] = table[ ((inBuf[1] & 0xF) << 2) | (inBuf[2] >> 6) ]; + outBuf[3] = table[ inBuf[2] & 0x3F ]; + + if( n < 3 ) + { + outBuf[3] = '='; + if( n < 2 ) + { + outBuf[2] = '='; + } + } + + for( uint m=0; m<4; m++ ) + { + if( lineLen >= lineSize ) + { + dst[j++] = '\r'; + dst[j++] = '\n'; + lineLen = 0; + } + dst[j++] = outBuf[m]; + lineLen += 1; + } + } + } + dst[j++] = '\r'; + dst[j++] = '\n'; + dst[j++] = '\0'; + return( true ); +} + + + + +bool CHexClipboard::decode( QByteArray &dst, QString &src ) +{ + uint mimeSize = strlen( mimeHeader() ); + if( src.length() <= mimeSize ) + { + return( plainDecode( dst, src ) ); + } + + if( memcmp( src.ascii(), mimeHeader(), mimeSize ) != 0 ) + { + return( plainDecode( dst, src ) ); + } + + uint srcSize = src.length(); + uint dstSize = (srcSize * 3) / 4; + uchar srcBuf[4], valBuf[4], dstBuf[3]; + uint sumElement = 0; + + dst.resize( dstSize ); + if( dst.isNull() == true ) + { + return( plainDecode( dst, src ) ); + } + + uint i,j; + uint n = 0; + + const uchar *table = base64DecodeTable(); + for( i=mimeSize; i<srcSize; ) + { + for( j=0; j<4; ) + { + if( i >= srcSize ) + { + dst.truncate( sumElement ); + return( j > 0 ? false : true ); + } + + int c = src[i++].latin1(); + if( c <= ' ' ) + { + continue; + } + if( table[c] & 0x80 ) + { + return( plainDecode( dst, src ) ); + } + + srcBuf[j] = c; + valBuf[j] = table[c]; + j++; + } + + dstBuf[0] = (valBuf[0] << 2) | (valBuf[1] >> 4); + dstBuf[1] = (valBuf[1] << 4) | (valBuf[2] >> 2); + dstBuf[2] = (valBuf[2] << 6) | (valBuf[3]); + + uint numElement = srcBuf[2] == '=' ? 1 : (srcBuf[3] == '=' ? 2 : 3); + for( uint m=0; m < numElement; m++ ) + { + dst[n++] = dstBuf[m]; + } + sumElement += numElement; + + if( numElement < 3 ) + { + break; + } + } + + dst.truncate( sumElement ); + return( true ); +} + + +bool CHexClipboard::plainDecode( QByteArray &dst, QString &src ) +{ + dst.resize( src.length() ); + if( dst.isNull() == true ) + { + return( false ); + } + + for( uint i=0; i < src.length(); dst[i] = src[i].latin1(), i++ ); + return( true ); +} + diff --git a/khexedit/hexclipboard.h b/khexedit/hexclipboard.h new file mode 100644 index 0000000..9a7710d --- /dev/null +++ b/khexedit/hexclipboard.h @@ -0,0 +1,40 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_CLIPBOARD_H_ +#define _HEX_CLIPBOARD_H_ + +#include <qstring.h> + +class CHexClipboard +{ + public: + CHexClipboard( void ); + ~CHexClipboard( void ); + + bool encode( QByteArray &dst, QByteArray &src ); + bool decode( QByteArray &dst, QString &src ); + + private: + bool plainDecode( QByteArray &dst, QString &src ); +}; + + +#endif diff --git a/khexedit/hexdrag.cc b/khexedit/hexdrag.cc new file mode 100644 index 0000000..d09b28d --- /dev/null +++ b/khexedit/hexdrag.cc @@ -0,0 +1,130 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + + +#include "hexdrag.h" +static const char *mediaString = "application/octet-stream"; + + +CHexDrag::CHexDrag( const QByteArray &data, QWidget *dragSource, + const char *name ) + :QDragObject(dragSource,name) +{ + setData( data ); + prepPixmap(); +} + + +CHexDrag::CHexDrag( QWidget *dragSource, const char *name ) + :QDragObject(dragSource,name) +{ + prepPixmap(); +} + + +void CHexDrag::setData( const QByteArray &data ) +{ + mData = data; +} + + + +void CHexDrag::prepPixmap(void) +{ + // + // Wont use it yet, + // + /* + KIconLoader &loader = *KGlobal::iconLoader(); + QPixmap pix = loader.loadIcon( "binary.xpm" ); + + QPoint hotspot( pix.width()-20,pix.height()/2 ); + setPixmap( pix, hotspot ); + */ +} + + +const char *CHexDrag::format( int i ) const +{ + if( i == 0 ) + { + return( mediaString ); + } + else + { + return( 0 ); + } + return( i == 0 ? mediaString : 0 ); +} + + +QByteArray CHexDrag::encodedData( const char *fmt ) const +{ + if( fmt != 0 ) + { + if( strcmp( fmt, mediaString) == 0 ) + { + return( mData ); + } + } + + QByteArray buf; + return( buf ); +} + + +bool CHexDrag::canDecode( const QMimeSource *e ) +{ + return( e->provides(mediaString) ); +} + + +bool CHexDrag::decode( const QMimeSource *e, QByteArray &dest ) +{ + dest = e->encodedData(mediaString); + return( dest.size() == 0 ? false : true ); + + // + // I get an + // "X Error: BadAtom (invalid Atom parameter) 5 + // Major opcode: 17" + // + // if I try to use the code below on a source that has been + // collected from QClipboard. It is the e->provides(mediaString) + // that fail (Qt-2.0). Sometimes it works :( + // + // printf("0: %s\n", e->format(0) ); No problem. + // printf("1: %s\n", e->format(1) ); Crash. + // + #if 0 + if( e->provides(mediaString) == true ) + { + dest = e->encodedData(mediaString); + return( true ); + } + else + { + return( false ); + } + #endif +} + + +#include "hexdrag.moc" diff --git a/khexedit/hexdrag.h b/khexedit/hexdrag.h new file mode 100644 index 0000000..b29b197 --- /dev/null +++ b/khexedit/hexdrag.h @@ -0,0 +1,54 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_DRAG_H_ +#define _HEX_DRAG_H_ + + +#include <qdragobject.h> +#include <qstring.h> + +class CHexDrag : public QDragObject +{ + Q_OBJECT + + public: + CHexDrag( const QByteArray &data, QWidget *dragSource = 0, + const char *name = 0 ); + CHexDrag( QWidget *dragSource = 0, const char *name = 0 ); + + void setData( const QByteArray &data ); + const char* format ( int i ) const; + QByteArray encodedData( const char *fmt ) const; + + + static bool canDecode( const QMimeSource *e ); + static bool decode( const QMimeSource *e, QByteArray &dest ); + + private: + void prepPixmap( void ); + + private: + QByteArray mData; + +}; + + +#endif diff --git a/khexedit/hexeditorwidget.cc b/khexedit/hexeditorwidget.cc new file mode 100644 index 0000000..16b62a4 --- /dev/null +++ b/khexedit/hexeditorwidget.cc @@ -0,0 +1,2443 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + + +#include <iostream> +#include <unistd.h> + +#undef Unsorted + +#include <kfiledialog.h> +#include <kglobalsettings.h> +#include <kio/netaccess.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ktempfile.h> +#include <kpushbutton.h> +#include <kstdguiitem.h> + +#include "chartabledialog.h" +#include "converterdialog.h" +#include "dialog.h" +#include "exportdialog.h" +#include "fileinfodialog.h" +#include "hexeditorwidget.h" +#include "hexerror.h" +#include "optiondialog.h" +#include "printdialogpage.h" +#include "stringdialog.h" + + + + +CHexEditorWidget::CHexEditorWidget( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + CHexBuffer *hexBuffer = new CHexBuffer; + if( hexBuffer == 0 ) { return; } + + mDocumentList.setAutoDelete( true ); + mDocumentList.append( hexBuffer ); + mUntitledCount = 1; + + mHexView = new CHexViewWidget( this, "hexview", hexBuffer ); + if( mHexView == 0 || mHexView->widgetValid() == false ) { return; } + + connect( mHexView, SIGNAL(pleaseOpenNewFile()), SLOT( newFile()) ); + connect( mHexView, SIGNAL(pleaseOpenFile( const QString&, bool, uint )), + SLOT( open(const QString&, bool, uint)) ); + connect( mHexView, SIGNAL(pleaseStepFile(bool)), SLOT( stepFile(bool)) ); + connect( kapp, SIGNAL( kdisplayFontChanged() ), SLOT( fontChanged() ) ); + connect( kapp, SIGNAL( kdisplayPaletteChanged() ),SLOT( paletteChanged()) ); + connect( mHexView, SIGNAL( layoutChanged( const SDisplayLayout & ) ), + SLOT( layoutChanged( const SDisplayLayout & ) ) ); + connect( mHexView, SIGNAL( inputModeChanged( const SDisplayInputMode & ) ), + this, SLOT( inputModeChanged( const SDisplayInputMode & ) ) ); + + mHexView->setFocus(); + setBackgroundColor( palette().active().base() ); + + mProgressBusy = false; + mGotoDialog = 0; + mFindDialog = 0; + mReplaceDialog = 0; + mInsertDialog = 0; + mFilterDialog = 0; + mOptionDialog = 0; + mStringDialog = 0; + mCharTableDialog = 0; + mFileInfoDialog = 0; + mExportDialog = 0; + mConverterDialog = 0; + mFindNavigatorDialog = 0; + mReplacePromptDialog = 0; +} + +CHexEditorWidget::~CHexEditorWidget( void ) +{ + delete mHexView; + delete mGotoDialog; + delete mFindDialog; + delete mReplaceDialog; + delete mInsertDialog; + delete mFilterDialog; + delete mOptionDialog; + delete mStringDialog; + delete mCharTableDialog; + delete mFileInfoDialog; + delete mExportDialog; + delete mConverterDialog; + delete mFindNavigatorDialog; + delete mReplacePromptDialog; +} + + +void CHexEditorWidget::initialize( void ) +{ + setColor( mDisplayState.color ); + setFont( mDisplayState.font ); + mHexView->setMisc( mDisplayState.misc ); + mHexView->setCursor( mDisplayState.cursor, false ); + mHexView->setLayout( mDisplayState.layout ); + mHexView->setInputMode( mDisplayState.input ); + mHexView->setInsertMode( mDisplayState.misc.insertMode ); +} + + +void CHexEditorWidget::writeConfiguration( KConfig &config ) +{ + SDisplayLayout &layout = mDisplayState.layout; + config.setGroup( "Display Options" ); + config.writeEntry( "PrimaryMode", layout.primaryModeString() ); + config.writeEntry( "SecondaryMode", layout.secondaryModeString() ); + config.writeEntry( "OffsetMode", layout.offsetModeString() ); + config.writeEntry( "OffsetVisible", layout.offsetVisible ); + config.writeEntry( "PrimaryUpperCase", layout.primaryUpperCase ); + config.writeEntry( "OffsetUpperCase", layout.offsetUpperCase ); + config.writeEntry( "LineSize", layout.lineSize ); + config.writeEntry( "ColumnSize", layout.columnSize ); + config.writeEntry( "LockLine", layout.lockLine ); + config.writeEntry( "LockColumn", layout.lockColumn ); + config.writeEntry( "ColumnCharSpace", layout.columnCharSpace ); + config.writeEntry( "ColumnSpacing", layout.columnSpacing ); + config.writeEntry( "SeparatorMarginWidth", layout.separatorMarginWidth ); + config.writeEntry( "EdgeMarginWidth", layout.edgeMarginWidth ); + config.writeEntry( "LeftSeparatorWidth", layout.leftSeparatorWidth ); + config.writeEntry( "RightSeparatorWidth", layout.rightSeparatorWidth ); + config.writeEntry( "GridMode", layout.gridModeString() ); + + SDisplayLine &line = mDisplayState.line; + config.setGroup( "Line Size" ); + config.writeEntry( "Hexadecimal",line.lineSize[SDisplayLine::hexadecimal] ); + config.writeEntry( "Decimal", line.lineSize[SDisplayLine::decimal] ); + config.writeEntry( "Octal", line.lineSize[SDisplayLine::octal] ); + config.writeEntry( "Binary", line.lineSize[SDisplayLine::binary] ); + config.writeEntry( "TextOnly", line.lineSize[SDisplayLine::textOnly] ); + config.setGroup( "Column Size" ); + config.writeEntry( "Hexadecimal",line.columnSize[SDisplayLine::hexadecimal]); + config.writeEntry( "Decimal", line.columnSize[SDisplayLine::decimal] ); + config.writeEntry( "Octal", line.columnSize[SDisplayLine::octal] ); + config.writeEntry( "Binary", line.columnSize[SDisplayLine::binary] ); + config.writeEntry( "TextOnly", line.columnSize[SDisplayLine::textOnly] ); + + SDisplayColor &color = mDisplayState.color; + config.setGroup( "Display Colors" ); + config.writeEntry( "UseSystemColor", color.useSystemColor ); + config.writeEntry( "TextBg", color.textBg ); + config.writeEntry( "SecondTextBg", color.secondTextBg ); + config.writeEntry( "OffsetBg", color.offsetBg ); + config.writeEntry( "InactiveBg", color.inactiveBg ); + config.writeEntry( "PrimaryFg1", color.primaryFg[0] ); + config.writeEntry( "PrimaryFg2", color.primaryFg[1] ); + config.writeEntry( "OffsetFg", color.offsetFg ); + config.writeEntry( "SecondaryFg", color.secondaryFg ); + config.writeEntry( "MarkBg", color.markBg ); + config.writeEntry( "MarkFg", color.markFg ); + config.writeEntry( "LeftSeparatorFg", color.leftSeparatorFg ); + config.writeEntry( "RightSeparatorFg", color.leftSeparatorFg ); + config.writeEntry( "NonPrintFg", color.nonPrintFg ); + config.writeEntry( "CursorBg", color.cursorBg ); + config.writeEntry( "CursorFg", color.cursorFg ); + config.writeEntry( "GridFg", color.gridFg ); + config.writeEntry( "BookmarkBg", color.bookmarkBg ); + config.writeEntry( "BookmarkFg", color.bookmarkFg ); + + SDisplayFont &font = mDisplayState.font; + config.setGroup( "Display Font" ); + config.writeEntry( "UseSystemFont", font.useSystemFont ); + config.writeEntry( "LocalFont", font.localFont ); + config.writeEntry( "NonPrintChar", font.nonPrintChar.unicode() ); + + SDisplayCursor &cursor = mDisplayState.cursor; + config.setGroup( "Display Cursor" ); + config.writeEntry( "NeverBlink", cursor.alwaysVisible ); + config.writeEntry( "AlwaysBlockShape", cursor.alwaysBlockShape ); + config.writeEntry( "ThickInsertShape", cursor.thickInsertShape ); + config.writeEntry( "FocusMode", cursor.focusModeString() ); + config.writeEntry( "Interval", cursor.interval ); + + SDisplayMisc &misc = mDisplayState.misc; + config.setGroup( "Display Misc" ); + config.writeEntry( "UndoLevel", misc.undoLevel ); + config.writeEntry( "OpenFile", misc.openFileString() ); + config.writeEntry( "InputSound", misc.inputSound ); + config.writeEntry( "FatalSound", misc.fatalSound ); + config.writeEntry( "AutoCopyToClipboard", misc.autoCopyToClipboard ); + config.writeEntry( "InsertMode", misc.insertMode ); + config.writeEntry( "WriteProtect", misc.writeProtect ); + config.writeEntry( "ConfirmWrap", misc.confirmWrap ); + config.writeEntry( "CursorJump", misc.cursorJump ); + config.writeEntry( "MakeBackup", misc.makeBackup ); + config.writeEntry( "ConfirmThreshold", misc.confirmThreshold ); + config.writeEntry( "ThresholdValue", misc.thresholdValue ); + config.writeEntry( "DiscardRecent", misc.discardRecent ); + config.writeEntry( "GotoOnStartup", misc.gotoOnStartup ); + config.writeEntry( "GotoOnReload", misc.gotoOnReload ); + config.writeEntry( "ShowBookmarkInOffsetColumn", misc.bookmarkOffsetColumn ); + config.writeEntry( "ShowBookmarkInEditor", misc.bookmarkEditor ); + + if( mExportDialog != 0 ) + { + mExportDialog->writeConfiguration(); + } +} + +void CHexEditorWidget::readConfiguration( KConfig &config ) +{ + SDisplayLayout &layout = mDisplayState.layout; + config.setGroup( "Display Options" ); + layout.setPrimaryMode( config.readEntry("PrimaryMode") ); + layout.setSecondaryMode( config.readEntry("SecondaryMode") ); + layout.setOffsetMode( config.readEntry("OffsetMode") ); + layout.offsetVisible = config.readBoolEntry( + "OffsetVisible", layout.offsetVisible ); + layout.primaryUpperCase = config.readBoolEntry( + "PrimaryUpperCase", layout.primaryUpperCase ); + layout.offsetUpperCase = config.readBoolEntry( + "OffsetUpperCase", layout.offsetUpperCase ); + layout.lineSize = config.readNumEntry( + "LineSize", layout.lineSize ); + layout.columnSize = config.readNumEntry( + "ColumnSize", layout.columnSize ); + layout.lockLine = config.readBoolEntry( + "LockLine", layout.lockLine ); + layout.lockColumn = config.readBoolEntry( + "LockColumn", layout.lockColumn ); + layout.columnCharSpace = config.readBoolEntry( + "ColumnCharSpace", layout.columnCharSpace ); + layout.columnSpacing = config.readNumEntry( + "ColumnSpacing", layout.columnSpacing ); + layout.separatorMarginWidth = config.readNumEntry( + "SeparatorMarginWidth", layout.separatorMarginWidth ); + layout.edgeMarginWidth = config.readNumEntry( + "EdgeMarginWidth", layout.edgeMarginWidth ); + layout.leftSeparatorWidth = config.readNumEntry( + "LeftSeparatorWidth", layout.leftSeparatorWidth ); + layout.rightSeparatorWidth = config.readNumEntry( + "RightSeparatorWidth", layout.rightSeparatorWidth ); + layout.setGridMode( config.readEntry("GridMode") ); + + SDisplayLine &line = mDisplayState.line; + config.setGroup( "Line Size" ); + line.lineSize[SDisplayLine::hexadecimal] = config.readUnsignedNumEntry( + "Hexadecimal", line.lineSize[SDisplayLine::hexadecimal] ); + line.lineSize[SDisplayLine::decimal] = config.readUnsignedNumEntry( + "Decimal", line.lineSize[SDisplayLine::decimal] ); + line.lineSize[SDisplayLine::octal] = config.readUnsignedNumEntry( + "Octal", line.lineSize[SDisplayLine::octal] ); + line.lineSize[SDisplayLine::binary] = config.readUnsignedNumEntry( + "Binary", line.lineSize[SDisplayLine::binary] ); + line.lineSize[SDisplayLine::textOnly] = config.readUnsignedNumEntry( + "TextOnly", line.lineSize[SDisplayLine::textOnly] ); + config.setGroup( "Column Size" ); + line.columnSize[SDisplayLine::hexadecimal] = config.readUnsignedNumEntry( + "Hexadecimal", line.columnSize[SDisplayLine::hexadecimal] ); + line.columnSize[SDisplayLine::decimal] = config.readUnsignedNumEntry( + "Decimal", line.columnSize[SDisplayLine::decimal] ); + line.columnSize[SDisplayLine::octal] = config.readUnsignedNumEntry( + "Octal", line.columnSize[SDisplayLine::octal] ); + line.columnSize[SDisplayLine::binary] = config.readUnsignedNumEntry( + "Binary", line.columnSize[SDisplayLine::binary] ); + line.columnSize[SDisplayLine::textOnly] = config.readUnsignedNumEntry( + "TextOnly", line.columnSize[SDisplayLine::textOnly] ); + + SDisplayFont &font = mDisplayState.font; + config.setGroup( "Display Font" ); + font.useSystemFont = config.readBoolEntry( + "UseSystemFont", true ); + font.localFont = config.readFontEntry( + "LocalFont", &font.localFont ); + font.nonPrintChar = config.readNumEntry( + "NonPrintChar", font.nonPrintChar ); + + SDisplayColor &color = mDisplayState.color; + config.setGroup( "Display Colors" ); + color.useSystemColor = config.readBoolEntry( + "UseSystemColor", color.useSystemColor ); + color.textBg = config.readColorEntry( + "TextBg", &color.textBg ); + color.secondTextBg = config.readColorEntry( + "SecondTextBg", &color.secondTextBg ); + color.offsetBg = config.readColorEntry( + "OffsetBg", &color.offsetBg ); + color.inactiveBg = config.readColorEntry( + "InactiveBg", &color.inactiveBg ); + color.primaryFg[0] = config.readColorEntry( + "PrimaryFg1", &color.primaryFg[0] ); + color.primaryFg[1] = config.readColorEntry( + "PrimaryFg2", &color.primaryFg[1] ); + color.offsetFg = config.readColorEntry( + "OffsetFg", &color.offsetFg ); + color.secondaryFg = config.readColorEntry( + "SecondaryFg", &color.secondaryFg ); + color.markBg = config.readColorEntry( + "MarkBg", &color.markBg ); + color.markFg = config.readColorEntry( + "MarkFg", &color.markFg ); + color.cursorBg = config.readColorEntry( + "CursorBg", &color.cursorBg ); + color.cursorFg = config.readColorEntry( + "CursorFg", &color.cursorFg ); + color.leftSeparatorFg = config.readColorEntry( + "LeftSeparatorFg", &color.leftSeparatorFg ); + color.rightSeparatorFg = config.readColorEntry( + "RightSeparatorFg", &color.rightSeparatorFg ); + color.nonPrintFg = config.readColorEntry( + "NonPrintFg", &color.nonPrintFg ); + color.gridFg = config.readColorEntry( + "GridFg", &color.gridFg ); + color.bookmarkBg = config.readColorEntry( + "BookmarkBg", &color.bookmarkBg ); + color.bookmarkFg = config.readColorEntry( + "BookmarkFg", &color.bookmarkFg ); + + SDisplayCursor &cursor = mDisplayState.cursor; + config.setGroup( "Display Cursor" ); + cursor.alwaysVisible = config.readBoolEntry( + "NeverBlink", cursor.alwaysVisible ); + cursor.alwaysBlockShape = config.readBoolEntry( + "AlwaysBlockShape", cursor.alwaysBlockShape ); + cursor.thickInsertShape = config.readBoolEntry( + "ThickInsertShape", cursor.thickInsertShape ); + cursor.setFocusMode( config.readEntry("FocusMode") ); + cursor.interval = config.readNumEntry( + "Interval", cursor.interval ); + + SDisplayMisc &misc = mDisplayState.misc; + config.setGroup( "Display Misc" ); + misc.undoLevel = config.readNumEntry( + "UndoLevel", misc.undoLevel ); + misc.setOpenFile( config.readEntry("OpenFile") ); + misc.inputSound = config.readBoolEntry( + "InputSound", misc.inputSound ); + misc.fatalSound = config.readBoolEntry( + "FatalSound", misc.fatalSound ); + misc.autoCopyToClipboard = config.readBoolEntry( + "AutoCopyToClipboard", misc.autoCopyToClipboard ); + misc.insertMode = config.readBoolEntry( + "InsertMode", misc.insertMode ); + misc.writeProtect = config.readBoolEntry( + "WriteProtect", misc.writeProtect ); + misc.confirmWrap = config.readBoolEntry( + "ConfirmWrap", misc.confirmWrap ); + misc.cursorJump = config.readBoolEntry( + "CursorJump", misc.cursorJump ); + misc.makeBackup = config.readBoolEntry( + "MakeBackup", misc.makeBackup ); + misc.confirmThreshold = config.readBoolEntry( + "ConfirmThreshold", misc.confirmThreshold ); + misc.thresholdValue = config.readNumEntry( + "ThresholdValue", misc.thresholdValue ); + misc.discardRecent = config.readBoolEntry( + "DiscardRecent", misc.discardRecent ); + misc.gotoOnStartup = config.readBoolEntry( + "GotoOnStartup", misc.gotoOnStartup ); + misc.gotoOnReload = config.readBoolEntry( + "GotoOnReload", misc.gotoOnReload ); + misc.bookmarkOffsetColumn = config.readBoolEntry( + "ShowBookmarkInOffsetColumn", misc.bookmarkOffsetColumn ); + misc.bookmarkEditor = config.readBoolEntry( + "ShowBookmarkInEditor", misc.bookmarkEditor ); +} + + + +void CHexEditorWidget::resizeEvent( QResizeEvent *e ) +{ + mHexView->resize( e->size().width(), e->size().height() ); +} + + +void CHexEditorWidget::fontChanged( void ) +{ + if( mDisplayState.font.useSystemFont == true ) + { + setFont( mDisplayState.font ); + } +} + +void CHexEditorWidget::paletteChanged( void ) +{ + setColor( mDisplayState.color ); +} + +void CHexEditorWidget::layoutChanged( const SDisplayLayout &/*layout*/ ) +{ + //mDisplayState.layout = layout; +} + +void CHexEditorWidget::inputModeChanged( const SDisplayInputMode &input ) +{ + mDisplayState.input = input; +} + + +void CHexEditorWidget::setLineSize(const SDisplayLine &line ) +{ + mDisplayState.line = line; +} + +void CHexEditorWidget::setLayout( const SDisplayLayout &layout ) +{ + // + // We only set the values that can be modified by the dialog + // + mDisplayState.layout.lockLine = layout.lockLine; + mDisplayState.layout.lockColumn = layout.lockColumn; + mDisplayState.layout.leftSeparatorWidth = layout.leftSeparatorWidth; + mDisplayState.layout.rightSeparatorWidth = layout.rightSeparatorWidth; + mDisplayState.layout.separatorMarginWidth = layout.separatorMarginWidth; + mDisplayState.layout.edgeMarginWidth = layout.edgeMarginWidth; + mDisplayState.layout.columnCharSpace = layout.columnCharSpace; + mDisplayState.layout.columnSpacing = layout.columnSpacing; + mDisplayState.layout.horzGridWidth = layout.horzGridWidth; + mDisplayState.layout.vertGridWidth = layout.vertGridWidth; + + // + // Select the line and column sizes we shall use now. + // + SDisplayLayout &l = mDisplayState.layout; + l.lineSize = mDisplayState.line.lineSize[ l.primaryMode ]; + l.columnSize = mDisplayState.line.columnSize[ l.primaryMode ]; + + mHexView->setLayout( mDisplayState.layout ); +} + +void CHexEditorWidget::setCursor( const SDisplayCursor &cursor ) +{ + mDisplayState.cursor = cursor; + mHexView->setCursor( mDisplayState.cursor, true ); +} + +void CHexEditorWidget::setColor( const SDisplayColor &color ) +{ + mDisplayState.color = color; + + // + // The selection colors can not be chosen. + // + mDisplayState.color.selectBg = kapp->palette().active().highlight(); + mDisplayState.color.selectFg = kapp->palette().active().highlightedText(); + + if( mDisplayState.color.useSystemColor == true ) + { + SDisplayColor c = mDisplayState.color; + c.textBg = kapp->palette().active().base(); + c.secondTextBg = kapp->palette().active().base(); + c.offsetBg = kapp->palette().active().base(); + c.inactiveBg = kapp->palette().active().base(); + c.primaryFg[0] = kapp->palette().active().text(); + c.primaryFg[1] = kapp->palette().active().text(); + c.nonPrintFg = kapp->palette().active().text(); + c.offsetFg = kapp->palette().active().text(); + c.secondaryFg = kapp->palette().active().text(); + c.leftSeparatorFg = kapp->palette().active().text(); + c.rightSeparatorFg = kapp->palette().active().text(); + c.cursorBg = kapp->palette().active().text(); + c.cursorFg = kapp->palette().active().base(); + c.gridFg = kapp->palette().active().text(); + SDisplayColor defaultColor; + c.bookmarkBg = defaultColor.bookmarkBg; + c.bookmarkFg = defaultColor.bookmarkFg; + + mHexView->setColor( c, true ); + } + else + { + mHexView->setColor( mDisplayState.color, true ); + } +} + + +void CHexEditorWidget::setFont( const SDisplayFont &font ) +{ + mDisplayState.font = font; + + SDisplayFontInfo fontInfo; + if( mDisplayState.font.useSystemFont == true ) + { + fontInfo.font = KGlobalSettings::fixedFont(); + } + else + { + fontInfo.font = mDisplayState.font.localFont; + } + fontInfo.nonPrintChar = mDisplayState.font.nonPrintChar; + mHexView->setFont( fontInfo, true ); +} + +void CHexEditorWidget::setMisc( const SDisplayMisc &misc ) +{ + mDisplayState.misc = misc; + mHexView->setMisc( mDisplayState.misc ); +} + + + +void CHexEditorWidget::setHexadecimalMode( void ) +{ + layout().primaryMode = SDisplayLayout::hexadecimal; + layout().lineSize = line().lineSize[ SDisplayLine::hexadecimal ]; + layout().columnSize = line().columnSize[ SDisplayLine::hexadecimal ]; + mHexView->setLayout( layout() ); +} + + +void CHexEditorWidget::setDecimalMode( void ) +{ + layout().primaryMode = SDisplayLayout::decimal; + layout().lineSize = line().lineSize[ SDisplayLine::decimal ]; + layout().columnSize = line().columnSize[ SDisplayLine::decimal ]; + mHexView->setLayout( layout() ); +} + + +void CHexEditorWidget::setOctalMode( void ) +{ + layout().primaryMode = SDisplayLayout::octal; + layout().lineSize = line().lineSize[ SDisplayLine::octal ]; + layout().columnSize = line().columnSize[ SDisplayLine::octal ]; + mHexView->setLayout( layout() ); +} + + +void CHexEditorWidget::setBinaryMode( void ) +{ + layout().primaryMode = SDisplayLayout::binary; + layout().lineSize = line().lineSize[ SDisplayLine::binary ]; + layout().columnSize = line().columnSize[ SDisplayLine::binary ]; + mHexView->setLayout( layout() ); +} + + +void CHexEditorWidget::setTextMode( void ) +{ + layout().primaryMode = SDisplayLayout::textOnly; + layout().lineSize = line().lineSize[ SDisplayLine::textOnly ]; + layout().columnSize = line().columnSize[ SDisplayLine::textOnly ]; + mHexView->setLayout( layout() ); +} + + + +void CHexEditorWidget::saveWorkingDirectory( const QString &url ) +{ + if( url.isEmpty() == true ) + { + return; + } + + int index = url.findRev( '/' ); + if( index != -1 ) + { + mWorkDir = url.left( index+1 ); + } +} + + + +void CHexEditorWidget::newFile( void ) +{ + if( busy( true ) == true ) + { + return; + } + + QString url = i18n("Untitled %1").arg( mUntitledCount ); + + // + // If the url is already present in the document list (should not happen), + // then this document is "raised". + // + bool success = selectDocument( url, false ); + if( success == true ) + { + return; + } + + // + // Prepare a new buffer we can load the document into + // + success = createBuffer(); + if( success == false ) + { + return; + } + + int errCode = mHexView->newFile( url ); + if( errCode != Err_Success ) + { + QString msg = i18n("Unable to create new document."); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Operation Failed") ); + return; + } + + mUntitledCount += 1; +} + + + + +void CHexEditorWidget::newFile( const QByteArray &data ) +{ + newFile(); + mHexView->append( data ); +} + + + + +void CHexEditorWidget::open() +{ + KURL file = KFileDialog::getOpenURL( mWorkDir, "*" ,topLevelWidget() ); + + if( file.isEmpty() ) + return; + + QString url = file.url(); + + saveWorkingDirectory( url ); + + if( busy( true ) ) + return; + + // + // If the url is already present in the document list, then this + // document is "raised". + // + if( selectDocument( url, true ) ) + return; + + // + // Prepare a new buffer we can load the document into + // + if( !createBuffer() ) + return; + + int errCode = readURL( file, false ); + if( errCode != Err_Success ) + { + emit errorLoadFile( url ); + removeBuffer(); + } + else if( errCode == Err_Success ) + { + defaultWriteProtection(); + } +} + + + +void CHexEditorWidget::open( const QString &url, bool reloadWhenChanged, + uint offset ) +{ + if( busy( true ) == true ) + { + return; + } + + // + // If the url is already present in the document list, then this + // document is "raised". + // + bool success = selectDocument( url, reloadWhenChanged ); + if( success == true ) + { + return; + } + + // + // Prepare a new buffer we can load the document into + // + success = createBuffer(); + if( success == false ) + { + return; + } + + int errCode = readURL( url, false ); + if( errCode != Err_Success ) + { + emit errorLoadFile( url ); + removeBuffer(); + } + else if( errCode == Err_Success ) + { + mHexView->gotoOffset( offset ); + defaultWriteProtection(); + } +} + + +void CHexEditorWidget::stepFile( bool next ) +{ + // + // The buffer list is is reverse when compared with the visible + // document list in the menu so I toggle the flag. + // + next = next == true ? false : true; + + CHexBuffer *hexBuffer = documentItem( mHexView->url(), next ); + if( hexBuffer == 0 ) + { + return; + } + + mHexView->setBuffer( hexBuffer ); +} + + + + + +bool CHexEditorWidget::isOpen( const QString &url, uint &offset ) +{ + CHexBuffer *hexBuffer = documentItem( url ); + if( hexBuffer == 0 ) + { + return( false ); + } + offset = hexBuffer->cursorOffset(); + return( true ); +} + + +bool CHexEditorWidget::selectDocument( const QString &url, + bool reloadWhenChanged ) +{ + CHexBuffer *hexBuffer = documentItem( url ); + if( hexBuffer == 0 ) + { + return( false ); + } + + mHexView->setBuffer( hexBuffer ); + + if( reloadWhenChanged == true && mHexView->urlValid() == true ) + { + if( modifiedByAlien( mHexView->url() ) == true ) + { + reload(); + } + } + + return( true ); +} + + +void CHexEditorWidget::insertFile( void ) +{ + KFileDialog fdlg(mWorkDir, QString::null, topLevelWidget(), 0, TRUE); + fdlg.setOperationMode( KFileDialog::Opening ); + fdlg.okButton()->setGuiItem( KStdGuiItem::insert() ); + fdlg.setCaption(i18n("Insert File")); + + if (!fdlg.exec()) return; + KURL file = fdlg.selectedURL(); + + if( file.isEmpty() ) + return; + + if( !file.isLocalFile() ) + { + KMessageBox::sorry( this, i18n( "Only local files are currently supported." ) ); + return; + } + + QString url = file.path(); + + saveWorkingDirectory( url ); + + if( busy( true ) ) + return; + + readURL( url, true ); +} + + + +void CHexEditorWidget::stop( void ) +{ + mProgressStop = mProgressBusy; +} + + +bool CHexEditorWidget::close( void ) +{ + if( busy( true ) == true ) + { + return( false ); + } + + if( querySave() == false ) + { + return( false ); + } + + removeBuffer(); + return( true ); +} + + + + +bool CHexEditorWidget::closeAll( void ) +{ + if( busy( true ) == true ) + { + return( false ); + } + + while( mDocumentList.count() > 0 ) + { + CHexBuffer *buf; + for( buf = mDocumentList.first(); buf != 0; buf = mDocumentList.next() ) + { + // + // We select the buffer we are about to close because it will + // the become visible, and because 'close()' works on the current + // buffer. + // + mHexView->setBuffer( buf ); + if( close() == false ) + { + return( false ); + } + } + + // + // The document list will always contain at least one element because + // the hexview widget needs a hexbuffer to work. If this hexbuffer is + // not valid, then all files have been closed. + // + if( mDocumentList.count() == 1 && mHexView->documentPresent() == false ) + { + break; + } + } + + return( true ); +} + + + +bool CHexEditorWidget::querySave( void ) +{ + if( mHexView->modified() == false ) + { + return( true ); + } + + QString msg = i18n("" + "The current document has been modified.\n" + "Do you want to save it?" ); + int reply = KMessageBox::warningYesNoCancel( topLevelWidget(), msg, QString::null, KStdGuiItem::save(), KStdGuiItem::discard() ); + if( reply == KMessageBox::Yes ) + { + return( save() ); + } + else if( reply == KMessageBox::No ) + { + return( true ); + } + else + { + return( false ); + } +} + + +bool CHexEditorWidget::backup( void ) +{ + if( mHexView->documentPresent() == false || mHexView->urlValid() == false ) + { + return( false ); + } + + KURL kurl( mHexView->url() ); + if( kurl.isLocalFile() == false ) + { + return( false ); + } + + const QString currentName = kurl.path(); + QString backupName = currentName + '~'; + + int errCode = rename( currentName.latin1(), backupName.latin1() ); + if( errCode != 0 ) + { + return( false ); + } + + + return( true ); +} + + + +// +// Returns false if operation was canceled +// +bool CHexEditorWidget::save( void ) +{ + if( mHexView->documentPresent() == false ) + { + return( true ); + } + + if( mHexView->urlValid() == false ) + { + return( saveAs() ); + } + else + { + if( modifiedByAlien( mHexView->url() ) == true ) + { + QString msg = i18n("" + "Current document has been changed on disk.\n" + "If you save now, those changes will be lost.\n" + "Proceed?" ); + int reply = KMessageBox::warningYesNoCancel( topLevelWidget(), msg, + i18n("Save"), KStdGuiItem::save(), KStdGuiItem::discard() ); + if( reply == KMessageBox::No || reply == KMessageBox::Cancel ) + { + return( reply == KMessageBox::No ? true : false ); + } + } + + if( mDisplayState.misc.makeBackup == true ) + { + backup(); + } + writeURL( mHexView->url() ); + } + + return( true ); +} + + +// +// Returns false if operation was canceled +// +bool CHexEditorWidget::saveAs( void ) +{ + if( mHexView->documentPresent() == false ) + { + return( true ); + } + + KURL url; + while( 1 ) + { + url = KFileDialog::getSaveURL( mHexView->url(), "*", this ); + if( url.isEmpty() == true ) + { + return( false ); + } + else + { + saveWorkingDirectory( url.url() ); + } + + if( url.isLocalFile() ) + { + QString name( url.path() ); + QFileInfo info( name ); + + if( info.exists() ) + { + QString msg = i18n("" + "A document with this name already exists.\n" + "Do you want to overwrite it?" ); + int reply = KMessageBox::warningContinueCancel( topLevelWidget(), msg, + i18n("Save As"), i18n("Overwrite") ); + if( reply == KMessageBox::Continue ) + break; + } + else + break; + } + } + + QString symbolicName( url.url() ); +// KURL::decode( symbolicName ); + + mHexView->setUrl( symbolicName ); + writeURL( mHexView->url() ); + return( true ); +} + + + +void CHexEditorWidget::reload( void ) +{ + if( mHexView->documentPresent() == false ) + { + return; + } + + if( busy( true ) == true ) + { + return; + } + + if( mHexView->urlValid() == false ) + { + QString msg = i18n( "The current document does not exist on the disk." ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Reload") ); + return; + } + + if( mHexView->modified() == true ) + { + QString msg; + if( modifiedByAlien( mHexView->url() ) == true ) + { + msg = i18n( "The current document has changed on the disk and " + "also contains unsaved modifications.\n" + "If you reload now, the modifications will be lost." ); + } + else + { + msg = i18n( "The current document contains unsaved modifications.\n" + "If you reload now, the modifications will be lost." ); + } + + int reply = KMessageBox::warningContinueCancel(topLevelWidget(),msg,i18n("Reload"), i18n("&Reload")); + if( reply != KMessageBox::Continue ) + { + return; + } + } + + QString url( mHexView->url() ); + uint offset = mHexView->offset(); + + //mHexView->closeFile(); + int errCode = readURL( url, false ); + if( errCode == Err_Success && gotoReloadOffset() == true ) + { + mHexView->gotoOffset( offset ); + } + +} + + +void CHexEditorWidget::print( void ) +{ + CHexPrinter prt; + + prt.addDialogPage( new LayoutDialogPage() ); + + prt.setPageSelection( KPrinter::SystemSide ); + prt.setFullPage( true ); // I use my own marings + + // FIXME: Make a better header for the printingdialog + if (prt.setup(topLevelWidget(), i18n("Print Hex-Document"))) + { + prt.setTopMarginMM( prt.option("kde-khexedit-topmarginmm").toInt() ); + prt.setBottomMarginMM( prt.option("kde-khexedit-bottommarginmm").toInt() ); + prt.setLeftMarginMM( prt.option("kde-khexedit-leftmarginmm").toInt() ); + prt.setRightMarginMM( prt.option("kde-khexedit-rightmarginmm").toInt() ); + + prt.setPageHeader( (prt.option("kde-khexedit-headercheck") == "true"), + prt.option("kde-khexedit-headercombo0").toInt(), + prt.option("kde-khexedit-headercombo1").toInt(), + prt.option("kde-khexedit-headercombo2").toInt(), + prt.option("kde-khexedit-headercombo3").toInt() ); + + prt.setPageFooter( (prt.option("kde-khexedit-footercheck") == "true"), + prt.option("kde-khexedit-footercombo0").toInt(), + prt.option("kde-khexedit-footercombo1").toInt(), + prt.option("kde-khexedit-footercombo2").toInt(), + prt.option("kde-khexedit-footercombo3").toInt() ); + + printPostscript(prt); + } + +} + + + + +void CHexEditorWidget::printPostscript( CHexPrinter &printer ) +{ + if( confirmPrintPageNumber( printer ) == false ) + { + return; + } + + // + // No i18n() on this one! + // Constants come from config.h + // + QString creator( PACKAGE ); + creator += " "; + creator += VERSION; + + printer.setCreator( creator ); + + int errCode = prepareProgressData( pg_print ); + if( errCode == Err_Success ) + { + errCode = mHexView->print( printer, mProgressData ); + } + + QString msg = i18n("Could not print data.\n"); + msg += hexError( errCode ); + + if( errCode != Err_Success ) + { + KMessageBox::sorry( topLevelWidget(), msg, i18n("Print") ); + } +} + + +bool CHexEditorWidget::confirmPrintPageNumber( CHexPrinter &printer ) +{ + if( mDisplayState.misc.confirmThreshold == true ) + { + uint numPage = mHexView->numPage( printer ); + printer.setMinMax( 1, numPage ); + uint numPageSelected = printer.pageList().count(); + + if( numPageSelected > mDisplayState.misc.thresholdValue ) + { + QString msg = i18n( + "<qt>Print threshold exceeded.<br>" + "You are about to print one page.<br>" + "Proceed?</qt>", + "<qt>Print threshold exceeded.<br>" + "You are about to print %n pages.<br>" + "Proceed?</qt>", + numPageSelected ); + int reply = KMessageBox::warningYesNo( topLevelWidget(), msg, + i18n("Print"), KStdGuiItem::print(), KStdGuiItem::cancel() ); + if( reply != KMessageBox::Continue ) + { + return( false ); + } + } + } + + return( true ); +} + + +void CHexEditorWidget::exportDialog( void ) +{ + if( mExportDialog == 0 ) + { + mExportDialog = new CExportDialog( topLevelWidget(), 0, false ); + if( mExportDialog == 0 ) { return; } + connect( mExportDialog, SIGNAL( exportText(const SExportText &)), + this, SLOT( exportText( const SExportText &)) ); + connect( mExportDialog, SIGNAL( exportHtml(const SExportHtml &)), + this, SLOT( exportHtml( const SExportHtml &)) ); + connect( mExportDialog, SIGNAL( exportCArray(const SExportCArray &)), + this, SLOT( exportCArray( const SExportCArray &)) ); + } + mExportDialog->show(); +} + + + +void CHexEditorWidget::exportText( const SExportText &ex ) +{ + int errCode = prepareProgressData( pg_export ); + if( errCode == Err_Success ) + { + errCode = mHexView->exportText( ex, mProgressData ); + } + + if( errCode != Err_Success ) + { + QString msg = i18n("Unable to export data.\n"); + msg += hexError( errCode ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Export") ); + } +} + + +void CHexEditorWidget::exportHtml( const SExportHtml &ex ) +{ + int errCode = prepareProgressData( pg_export ); + if( errCode == Err_Success ) + { + errCode = mHexView->exportHtml( ex, mProgressData ); + } + + if( errCode != Err_Success ) + { + QString msg = i18n("Unable to export data.\n"); + msg += hexError( errCode ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Export") ); + } +} + + +void CHexEditorWidget::exportCArray( const SExportCArray &ex ) +{ + int errCode = prepareProgressData( pg_export ); + if( errCode == Err_Success ) + { + errCode = mHexView->exportCArray( ex, mProgressData ); + } + + if( errCode != Err_Success ) + { + QString msg = i18n("Unable to export data.\n"); + msg += hexError( errCode ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Export") ); + } +} + + +void CHexEditorWidget::encode( CConversion::EMode mode ) +{ + if( mHexView->losslessEncoding( mode ) == false ) + { + QString msg = i18n("" + "The encoding you have selected is not reversible.\n" + "If you revert to the original encoding later, there is no " + "guarantee that the data can be restored to the original state."); + int reply = KMessageBox::warningContinueCancel( topLevelWidget(), msg, + i18n("Encode"), i18n("&Encode")); + if( reply != KMessageBox::Continue ) + { + // Restore correct menu setting + mHexView->reportEncoding(); + return; + } + } + + int errCode = prepareProgressData( pg_encode ); + if( errCode == Err_Success ) + { + errCode = mHexView->setEncoding( mode, mProgressData ); + } + + if( errCode != Err_Success ) + { + QString msg = i18n("Could not encode data.\n"); + msg += hexError( errCode ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Encode") ); + } +} + +void CHexEditorWidget::undo( void ) +{ + mHexView->undo(); +} + +void CHexEditorWidget::redo( void ) +{ + mHexView->redo(); +} + +void CHexEditorWidget::toggleWriteProtection( void ) +{ + mDisplayState.input.readOnly = mDisplayState.input.readOnly == true ? + false : true; + mHexView->setInputMode( mDisplayState.input ); +} + +void CHexEditorWidget::defaultWriteProtection( void ) +{ + mDisplayState.input.readOnly = mDisplayState.misc.writeProtect; + mHexView->setInputMode( mDisplayState.input ); +} + +void CHexEditorWidget::toggleResizeLock( void ) +{ + mDisplayState.input.allowResize = mDisplayState.input.allowResize == true ? + false : true; + mHexView->setInputMode( mDisplayState.input ); +} + +void CHexEditorWidget::setResizeLock( bool state ) +{ + mDisplayState.input.allowResize = state; + mHexView->setInputMode( mDisplayState.input ); +} + +void CHexEditorWidget::enableInputLock( bool inputLock ) +{ + mDisplayState.input.inputLock = inputLock; + mHexView->setInputMode( mDisplayState.input ); +} + +void CHexEditorWidget::toggleOffsetColumnVisibility( void ) +{ + layout().offsetVisible = layout().offsetVisible == true ? false : true; + mHexView->setLayout( layout() ); +} + +void CHexEditorWidget::toggleTextColumnVisibility( void ) +{ + layout().secondaryMode = layout().secondaryMode == SDisplayLayout::hide ? + SDisplayLayout::textOnly : SDisplayLayout::hide; + mHexView->setLayout( layout() ); +} + +void CHexEditorWidget::toggleOffsetAsDecimal( void ) +{ + layout().offsetMode = layout().offsetMode == SDisplayLayout::hexadecimal ? + SDisplayLayout::decimal : SDisplayLayout::hexadecimal; + mHexView->setLayout( layout() ); +} + +void CHexEditorWidget::toggleDataUppercase( void ) +{ + layout().primaryUpperCase = layout().primaryUpperCase == true ? false : true; + mHexView->setLayout( layout() ); +} + +void CHexEditorWidget::toggleOffsetUppercase( void ) +{ + layout().offsetUpperCase = layout().offsetUpperCase == true ? false : true; + mHexView->setLayout( layout() ); +} + +void CHexEditorWidget::toggleInsertMode( void ) +{ + mHexView->setInsertMode( !mHexView->insertMode() ); +} + +void CHexEditorWidget::benchmark( void ) +{ + mHexView->benchmark(); +} + +void CHexEditorWidget::copy( void ) +{ + mHexView->copy(); +} + +void CHexEditorWidget::copyText( void ) +{ + mHexView->copyText(); +} + +void CHexEditorWidget::paste( void ) +{ + if( mHexView->documentPresent() == false ) + { + pasteNewFile(); + } + else + { + mHexView->paste(); + } +} + +void CHexEditorWidget::pasteNewFile( void ) +{ + newFile(); + mHexView->paste(); +} + +void CHexEditorWidget::cut( void ) +{ + mHexView->cut(); +} + +void CHexEditorWidget::selectAll( void ) +{ + mHexView->selectAll(); +} + +void CHexEditorWidget::unselect( void ) +{ + mHexView->unselect(); +} + + +void CHexEditorWidget::addBookmark( void ) +{ + mHexView->addBookmark( -1 ); +} + + +void CHexEditorWidget::removeBookmark( void ) +{ + if( mHexView->bookmarkCount() > 0 ) + { + mHexView->removeBookmark( false ); + } +} + + +void CHexEditorWidget::removeAllBookmark( void ) +{ + if( mHexView->bookmarkCount() > 0 ) + { + QString msg = i18n("" + "Deleted bookmarks can not be restored.\n" + "Proceed?" ); + int reply = KMessageBox::warningContinueCancel( topLevelWidget(), msg ); + if( reply != KMessageBox::Continue ) + { + return; + } + mHexView->removeBookmark( true ); + } +} + + +void CHexEditorWidget::replaceBookmark( void ) +{ + mHexView->replaceBookmark(); +} + + +void CHexEditorWidget::gotoBookmark( int position ) +{ + mHexView->gotoBookmark( (uint)position ); +} + +void CHexEditorWidget::gotoNextBookmark( void ) +{ + mHexView->gotoNextBookmark(true); +} + +void CHexEditorWidget::gotoPrevBookmark( void ) +{ + mHexView->gotoNextBookmark(false); +} + +void CHexEditorWidget::gotoOffset( void ) +{ + if( mGotoDialog == 0 ) + { + mGotoDialog = new CGotoDialog( topLevelWidget(), 0, false ); + if( mGotoDialog == 0 ) { return; } + connect( mGotoDialog, SIGNAL(gotoOffset( uint, uint, bool, bool )), + mHexView, SLOT(gotoOffset( uint, uint, bool, bool )) ); + } + mGotoDialog->show(); +} + + +void CHexEditorWidget::find( void ) +{ + if( mFindNavigatorDialog != 0 ) + { + mFindNavigatorDialog->hide(); + } + + if( mFindDialog == 0 ) + { + mFindDialog = new CFindDialog( topLevelWidget(), 0, false ); + if( mFindDialog == 0 ) { return; } + connect( mFindDialog, + SIGNAL(findData(SSearchControl &, uint, bool)), + SLOT(findData(SSearchControl &, uint, bool)) ); + } + mFindDialog->show(); +} + + + +void CHexEditorWidget::findData( SSearchControl &sc, uint mode, bool navigator) +{ + for( uint i=0; i < 2; i++ ) + { + int errCode; + if( mode == Find_First ) + { + errCode = mHexView->findFirst( sc ); + if( errCode == Err_Success ) + { + if( navigator == true ) + { + findNavigator( sc ); + } + return; + } + } + else if( mode == Find_Next ) + { + errCode = mHexView->findNext( sc ); + if( errCode == Err_Success ) + { + if( navigator == true ) + { + findNavigator( sc ); + } + return; + } + } + else + { + return; + } + + if( errCode == Err_WrapBuffer && i == 0 ) + { + bool reply = askWrap( sc.forward, i18n("Find") ); + if( reply == false ) + { + return; + } + + sc.fromCursor = false; + mode = Find_First; + } + } + + if( mode == Find_First ) + { + QString msg = i18n( "Search key not found in document." ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Find") ); + } +} + + + +void CHexEditorWidget::findAgain( void ) +{ + if( canFind( true ) == true ) + { + mFindDialog->findAgain( CFindDialog::find_Again ); + } +} + + +void CHexEditorWidget::findNext( void ) +{ + if( canFind( true ) == true ) + { + mFindDialog->findAgain( CFindDialog::find_Next ); + } +} + + +void CHexEditorWidget::findPrevious( void ) +{ + if( canFind( true ) == true ) + { + mFindDialog->findAgain( CFindDialog::find_Previous ); + } +} + + +bool CHexEditorWidget::askWrap( bool fwd, const QString &header ) +{ + if( mDisplayState.misc.confirmWrap == false ) + { + return( true ); // Never ask the user + } + + QString msg; + if( fwd == true ) + { + msg += i18n("" + "End of document reached.\n" + "Continue from the beginning?" ); + } + else + { + msg += i18n("" + "Beginning of document reached.\n" + "Continue from the end?" ); + } + + int reply = KMessageBox::questionYesNo( topLevelWidget(), msg, header, KStdGuiItem::cont(), KStdGuiItem::cancel() ); + return( reply == KMessageBox::Yes ? true : false ); +} + + +bool CHexEditorWidget::canFind( bool showError ) +{ + if( mFindDialog == 0 || mFindDialog->isEmpty() == true ) + { + if( showError == true ) + { + QString msg = i18n("" + "Your request can not be processed.\n" + "No search pattern defined." ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Find") ); + } + return( false ); + } + + return( true ); +} + + + +void CHexEditorWidget::findNavigator( SSearchControl &sc ) +{ + if( canFind( false ) == false ) + { + return; + } + + if( mFindNavigatorDialog == 0 ) + { + mFindNavigatorDialog = new CFindNavigatorDialog(topLevelWidget(),0,false); + if( mFindNavigatorDialog == 0 ) { return; } + connect( mFindNavigatorDialog, + SIGNAL(findData(SSearchControl &, uint, bool)), + SLOT(findData(SSearchControl &, uint, bool)) ); + connect( mFindNavigatorDialog, SIGNAL(makeKey(void)), + SLOT(find()) ); + } + if( mFindNavigatorDialog->isVisible() == false ) + { + mFindNavigatorDialog->defineData( sc ); + } + mFindNavigatorDialog->show(); +} + + + +void CHexEditorWidget::replace( void ) +{ + hideReplacePrompt(); + + if( mReplaceDialog == 0 ) + { + mReplaceDialog = new CReplaceDialog( topLevelWidget(), 0, false ); + if( mReplaceDialog == 0 ) { return; } + connect( mReplaceDialog, + SIGNAL( replaceData( SSearchControl &, uint)), + SLOT( replaceData( SSearchControl &, uint))); + } + mReplaceDialog->show(); +} + + + +void CHexEditorWidget::replaceData( SSearchControl &sc, uint mode ) +{ + while( 1 ) + { + if( mode == Replace_All || mode == Replace_AllInit ) + { + mHexView->replaceAll( sc, mode == Replace_AllInit ? true : false ); + } + else if( mode == Replace_First ) + { + int errCode = mHexView->findFirst( sc ); + if( errCode == Err_Success ) + { + replacePrompt( sc ); + return; + } + } + else if( mode == Replace_Next ) + { + int errCode = mHexView->replaceMarked( sc ); + if( errCode != Err_Success ) + { + // Perhaps a notification here ? + } + errCode = mHexView->findNext( sc ); + if( errCode == Err_Success ) + { + replacePrompt( sc ); + return; + } + } + else if( mode == Replace_Ignore ) + { + int errCode = mHexView->findNext( sc ); + if( errCode == Err_Success ) + { + replacePrompt( sc ); + return; + } + } + else + { + break; + } + + if( sc.wrapValid == false ) + { + break; + } + + bool reply = askWrap( sc.forward, i18n("Find and Replace") ); + if( reply == false ) + { + break; + } + + int errCode = mHexView->findWrap( sc ); + if( errCode != Err_Success ) + { + break; + } + + if( mode == Replace_All || mode == Replace_AllInit ) + { + mode = Replace_All; + continue; + } + + replacePrompt( sc ); + return; + } + + replaceResult( sc ); +} + +void CHexEditorWidget::replacePrompt( SSearchControl &sc ) +{ + if( mReplacePromptDialog == 0 ) + { + mReplacePromptDialog = new CReplacePromptDialog(topLevelWidget(), 0,false); + if( mReplacePromptDialog == 0 ) { return; } + connect( mReplacePromptDialog, + SIGNAL( replaceData( SSearchControl &, uint)), + SLOT( replaceData( SSearchControl &, uint))); + } + if( mReplacePromptDialog->isVisible() == false ) + { + mReplacePromptDialog->defineData( sc ); + } + mReplacePromptDialog->show(); +} + + +void CHexEditorWidget::hideReplacePrompt( void ) +{ + if( mReplacePromptDialog != 0 ) + { + mReplacePromptDialog->hide(); + } +} + + + +void CHexEditorWidget::replaceResult( SSearchControl &sc ) +{ + hideReplacePrompt(); + + if( sc.match == false ) + { + QString msg; + if( sc.inSelection == true ) + { + msg += i18n( "Search key not found in selected area." ); + } + else + { + msg += i18n( "Search key not found in document." ); + } + KMessageBox::information( topLevelWidget(), msg, i18n("Find & Replace")); + } + else + { + const QString msg = i18n( + "<qt>Operation complete.<br><br>One replacement was made.</qt>", + "<qt>Operation complete.<br><br>%n replacements were made.</qt>", sc.numReplace ); + KMessageBox::information( topLevelWidget(), msg, i18n("Find & Replace")); + } +} + + +void CHexEditorWidget::insertPattern( void ) +{ + if( mInsertDialog == 0 ) + { + mInsertDialog = new CInsertDialog( topLevelWidget(), 0, false ); + if( mInsertDialog == 0 ) { return; } + connect( mInsertDialog, SIGNAL(execute( SInsertData & )), + mHexView, SLOT(insert( SInsertData & )) ); + } + mInsertDialog->show(); +} + + +void CHexEditorWidget::encoding( void ) +{ + QString msg = i18n("" + "Not available yet!\n" + "Define your own encoding" ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Encoding") ); +} + + +void CHexEditorWidget::strings( void ) +{ + if( mStringDialog == 0 ) + { + mStringDialog = new CStringDialog( topLevelWidget(), 0, false ); + if( mStringDialog == 0 ) { return; } + connect( mStringDialog, SIGNAL(markText( uint, uint, bool )), + mHexView, SLOT(setMark( uint, uint, bool )) ); + connect( mStringDialog, SIGNAL(collect()), SLOT(collectStrings()) ); + connect( mHexView, SIGNAL(fileName( const QString &, bool ) ), + mStringDialog, SLOT( removeList() ) ); + connect( mHexView, SIGNAL(dataChanged()), + mStringDialog, SLOT(setDirty()) ); + } + mStringDialog->show(); +} + + +void CHexEditorWidget::collectStrings( void ) +{ + int errCode = prepareProgressData( pg_strings ); + if( errCode == Err_Success ) + { + mHexView->collectStrings( mStringDialog->stringData() ); + errCode = mStringDialog->updateList( mProgressData ); + } + + if( errCode != Err_Success && errCode != Err_Stop ) + { + QString msg = i18n("Could not collect strings.\n"); + msg += hexError( errCode ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Collect Strings") ); + } + +} + + + +void CHexEditorWidget::recordView( void ) +{ + QString msg = i18n("" + "Not available yet!\n" + "Define a record (structure) and fill it with data from the document." ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Record Viewer") ); +} + +void CHexEditorWidget::filter( void ) +{ + if( mFilterDialog == 0 ) + { + mFilterDialog = new CFilterDialog( topLevelWidget(), 0, false ); + if( mFilterDialog == 0 ) { return; } + connect( mFilterDialog, SIGNAL(filterData( SFilterControl & )), + mHexView, SLOT(filter( SFilterControl & )) ); + } + mFilterDialog->show(); +} + + +void CHexEditorWidget::chart( void ) +{ + if( mCharTableDialog == 0 ) + { + mCharTableDialog = new CCharTableDialog( topLevelWidget(), 0, false ); + if( mCharTableDialog == 0 ) { return; } + connect( mCharTableDialog, SIGNAL(assign( const QByteArray & )), + mHexView, SLOT(insert( const QByteArray & )) ); + } + mCharTableDialog->show(); +} + + +void CHexEditorWidget::converter( void ) +{ + if( mConverterDialog == 0 ) + { + mConverterDialog = new CConverterDialog( this, "converter", false ); + connect( mConverterDialog, SIGNAL(probeCursorValue(QByteArray &, uint)), + mHexView, SLOT(valueOnCursor(QByteArray &, uint)) ); + } + mConverterDialog->show(); +} + + +void CHexEditorWidget::statistics( void ) +{ + if( mFileInfoDialog == 0 ) + { + mFileInfoDialog = new CFileInfoDialog( topLevelWidget(), 0, false ); + if( mFileInfoDialog == 0 ) { return; } + connect( mFileInfoDialog, SIGNAL(collectStatistic(SStatisticControl &)), + SLOT(collectStatistics(SStatisticControl &))); + connect( mHexView, SIGNAL(dataChanged()), + mFileInfoDialog, SLOT(setDirty()) ); + } + mFileInfoDialog->show(); +} + + +void CHexEditorWidget::collectStatistics( SStatisticControl &sc ) +{ + int errCode = prepareProgressData( pg_statistic ); + if( errCode == Err_Success ) + { + errCode = mHexView->collectStatistic( sc, mProgressData ); + if( errCode == Err_Success ) + { + mFileInfoDialog->setStatistics( sc ); + } + } + + if( errCode != Err_Success && errCode != Err_Stop ) + { + mFileInfoDialog->setStatistics(); // Default values + + QString msg = i18n("Could not collect document statistics.\n"); + msg += hexError( errCode ); + KMessageBox::sorry( topLevelWidget(), msg, + i18n("Collect Document Statistics") ); + } + +} + + +void CHexEditorWidget::options( void ) +{ + if( mOptionDialog == 0 ) + { + mOptionDialog = new COptionDialog( topLevelWidget(), 0, false ); + if( mOptionDialog == 0 ) { return; } + + connect( mOptionDialog, SIGNAL(lineSizeChoice(const SDisplayLine &)), + SLOT(setLineSize(const SDisplayLine &)) ); + connect( mOptionDialog, SIGNAL(layoutChoice(const SDisplayLayout &)), + SLOT(setLayout(const SDisplayLayout &)) ); + connect( mOptionDialog, SIGNAL(fontChoice(const SDisplayFont &)), + SLOT(setFont(const SDisplayFont &)) ); + connect( mOptionDialog, SIGNAL(colorChoice(const SDisplayColor &)), + SLOT(setColor(const SDisplayColor &)) ); + connect( mOptionDialog, SIGNAL(cursorChoice(const SDisplayCursor &)), + SLOT(setCursor(const SDisplayCursor &)) ); + connect( mOptionDialog, SIGNAL(miscChoice(const SDisplayMisc &)), + SLOT(setMisc(const SDisplayMisc &)) ); + connect( mOptionDialog, SIGNAL(removeRecentFiles()), + SIGNAL(removeRecentFiles()) ); + } + if( mOptionDialog->isVisible() == false ) + { + mOptionDialog->setState( mDisplayState ); + } + mOptionDialog->show(); +} + + + +void CHexEditorWidget::favorites( void ) +{ + QString msg = i18n("" + "Not available yet!\n" + "Save or retrive your favorite layout" ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Profiles") ); +} + + +int CHexEditorWidget::readURL( const KURL &url, bool insert ) +{ + // + // 1) Make sure there is data in the url + // + if( url.isEmpty() ) + return( Err_EmptyArgument ); + + // + // 2) Verify that the url is valid URL string. If not, try to repair it. + // This will work if the url contains a name of a file in the + // current directory. + // + if( !url.isValid() ) + { + QString msg = i18n("Malformed URL\n%1").arg( url.url() ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Read URL") ); + return( Err_IllegalArgument ); + } + + // + // 3) Load the file. + // + QString tmpfile; + if ( !KIO::NetAccess::download( url, tmpfile, this ) ) + return Err_ReadFailed; + + bool success = readFile( tmpfile, url.url(), insert ); + + KIO::NetAccess::removeTempFile( tmpfile ); + + return( success == true ? Err_Success : Err_ReadFailed ); +} + + +void CHexEditorWidget::writeURL( QString &url ) +{ + KURL kurl( url ); + if( kurl.isLocalFile() ) + writeFile( kurl.path() ); + else + { + bool modified = mHexView->modified(); + KTempFile tf; + tf.setAutoDelete( true ); + writeFile( tf.name() ); + if( !KIO::NetAccess::upload(tf.name(),url,this) ) + { + mHexView->setModified( modified ); + QString msg = i18n("Could not save remote file."); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Write Failure") ); + } + } +} + +bool CHexEditorWidget::modifiedByAlien( const QString &url ) +{ + KURL kurl( url ); + if( kurl.isLocalFile() == false ) + { + return( false ); + } + + QFileInfo fileInfo( kurl.path() ); + if( fileInfo.exists() == false ) + { + return( false ); + } + + if( fileInfo.lastModified() == mHexView->diskModifyTime() ) + { + return( false ); + } + + return( true ); +} + + + +bool CHexEditorWidget::readFile( const QString &diskPath, const QString &url, + bool insert ) +{ + + QFileInfo info( diskPath ); + if( info.exists() == false ) + { + const QString msg = i18n("The specified file does not exist.\n%1").arg( diskPath ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Read") ); + return( false ); + } + + if( info.isDir() == true ) + { + const QString msg = i18n("You have specified a folder.\n%1").arg( diskPath ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Read") ); + return( false ); + } + + if( info.isReadable() == false ) + { + const QString msg = i18n("You do not have read permission to this file.\n%1").arg( diskPath ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Read") ); + return( false ); + } + + QFile file( diskPath ); + if( file.open( IO_ReadOnly | IO_Raw ) == false ) + { + const QString msg = i18n("An error occurred while trying to open the file.\n%1").arg( diskPath ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Read") ); + return( false ); + } + + if( mHexView->documentPresent() == false ) + { + // + // Can not insert if there is no document present. + // + insert = false; + } + + int errCode = prepareProgressData( insert == true ? pg_insert: pg_read ); + if( errCode == Err_Success ) + { + if( insert == true ) + { + errCode = mHexView->insertFile( file, mProgressData ); + } + else + { + errCode = mHexView->readFile( file, url, mProgressData ); + } + } + + if( errCode != Err_Success ) + { + QString header = insert == true ? i18n("Insert") : i18n("Read"); + QString msg = i18n("Could not read file.\n"); + msg += hexError( errCode ); + KMessageBox::sorry( topLevelWidget(), msg, header ); + } + + file.close(); + return( errCode == Err_Success || errCode == Err_Busy ? true : false ); +} + + + + +bool CHexEditorWidget::writeFile( const QString &diskPath ) +{ + QFileInfo info( diskPath ); + if( info.exists() == true ) + { + if( info.isDir() == true ) + { + QString msg = i18n("You have specified a folder."); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Write Failure") ); + return( false ); + } + + if( info.isWritable() == false ) + { + QString msg = i18n("You do not have write permission."); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Write Failure") ); + return( false ); + } + } + + QFile file( diskPath ); + if( file.open( IO_WriteOnly | IO_Raw | IO_Truncate ) == false ) + { + QString msg = i18n("An error occurred while trying to open the file."); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Write Failure") ); + return( false ); + } + + int errCode = prepareProgressData( pg_write ); + if( errCode == Err_Success ) + { + errCode = mHexView->writeFile( file, mProgressData ); + } + if( errCode != Err_Success ) + { + QString msg = i18n("Could not write data to disk.\n"); + msg += hexError( errCode ); + KMessageBox::sorry( topLevelWidget(), msg, i18n("Write Failure") ); + } + + file.close(); + return( true ); +} + + +CHexBuffer *CHexEditorWidget::documentItem( const QString &url ) +{ + QString symbolicName( url ); +// KURL::decode( symbolicName ); + + for( CHexBuffer *hexBuffer = mDocumentList.first(); hexBuffer != 0; + hexBuffer = mDocumentList.next() ) + { + if( hexBuffer->url() == symbolicName ) + { + return( hexBuffer ); + } + } + + return( 0 ); +} + + +CHexBuffer *CHexEditorWidget::documentItem( const QString &url, bool next ) +{ + if( mDocumentList.count() <= 1 ) + { + return( 0 ); + } + + QString symbolicName( url ); +// KURL::decode( symbolicName ); + + if( next == true ) + { + CHexBuffer *hexBuffer = mDocumentList.first(); + for( ; hexBuffer != 0; hexBuffer = mDocumentList.next() ) + { + if( hexBuffer->url() == symbolicName ) + { + hexBuffer = mDocumentList.next(); + return( hexBuffer == 0 ? mDocumentList.first() : hexBuffer ); + } + } + } + else + { + CHexBuffer *hexBuffer = mDocumentList.last(); + for( ; hexBuffer != 0; hexBuffer = mDocumentList.prev() ) + { + if( hexBuffer->url() == symbolicName ) + { + hexBuffer = mDocumentList.prev(); + return( hexBuffer == 0 ? mDocumentList.last() : hexBuffer ); + } + } + } + + return( 0 ); +} + + + +bool CHexEditorWidget::createBuffer( void ) +{ + if( mHexView->documentPresent() == false ) + { + // + // The document is not valid, i.e. the buffer contains no data + // so we can use this one without destroying anything. + // + return( true ); + } + + CHexBuffer *hexBuffer = new CHexBuffer; + if( hexBuffer == 0 ) + { + QString msg = i18n( "Can not create text buffer.\n" ); + msg += hexError( Err_NoMemory ); + KMessageBox::error( topLevelWidget(), msg, i18n("Loading Failed" ) ); + return( false ); + } + + mDocumentList.append( hexBuffer ); + mHexView->setBuffer( hexBuffer ); + + return( true ); +} + + +void CHexEditorWidget::removeBuffer( void ) +{ + mHexView->closeFile(); + + if( mDocumentList.count() > 1 ) + { + CHexBuffer *prev = 0; + CHexBuffer *curr = mDocumentList.first(); + for( ; curr != 0; curr = mDocumentList.next() ) + { + if( curr == mHexView->hexBuffer() ) + { + CHexBuffer *ptr = prev != 0 ? prev : mDocumentList.next(); + if( ptr != 0 ) + { + mHexView->setBuffer( ptr ); + mDocumentList.remove( curr ); + break; + } + } + prev = curr; + } + } + +} + + +bool CHexEditorWidget::modified( void ) +{ + for( CHexBuffer *hexBuffer = mDocumentList.first(); hexBuffer != 0; + hexBuffer = mDocumentList.next() ) + { + if( hexBuffer->modified() == true ) + { + return( true ); + } + } + + return( false ); +} + + + + +int CHexEditorWidget::prepareProgressData( EProgressMode mode ) +{ + if( mode >= pg_MAX ) + { + return( Err_IllegalMode ); + } + + if( mProgressBusy == true ) + { + return( Err_Busy ); + } + + + mProgressMode = mode; + mProgressBusy = true; + mProgressStop = false; + enableInputLock( true ); + + static QString names[] = + { + i18n("Reading"), + i18n("Writing"), + i18n("Inserting"), + i18n("Printing"), + i18n("Encoding"), + i18n("Collect strings"), + i18n("Exporting"), + i18n("Scanning"), + }; + + mProgressData.define( progressReceiver, this ); + emit setProgressText( QString(names[mode]) ); + emit operationChanged( true ); + + return( Err_Success ); +} + + +int CHexEditorWidget::progressReceiver( void *clientData, SProgressData &pd ) +{ + if( clientData != 0 ) + { + int errCode = ((CHexEditorWidget*)clientData)->progressParse( pd ); + return( errCode ); + } + else + { + return( Err_Success ); + } +} + + +int CHexEditorWidget::progressParse( const SProgressData &pd ) +{ + if( pd.valid() == 0 ) + { + emit enableProgressText( false ); + emit setProgress( 0 ); + emit operationChanged( false ); + mProgressBusy = false; + enableInputLock( false ); + kapp->processEvents(); + return( Err_Success ); + } + else if( pd.useFraction == 1 ) + { + emit enableProgressText( true ); + emit setProgress( (int)(100.0 * pd.fraction ) ); + kapp->processEvents(); + } + else + { + emit enableProgressText( true ); + emit setProgress( pd.curPage, pd.maxPage ); + kapp->processEvents(); + } + + if( mProgressStop == false ) + { + return( Err_Success ); + } + + QString msg, header; + switch( mProgressMode ) + { + case pg_read: + header = i18n("Read"); + msg = i18n("Do you really want to cancel reading?"); + break; + + case pg_write: + header = i18n("Write"); + msg = i18n("Do you really want to cancel writing?\n" + "WARNING: Canceling can corrupt your data on disk"); + break; + + case pg_insert: + header = i18n("Insert"); + msg = i18n("Do you really want to cancel inserting?"); + break; + + case pg_print: + header = i18n("Print"); + msg = i18n("Do you really want to cancel printing?"); + break; + + case pg_encode: + header = i18n("Encode"); + msg = i18n("Do you really want to cancel encoding?"); + break; + + case pg_strings: + header = i18n("Collect strings"); + msg = i18n("Do you really want to cancel string scanning?"); + break; + + case pg_export: + header = i18n("Export"); + msg = i18n("Do you really want to cancel exporting?"); + break; + + case pg_statistic: + header = i18n("Collect document statistics"); + msg = i18n("Do you really want to cancel document scanning?"); + break; + + default: + return( Err_Success ); + break; + + } + + int reply = KMessageBox::warningYesNo( topLevelWidget(), msg, header, KStdGuiItem::cancel(), KStdGuiItem::cont() ); + mProgressStop = false; + return( reply == KMessageBox::Yes ? Err_Stop : Err_Success ); +} + + + +bool CHexEditorWidget::busy( bool showWarning ) +{ + if( mProgressBusy == true && showWarning == true ) + { + QString msg = i18n("Could not finish operation.\n"); + msg += hexError( Err_Busy ); + KMessageBox::sorry( topLevelWidget(), msg ); + } + + return( mProgressBusy ); +} + + + + +#include "hexeditorwidget.moc" diff --git a/khexedit/hexeditorwidget.h b/khexedit/hexeditorwidget.h new file mode 100644 index 0000000..5c4d86a --- /dev/null +++ b/khexedit/hexeditorwidget.h @@ -0,0 +1,301 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_EDITOR_WIDGET_H_ +#define _HEX_EDITOR_WIDGET_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <qvariant.h> +#include <qptrdict.h> +#include <kapplication.h> + +#include "hexbuffer.h" +#include "hexviewwidget.h" +#include "progress.h" + +class CGotoDialog; +class CFindDialog; +class CReplaceDialog; +class CInsertDialog; +class CFilterDialog; +class COptionDialog; +class CPrinterDialog; +class CStringDialog; +class CCharTableDialog; +class CFileInfoDialog; +class CExportDialog; +class CConverterDialog; +class CFindNavigatorDialog; +class CReplacePromptDialog; +namespace KIO { class Job; } + + +class CHexEditorWidget : public QWidget +{ + Q_OBJECT + + public: + enum EProgressMode + { + pg_read = 0, + pg_write, + pg_insert, + pg_print, + pg_encode, + pg_strings, + pg_export, + pg_statistic, + pg_MAX + }; + + public: + CHexEditorWidget( QWidget *parent = 0, const char *name = 0 ); + ~CHexEditorWidget( void ); + + void initialize( void ); + void writeConfiguration( KConfig &config ); + void readConfiguration( KConfig &config ); + + bool isOpen( const QString &url, uint &offset ); + bool modified( void ); + + inline int defaultTextWidth( void ); + inline CHexViewWidget *view( void ); + inline SDisplayLayout &layout( void ); + inline SDisplayLine &line( void ); + inline SDisplayInputMode &inputMode( void ); + inline SDisplayMisc::EOpenFile openFile( void ); + inline bool discardRecentFiles( void ); + inline bool gotoStartupOffset( void ); + inline bool gotoReloadOffset( void ); + + signals: + void errorLoadFile( const QString &url ); + void setProgress( int percent ); + void setProgress( int curPage, int maxPage ); + void enableProgressText( bool state ); + void setProgressText( const QString &msg ); + void operationChanged( bool state ); + void removeRecentFiles( void ); + + public slots: + void setHexadecimalMode( void ); + void setDecimalMode( void ); + void setOctalMode( void ); + void setTextMode( void ); + void setBinaryMode( void ); + void open( const QString &url, bool reloadWhenChanged, uint offset ); + void newFile( void ); + void newFile( const QByteArray &data ); + void stepFile( bool next ); + void open( void ); + void insertFile( void ); + void stop( void ); + bool close( void ); + bool closeAll( void ); + bool backup( void ); + bool save( void ); + bool saveAs( void ); + void reload( void ); + void print( void ); + void exportDialog( void ); + void encode( CConversion::EMode mode ); + void undo( void ); + void redo( void ); + void toggleWriteProtection( void ); + void defaultWriteProtection( void ); + void toggleResizeLock( void ); + void setResizeLock( bool state ); + void toggleOffsetColumnVisibility( void ); + void toggleTextColumnVisibility( void ); + void toggleOffsetAsDecimal( void ); + void toggleDataUppercase( void ); + void toggleOffsetUppercase( void ); + void toggleInsertMode( void ); + void benchmark( void ); + void copy( void ); + void copyText( void ); + void paste( void ); + void pasteNewFile( void ); + void cut( void ); + void selectAll( void ); + void unselect( void ); + void addBookmark( void ); + void removeBookmark( void ); + void removeAllBookmark( void ); + void replaceBookmark( void ); + void gotoBookmark( int position ); + void gotoNextBookmark( void ); + void gotoPrevBookmark( void ); + void gotoOffset( void ); + void find( void ); + void findAgain( void ); + void findNext( void ); + void findPrevious( void ); + void findData( SSearchControl &sc, uint mode, bool navigator ); + void replace( void ); + void insertPattern( void ); + void encoding( void ); + void strings( void ); + void recordView( void ); + void filter( void ); + void chart( void ); + void converter( void ); + void statistics( void ); + void options( void ); + void favorites( void ); + + protected slots: + void fontChanged( void ); + void paletteChanged( void ); + void layoutChanged( const SDisplayLayout &layout ); + void inputModeChanged( const SDisplayInputMode &input ); + void setLineSize(const SDisplayLine &line ); + void setLayout( const SDisplayLayout &layout ); + void setCursor( const SDisplayCursor &cursor ); + void setColor( const SDisplayColor &color ); + void setFont( const SDisplayFont &font ); + void setMisc( const SDisplayMisc &misc ); + + void printPostscript( CHexPrinter & ); + void exportText( const SExportText & ); + void exportHtml( const SExportHtml & ); + void exportCArray( const SExportCArray &ex ); + + void findNavigator( SSearchControl &sc ); + void replaceData( SSearchControl &sc, uint mode ); + void replacePrompt( SSearchControl &sc ); + void replaceResult( SSearchControl &sc ); + void collectStrings( void ); + void collectStatistics( SStatisticControl &sc ); + + protected: + void resizeEvent( QResizeEvent *e ); + + private: + bool selectDocument( const QString &url, bool reloadWhenChanged ); + bool querySave( void ); + int readURL( const KURL &url, bool insert ); + void writeURL( QString &url ); + bool readFile( const QString &diskPath, const QString &url, bool insert ); + bool writeFile( const QString &diskPath ); + void saveWorkingDirectory( const QString &url ); + + bool confirmPrintPageNumber( CHexPrinter &printer ); + + CHexBuffer *documentItem( const QString &url ); + CHexBuffer *documentItem( const QString &url, bool next ); + bool createBuffer( void ); + void removeBuffer( void ); + + bool askWrap( bool fwd, const QString &header ); + bool canFind( bool showError ); + void hideReplacePrompt( void ); + bool modifiedByAlien( const QString &url ); + void enableInputLock( bool inputLock ); + + int prepareProgressData( EProgressMode mode ); + static int progressReceiver( void *clientData, SProgressData &pd ); + int progressParse( const SProgressData &pd ); + bool busy( bool showWarning ); + + private: + QString mWorkDir; // Remembers last directroy used by file dialogs + + uint mUntitledCount; + QPtrList<CHexBuffer> mDocumentList; + SDisplayState mDisplayState; + + CProgress mProgressData; + EProgressMode mProgressMode; + bool mProgressBusy; + bool mProgressStop; + + CHexViewWidget *mHexView; + CGotoDialog *mGotoDialog; + CFindDialog *mFindDialog; + CReplaceDialog *mReplaceDialog; + CInsertDialog *mInsertDialog; + CFilterDialog *mFilterDialog; + COptionDialog *mOptionDialog; + CStringDialog *mStringDialog; + CCharTableDialog *mCharTableDialog; + CFileInfoDialog *mFileInfoDialog; + CExportDialog *mExportDialog; + CConverterDialog *mConverterDialog; + CFindNavigatorDialog *mFindNavigatorDialog; + CReplacePromptDialog *mReplacePromptDialog; +}; + +inline int CHexEditorWidget::defaultTextWidth( void ) +{ + return( mHexView->defaultWidth() ); +} + +inline CHexViewWidget *CHexEditorWidget::view( void ) +{ + return( mHexView ); +} + +inline SDisplayLayout &CHexEditorWidget::layout( void ) +{ + return( mDisplayState.layout ); +} + +inline SDisplayLine &CHexEditorWidget::line( void ) +{ + return( mDisplayState.line ); +} + +inline SDisplayInputMode &CHexEditorWidget::inputMode( void ) +{ + return( mDisplayState.input ); +} + +inline SDisplayMisc::EOpenFile CHexEditorWidget::openFile( void ) +{ + return( mDisplayState.misc.openFile ); +} + +inline bool CHexEditorWidget::discardRecentFiles( void ) +{ + return( mDisplayState.misc.discardRecent ); +} + +inline bool CHexEditorWidget::gotoStartupOffset( void ) +{ + return( mDisplayState.misc.gotoOnStartup ); +} + +inline bool CHexEditorWidget::gotoReloadOffset( void ) +{ + return( mDisplayState.misc.gotoOnReload ); +} + + + +#endif + + + diff --git a/khexedit/hexeditstate.h b/khexedit/hexeditstate.h new file mode 100644 index 0000000..f3f8fff --- /dev/null +++ b/khexedit/hexeditstate.h @@ -0,0 +1,596 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_EDIT_STATE_H_ +#define _HEX_EDIT_STATE_H_ + +#include <kapplication.h> +#include <qfont.h> +#include <qpalette.h> +#include <kglobalsettings.h> + + +class SDisplayLine +{ + public: + enum EViewMode + { + hexadecimal = 0, + decimal, + octal, + binary, + textOnly + }; + + SDisplayLine( void ) + { + lineSize[hexadecimal] = 16; + lineSize[decimal] = 16; + lineSize[octal] = 16; + lineSize[binary] = 8; + lineSize[textOnly] = 64; + + columnSize[hexadecimal] = 1; + columnSize[decimal] = 1; + columnSize[octal] = 1; + columnSize[binary] = 1; + columnSize[textOnly] = 64; + } + + uint getLineSize( int index ) + { + return( lineSize[ index > textOnly ? 0 : index ] ); + } + + uint getColumnSize( int index ) + { + return( columnSize[ index > textOnly ? 0 : index ] ); + } + + void setLineSize( int index, uint value ) + { + if( index <= textOnly ) { lineSize[ index ] = value; } + } + + void setColumnSize( int index, uint value ) + { + if( index <= textOnly ) { columnSize[ index ] = value; } + } + + uint lineSize[5]; + uint columnSize[5]; +}; + + +class SDisplayLayout +{ + public: + enum EViewMode + { + hexadecimal = 0, + decimal, + octal, + binary, + textOnly, + hide + }; + + SDisplayLayout( void ) + { + offsetMode = hexadecimal; + primaryMode = hexadecimal; + secondaryMode = textOnly; + offsetUpperCase = false; + primaryUpperCase = false; + offsetVisible = true; + lineSize = 16; + columnSize = 1; + lockLine = true; + lockColumn = true; + columnCharSpace = true; + columnSpacing = 5; + separatorMarginWidth = 5; + edgeMarginWidth = 5; + leftSeparatorWidth = 1; + rightSeparatorWidth = 1; + horzGridWidth = 0; + vertGridWidth = 0; + } + + void verify( void ) + { + if( lineSize < 1 ) { lineSize = 1; } + if( columnSize < 1 ) { columnSize = 1; } + if( columnSize > lineSize ) { columnSize = lineSize; } + if( primaryMode == textOnly ) { secondaryMode = hide; columnSpacing=0; } + if( columnSpacing == 0 ) { columnSize = lineSize; } + if( horzGridWidth > 1 ) { horzGridWidth = 1; } + if( vertGridWidth > 1 ) { vertGridWidth = 1; } + } + + bool showSecondary( void ) + { + if( primaryMode == textOnly || secondaryMode == hide ) + { + return( false ); + } + else + { + return( true ); + } + } + + QString modeStrings( uint index ) + { + if( index == hexadecimal ) + { + return( "hexadecimal" ); + } + else if( index == decimal ) + { + return( "decimal" ); + } + else if( index == octal ) + { + return( "octal" ); + } + else if( index == binary ) + { + return( "binary" ); + } + else if( index == textOnly ) + { + return( "textOnly" ); + } + else + { + return( "hide" ); + } + } + + + QString primaryModeString( void ) + { + return( modeStrings( primaryMode > textOnly ? + hexadecimal : primaryMode )); + } + + QString secondaryModeString( void ) + { + return( modeStrings( secondaryMode == textOnly ? textOnly : hide ) ); + } + + QString offsetModeString( void ) + { + return( modeStrings( offsetMode == hexadecimal ? hexadecimal : hide ) ); + } + + QString gridModeString( void ) + { + if( horzGridWidth == 0 && vertGridWidth == 0 ) + { + return( "none"); + } + else if( horzGridWidth != 0 && vertGridWidth != 0 ) + { + return( "both"); + } + else if( horzGridWidth != 0 ) + { + return( "horizontal"); + } + else + { + return( "vertical"); + } + } + + void setPrimaryMode( const QString & str ) + { + if( str.isNull() || str == "hexadecimal" ) + { + primaryMode = hexadecimal; + } + else if( str == "decimal" ) + { + primaryMode = decimal; + } + else if( str == "octal" ) + { + primaryMode = octal; + } + else if( str == "binary" ) + { + primaryMode = binary; + } + else if( str == "textOnly" ) + { + primaryMode = textOnly; + } + else + { + primaryMode = hexadecimal; + } + } + + void setSecondaryMode( const QString & str ) + { + if( str.isNull() || str == "textOnly" ) + { + secondaryMode = textOnly; + } + else + { + secondaryMode = hide; + } + } + + void setOffsetMode( const QString & str ) + { + if( str.isNull() || str == "hexadecimal" ) + { + offsetMode = hexadecimal; + } + else + { + offsetMode = decimal; + } + } + + void setGridMode( const QString & str ) + { + if( str.isNull() || str == "none" ) + { + horzGridWidth = vertGridWidth = 0; + } + else if( str == "vertical" ) + { + horzGridWidth = 0; + vertGridWidth = 1; + } + else if( str == "horizontal" ) + { + horzGridWidth = 1; + vertGridWidth = 0; + } + else if( str == "both" ) + { + horzGridWidth = vertGridWidth = 1; + } + else + { + horzGridWidth = vertGridWidth = 0; + } + } + + EViewMode offsetMode; + EViewMode primaryMode; + EViewMode secondaryMode; + bool offsetUpperCase; + bool primaryUpperCase; + bool offsetVisible; + bool lockLine; + bool lockColumn; + uint lineSize; + uint columnSize; + bool columnCharSpace; + uint columnSpacing; + uint separatorMarginWidth; + uint edgeMarginWidth; + uint leftSeparatorWidth; + uint rightSeparatorWidth; + uint horzGridWidth; + uint vertGridWidth; +}; + + + + +class SDisplayCursor +{ + public: + enum EFocusMode + { + stopBlinking = 0, + hide, + ignore + }; + + SDisplayCursor( void ) + { + focusMode = hide; + interval = 500; + alwaysVisible = false; + alwaysBlockShape = false; + thickInsertShape = true; + } + + QString modeStrings( uint index ) + { + if( index == hide ) + { + return( "hide" ); + } + else if( index == ignore ) + { + return( "ignore" ); + } + else + { + return( "stopBlinking" ); + } + } + + QString focusModeString( void ) + { + return( modeStrings( focusMode > ignore ? stopBlinking : focusMode )); + } + + void setFocusMode( const QString & str ) + { + if( str.isNull() || str == "hide" ) + { + focusMode = hide; + } + else if( str == "stopBlinking" ) + { + focusMode = stopBlinking; + } + else + { + focusMode = ignore; + } + } + + EFocusMode focusMode; + uint interval; + bool alwaysVisible; + bool alwaysBlockShape; + bool thickInsertShape; +}; + + +class SDisplayColor +{ + public: + + SDisplayColor( void ) + { + // + // Default colors. The selection colors will always be the one + // choses in Control Center. + // + useSystemColor = false; + offsetBg = Qt::white; + textBg = Qt::white; + secondTextBg = Qt::white; + inactiveBg = Qt::gray; + selectBg = kapp->palette().active().highlight(); + selectFg = kapp->palette().active().highlightedText(); + markBg = Qt::blue; + markFg = Qt::white; + primaryFg[0] = Qt::black; + primaryFg[1] = Qt::blue; + offsetFg = Qt::red; + secondaryFg = Qt::black; + nonPrintFg = Qt::red; + gridFg = Qt::darkCyan; + leftSeparatorFg = Qt::darkGreen; + rightSeparatorFg = Qt::darkGreen; + cursorBg = Qt::red; + cursorFg = Qt::black; + bookmarkBg = Qt::green; + bookmarkFg = Qt::black; + } + + bool useSystemColor; + QColor offsetBg; + QColor textBg; + QColor secondTextBg; + QColor inactiveBg; + QColor selectBg; + QColor selectFg; + QColor markBg; + QColor markFg; + QColor primaryFg[2]; + QColor offsetFg; + QColor secondaryFg; + QColor nonPrintFg; + QColor gridFg; + QColor leftSeparatorFg; + QColor rightSeparatorFg; + QColor cursorBg; + QColor cursorFg; + QColor bookmarkBg; + QColor bookmarkFg; +}; + + +class SDisplayFontInfo +{ + public: + + SDisplayFontInfo &init( void ) + { + font = KGlobalSettings::fixedFont(); + nonPrintChar = '.'; + return( *this ); + } + + QFont font; + QChar nonPrintChar; +}; + +class SDisplayFont +{ + public: + SDisplayFont( void ) + { + useSystemFont = false; + localFont = KGlobalSettings::fixedFont(); + nonPrintChar = '.'; + } + + bool useSystemFont; + QFont localFont; + QChar nonPrintChar; +}; + + +class SDisplayMisc +{ + public: + + enum EOpenFile + { + none = 0, + mostRecent, + allRecent + }; + + SDisplayMisc( void ) + { + undoLevel = 100; + openFile = none; + inputSound = false; + fatalSound = false; + autoCopyToClipboard = true; + insertMode = false; + writeProtect = false; + confirmWrap = true; + cursorJump = true; + makeBackup = false; + confirmThreshold = true; + thresholdValue = 30; + discardRecent = false; + gotoOnStartup = false; + gotoOnReload = true; + bookmarkOffsetColumn = true; + bookmarkEditor = true; + } + + + QString fileStrings( uint index ) + { + if( index == mostRecent ) + { + return( "mostRecent" ); + } + else if( index == allRecent ) + { + return( "allRecent" ); + } + else + { + return( "none" ); + } + } + + + QString openFileString( void ) + { + return( fileStrings( openFile > allRecent ? none : openFile )); + } + + void setOpenFile( const QString &str ) + { + if( str.isNull() == true || str == "none" ) + { + openFile = none; + } + else if( str == "mostRecent" ) + { + openFile = mostRecent; + } + else if( str == "allRecent" ) + { + openFile = allRecent; + } + else + { + openFile = none; + } + } + + uint undoLevel; + EOpenFile openFile; + bool inputSound; + bool fatalSound; + bool autoCopyToClipboard; + bool insertMode; + bool writeProtect; + bool confirmWrap; + bool cursorJump; + bool makeBackup; + bool confirmThreshold; + uint thresholdValue; + bool discardRecent; + bool gotoOnStartup; + bool gotoOnReload; + bool bookmarkOffsetColumn; + bool bookmarkEditor; +}; + + +class SDisplayInputMode +{ + public: + SDisplayInputMode( void ) + { + inputLock = false; + readOnly = false; + allowResize = true; + }; + + bool noInput( void ) + { + return( inputLock || readOnly ); + } + + bool inputLock; // Set by application only + bool readOnly; // Set by user + bool allowResize; +}; + + +class SDisplayState +{ + public: + SDisplayLine line; + SDisplayLayout layout; + SDisplayCursor cursor; + SDisplayColor color; + SDisplayFont font; + SDisplayMisc misc; + SDisplayInputMode input; +}; + + + + + +#endif + + + + + + + diff --git a/khexedit/hexerror.cc b/khexedit/hexerror.cc new file mode 100644 index 0000000..ac179e6 --- /dev/null +++ b/khexedit/hexerror.cc @@ -0,0 +1,69 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <klocale.h> + +#include "hexerror.h" + +static QString message; + + +const QString &hexError( int index ) +{ + static QString messages[ Err_MAXERROR - Err_NoData ] = + { + i18n("No data"), // Err_NoData + i18n("Insufficient memory"), // Err_NoMemory + i18n("List is full"), // Err_ListFull + i18n("Read operation failed"), // Err_ReadFailed + i18n("Write operation failed"), // Err_WriteFailed + i18n("Empty argument"), // Err_EmptyArgument + i18n("Illegal argument"), // Err_IllegalArgument + i18n("Null pointer argument"), // Err_NullArgument + i18n("Wrap buffer"), // Err_WrapBuffer + i18n("No match"), // Err_NoMatch + i18n("No data is selected"), // Err_NoSelection + i18n("Empty document"), // Err_EmptyDocument + i18n("No active document"), // Err_NoActiveDocument + i18n("No data is marked"), // Err_NoMark + i18n("Document is write protected"), // Err_WriteProtect + i18n("Document is resize protected"), // Err_NoResize + i18n("Operation was stopped"), // Err_Stop + i18n("Illegal mode"), // Err_IllegalMode + i18n("Program is busy, try again later"), // Err_Busy + i18n("Value is not within valid range"), // Err_IllegalRange + i18n("Operation was aborted"), // Err_OperationAborted + i18n("File could not be opened for writing"), // Err_OpenWriteFailed + i18n("File could not be opened for reading"), // Err_OpenReadFailed + }; + + + if( index < Err_NoData || index >= Err_MAXERROR ) + { + message = i18n("Unknown error"); + } + else + { + message = messages[ index - Err_NoData ]; + } + + return( message ); +} + diff --git a/khexedit/hexerror.h b/khexedit/hexerror.h new file mode 100644 index 0000000..d17d302 --- /dev/null +++ b/khexedit/hexerror.h @@ -0,0 +1,57 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_ERROR_H_ +#define _HEX_ERROR_H_ + +enum EHexError +{ + Err_NoErr = 0, + Err_Success = 0, + Err_NoData = -10000, // Must be the first + Err_NoMemory, + Err_ListFull, + Err_ReadFailed, + Err_WriteFailed, + Err_EmptyArgument, + Err_IllegalArgument, + Err_NullArgument, + Err_WrapBuffer, + Err_NoMatch, + Err_NoSelection, + Err_EmptyDocument, + Err_NoActiveDocument, + Err_NoMark, + Err_WriteProtect, + Err_NoResize, + Err_Stop, + Err_IllegalMode, + Err_Busy, + Err_IllegalRange, + Err_OperationAborted, + Err_OpenWriteFailed, + Err_OpenReadFailed, + Err_MAXERROR // Must be the last +}; + +const QString &hexError( int index ); + + +#endif diff --git a/khexedit/hexmanagerwidget.cc b/khexedit/hexmanagerwidget.cc new file mode 100644 index 0000000..1073b95 --- /dev/null +++ b/khexedit/hexmanagerwidget.cc @@ -0,0 +1,370 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <klocale.h> +#include <qlayout.h> +#include "hexmanagerwidget.h" +#include "searchbar.h" + +CHexManagerWidget::CHexManagerWidget( QWidget *parent, const char *name, + EConversionPosition conversionPosition, + EPosition tabBarPosition, + EPosition searchBarPosition ) + : QWidget( parent, name ) +{ + mValid = false; + + mEditor = new CHexEditorWidget( this ); + mTabBar = new CTabBar( this ); + mTabBar->hide(); + mSearchBar = 0; + + mConverter = new CHexToolWidget( this ); + + connect( mEditor->view(), SIGNAL(fileName(const QString &, bool)), + this, SLOT( addName(const QString &))); + connect( mEditor->view(), SIGNAL( fileClosed(const QString &)), + this, SLOT( removeName(const QString &))); + connect( mEditor->view(),SIGNAL(fileRename(const QString &,const QString &)), + this, SLOT(changeName(const QString &,const QString &))); + connect( mEditor->view(), SIGNAL( cursorChanged( SCursorState & ) ), + mConverter, SLOT( cursorChanged( SCursorState & ) ) ); + connect( mConverter, SIGNAL( closed(void) ), + this, SIGNAL( conversionClosed(void) ) ); + connect( mTabBar, SIGNAL(selected(const QString &)), + this, SLOT(open(const QString &))); + + mValid = true; + setConversionVisibility( conversionPosition ); + setTabBarPosition( tabBarPosition ); + setSearchBarPosition( searchBarPosition ); +} + + +CHexManagerWidget::~CHexManagerWidget( void ) +{ + delete mEditor; + delete mTabBar; + delete mConverter; +} + + +void CHexManagerWidget::updateLayout( void ) +{ + if( mValid == false ) { return; } + + delete layout(); + QVBoxLayout *vlay = new QVBoxLayout( this, 0, 0 ); + + if( mSearchBar && mSearchBarPosition == AboveEditor ) + { + vlay->addWidget( mSearchBar ); + } + + if( mTabPosition == AboveEditor ) + { + vlay->addWidget( mTabBar ); + vlay->addWidget( mEditor, 1 ); + } + else + { + vlay->addWidget( mEditor, 1 ); + vlay->addWidget( mTabBar ); + } + + if( mSearchBar && mSearchBarPosition == BelowEditor ) + { + vlay->addWidget( mSearchBar ); + } + + if( mConversionPosition == Embed ) + { + vlay->addWidget( mConverter ); + } + vlay->activate(); // Required in this case +} + + +void CHexManagerWidget::setConversionVisibility( EConversionPosition position ) +{ + if( mValid == false ) + { + return; + } + + if( mConversionPosition == position ) + { + if( mConversionPosition == Float ) + { + mConverter->raise(); + } + return; + } + + mConversionPosition = position; + if( mConversionPosition == Hide ) + { + mConverter->hide(); + } + else if( mConversionPosition == Float ) + { + QPoint point = mapToGlobal( QPoint(0,0) ); + QRect rect = geometry(); + QPoint p; + + p.setX(point.x() + rect.width()/2 - mConverter->minimumSize().width()/2); + p.setY(point.y() + rect.height()/2 - mConverter->minimumSize().height()/2); + mConverter->resize( mConverter->minimumSize() ); + mConverter->reparent( 0, WStyle_Customize | WStyle_DialogBorder, p, true ); + mConverter->setCaption(kapp->makeStdCaption(i18n("Conversion"))); + } + else + { + mConversionPosition = Embed; + uint utilHeight = mConverter->minimumSize().height(); + QPoint p( 0, height() - utilHeight ); + mConverter->reparent( this, 0, p, true ); + } + + updateLayout(); +} + + +void CHexManagerWidget::setTabBarPosition( EPosition position ) +{ + mTabPosition = position; + if( mTabPosition != HideItem && mTabBar->count() > 0 ) + { + if( mTabPosition == AboveEditor ) + { + mTabBar->setShape( QTabBar::RoundedAbove ); + } + else + { + mTabBar->setShape( QTabBar::RoundedBelow ); + } + mTabBar->show(); + } + else + { + mTabBar->hide(); + } + + updateLayout(); +} + + +void CHexManagerWidget::setSearchBarPosition( EPosition position ) +{ + mSearchBarPosition = position; + if( position != HideItem ) + { + if( mSearchBar == 0 ) + { + mSearchBar = new CSearchBar( this ); + connect( mSearchBar, SIGNAL(hidden()), this, SLOT(searchBarHidden()) ); + connect( mSearchBar, SIGNAL(findData(SSearchControl &, uint, bool)), + mEditor, SLOT(findData(SSearchControl &, uint, bool)) ); + connect( editor()->view(), SIGNAL( cursorChanged( SCursorState & ) ), + mSearchBar, SLOT( cursorMoved() ) ); + } + mSearchBar->show(); + } + else + { + if( mSearchBar != 0 ) + { + mSearchBar->hide(); + } + } + + updateLayout(); +} + + +void CHexManagerWidget::searchBarHidden( void ) +{ + updateLayout(); + mSearchBarPosition = HideItem; + emit searchBarClosed(); +} + + +void CHexManagerWidget::addName( const QString &name ) +{ + if( name.isEmpty() == true ) + { + return; + } + + mTabBar->addName( name ); + if( mTabBar->isVisible() == false && mTabPosition != HideItem ) + { + setTabBarPosition( mTabPosition ); + } +} + + +void CHexManagerWidget::removeName( const QString &name ) +{ + mTabBar->removeName( name ); + if( mTabBar->isVisible() == true && mTabBar->count() == 0 ) + { + setTabBarPosition( mTabPosition ); + } +} + + +void CHexManagerWidget::changeName( const QString &curName, + const QString &newName ) +{ + mTabBar->changeName( curName, newName ); +} + + +void CHexManagerWidget::open( const QString &name ) +{ + mEditor->open( name, false, 0 ); +} + + +int CHexManagerWidget::preferredWidth( void ) +{ + int w = mEditor->defaultTextWidth(); + if( mConversionPosition == Embed ) + { + int converterWidth = mConverter->sizeHint().width(); + w = QMAX( w, converterWidth ); + } + return( w ); +} + + + +CTabBar::CTabBar( QWidget *parent, char *name ) + :QTabBar( parent, name ) +{ + connect( this, SIGNAL(selected(int)), this, SLOT(slotSelected(int)) ); +} + + +void CTabBar::addName( const QString &name ) +{ + QString n( name.right(name.length()-name.findRev('/')-1) ); + + QTab *t = find( n ); + if( t == 0 ) + { + t = new QTab(); + t->setText( n); + int id = addTab( t ); + mFileList.append( CFileKey(name,id) ); + } + setCurrentTab(t); +} + + +void CTabBar::removeName( const QString &name ) +{ + QString n( name.right(name.length()-name.findRev('/')-1) ); + QTab *t = find(n); + if( t == 0 ) + { + return; + } + + QValueList<CFileKey>::Iterator it; + for( it = mFileList.begin(); it != mFileList.end(); ++it ) + { + if( (*it).id() == t->identifier() ) + { + mFileList.remove(it); + removeTab(t); + layoutTabs(); + break; + } + } +} + + +void CTabBar::changeName( const QString &curName, const QString &newName ) +{ + QString n( curName.right(curName.length()-curName.findRev('/')-1) ); + QTab *t = find(n); + if( t == 0 ) + { + return; + } + + QValueList<CFileKey>::Iterator it; + for( it = mFileList.begin(); it != mFileList.end(); ++it ) + { + if( (*it).id() == t->identifier() ) + { + QString m( newName.right(newName.length()-newName.findRev('/')-1) ); + t->setText(m); + + mFileList.remove(it); + mFileList.append( CFileKey(newName,t->identifier()) ); + layoutTabs(); + update(); // Seems to be necessary + break; + } + } +} + + +QTab *CTabBar::find( const QString &name ) +{ + QPtrList<QTab> &list = *tabList(); + for( QTab *t = list.first(); t != 0; t = list.next() ) + { + if( t->text() == name ) + { + return( t ); + } + } + + return( 0 ); +} + + +int CTabBar::count( void ) +{ + return( tabList()->count() ); +} + + +void CTabBar::slotSelected( int id ) +{ + QValueList<CFileKey>::Iterator it; + for( it = mFileList.begin(); it != mFileList.end(); ++it ) + { + if( (*it).id() == id ) + { + emit selected( (*it).filename() ); + } + } +} + + + + +#include "hexmanagerwidget.moc" diff --git a/khexedit/hexmanagerwidget.h b/khexedit/hexmanagerwidget.h new file mode 100644 index 0000000..08924da --- /dev/null +++ b/khexedit/hexmanagerwidget.h @@ -0,0 +1,202 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_MANAGER_WIDGET_H_ +#define _HEX_MANAGER_WIDGET_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qtabbar.h> +#include <qvaluelist.h> +#include <qwidget.h> + +#include "hexeditorwidget.h" +#include "hextoolwidget.h" + +class CSearchBar; + + +class CFileKey +{ + public: + CFileKey( const QString &fname, int fid ) + { + mFilename = fname; + mId = fid; + } + + CFileKey( const CFileKey & k ) + { + mFilename = k.mFilename; + mId = k.mId; + } + + CFileKey( void ) + { + } + + QString filename( void ) const + { + return( mFilename ); + } + + int id() const + { + return( mId ); + } + + private: + QString mFilename; + int mId; +}; + + + + +class CTabBar : public QTabBar +{ + Q_OBJECT + + public: + CTabBar( QWidget *parent=0, char *name=0 ); + void addName( const QString &name ); + void removeName( const QString &name ); + void changeName( const QString &curName, const QString &newName ); + int count( void ); + + protected slots: + void slotSelected( int id ); + + private: + QTab *find( const QString &name ); + + private: + QValueList<CFileKey> mFileList; + + signals: + void selected( const QString &filename ); +}; + + +class CHexManagerWidget : public QWidget +{ + Q_OBJECT + + public: + enum EConversionPosition + { + Hide, + Float, + Embed + }; + + enum EPosition + { + HideItem = 0, + AboveEditor, + BelowEditor + }; + + public: + CHexManagerWidget( QWidget *parent = 0, const char *name = 0, + EConversionPosition state = Embed, + EPosition tabBarPosition = HideItem, + EPosition searchBarPosition = HideItem ); + ~CHexManagerWidget( void ); + + inline bool isValid( void ); + inline CHexEditorWidget *editor( void ); + inline CHexToolWidget *converter( void ); + inline EConversionPosition conversionPosition( void ); + inline EPosition tabBarPosition( void ); + inline EPosition searchBarPosition( void ); + + int preferredWidth( void ); + + public slots: + void setConversionVisibility( EConversionPosition position ); + void setTabBarPosition( EPosition position ); + void setSearchBarPosition( EPosition position ); + void addName( const QString &name ); + void removeName( const QString &name ); + void changeName( const QString &curName, const QString &newName ); + + protected slots: + void open( const QString &name ); + void searchBarHidden( void ); + + private: + void updateLayout( void ); + + signals: + void conversionClosed( void ); + void searchBarClosed( void ); + + private: + bool mValid; + bool mEnableTabBar; + EConversionPosition mConversionPosition; + EPosition mTabPosition; + EPosition mSearchBarPosition; + CHexEditorWidget *mEditor; + CTabBar *mTabBar; + CHexToolWidget *mConverter; + CSearchBar *mSearchBar; +}; + + +inline bool CHexManagerWidget::isValid( void ) +{ + return( mValid ); +} + +inline CHexEditorWidget *CHexManagerWidget::editor( void ) +{ + return( mEditor ); +} + +inline CHexToolWidget *CHexManagerWidget::converter( void ) +{ + return( mConverter ); +} + +inline CHexManagerWidget::EConversionPosition + CHexManagerWidget::conversionPosition( void ) +{ + return( mConversionPosition ); +} + +inline CHexManagerWidget::EPosition CHexManagerWidget::tabBarPosition( void ) +{ + return( mTabPosition ); +} + +inline CHexManagerWidget::EPosition CHexManagerWidget::searchBarPosition(void) +{ + return( mSearchBarPosition ); +} + + + + +#endif + diff --git a/khexedit/hexprinter.cc b/khexedit/hexprinter.cc new file mode 100644 index 0000000..0127751 --- /dev/null +++ b/khexedit/hexprinter.cc @@ -0,0 +1,168 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + + +#include "hexprinter.h" + + +CHexPrinter::CHexPrinter( void ) + : KPrinter() +{ +} + + +void CHexPrinter::setPageMarginMM( uint top, uint bottom, int right, int left ) +{ + mPageMargin.top = top; + mPageMargin.left = left; + mPageMargin.bottom = bottom; + mPageMargin.right = right; +} + +void CHexPrinter::setTopMarginMM( uint value ) +{ + mPageMargin.top = value; +} + +void CHexPrinter::setLeftMarginMM( uint value ) +{ + mPageMargin.left = value; +} + +void CHexPrinter::setBottomMarginMM( uint value ) +{ + mPageMargin.bottom = value; +} + +void CHexPrinter::setRightMarginMM( uint value ) +{ + mPageMargin.right = value; +} + + + +void CHexPrinter::setPageHeader( bool enable, uint left, uint center, + uint right, uint line ) +{ + if( left > SPageHeader::FileName ) { left = SPageHeader::NoString; } + if( center > SPageHeader::FileName ) { center = SPageHeader::NoString; } + if( right > SPageHeader::FileName ) { right = SPageHeader::NoString; } + if( line > SPageHeader::Rectangle ) { line = SPageHeader::NoLine; } + + mHeader.enable = enable; + mHeader.pos[0] = (SPageHeader::EHeaderString)left; + mHeader.pos[1] = (SPageHeader::EHeaderString)center; + mHeader.pos[2] = (SPageHeader::EHeaderString)right; + mHeader.line = (SPageHeader::EHeaderLine)line; + + if( mHeader.pos[0] == SPageHeader::NoString && + mHeader.pos[1] == SPageHeader::NoString && + mHeader.pos[2] == SPageHeader::NoString && + mHeader.line == SPageHeader::NoLine ) + { + mHeader.enable = false; + } +} + +void CHexPrinter::setPageFooter( bool enable, uint left, uint center, + uint right, uint line ) +{ + if( left > SPageHeader::FileName ) { left = SPageHeader::NoString; } + if( center > SPageHeader::FileName ) { center = SPageHeader::NoString; } + if( right > SPageHeader::FileName ) { right = SPageHeader::NoString; } + if( line > SPageHeader::Rectangle ) { line = SPageHeader::NoLine; } + + mFooter.enable = enable; + mFooter.pos[0] = (SPageHeader::EHeaderString)left; + mFooter.pos[1] = (SPageHeader::EHeaderString)center; + mFooter.pos[2] = (SPageHeader::EHeaderString)right; + mFooter.line = (SPageHeader::EHeaderLine)line; + + if( mFooter.pos[0] == SPageHeader::NoString && + mFooter.pos[1] == SPageHeader::NoString && + mFooter.pos[2] == SPageHeader::NoString && + mFooter.line == SPageHeader::NoLine ) + { + mFooter.enable = false; + } +} + + +SPageMargin CHexPrinter::pageMargin( void ) +{ + QPaintDeviceMetrics metric( this ); + float f = (float)metric.width()/(float)metric.widthMM(); + + SPageMargin margin; + margin.top = (uint) (f*(float)mPageMargin.top); + margin.right = (uint) (f*(float)mPageMargin.right); + margin.bottom = (uint) (f*(float)mPageMargin.bottom); + margin.left = (uint) (f*(float)mPageMargin.left); + + return( margin ); +} + + +SPageMargin CHexPrinter::pageMarginMM( void ) +{ + return( mPageMargin ); +} + + +SPageSize CHexPrinter::pageFullSize( void ) +{ + QPaintDeviceMetrics metric( this ); + SPageSize size; + size.width = metric.width(); + size.height = metric.height(); + + return( size ); +} + + +SPageSize CHexPrinter::pageUsableSize( void ) +{ + QPaintDeviceMetrics metric( this ); + SPageMargin margin = pageMargin(); + SPageSize size; + + uint mw = margin.left + margin.right; + if( metric.width() <= (int)mw ) + { + size.width = 1; + } + else + { + size.width = metric.width() - mw; + } + + uint mh = margin.top + margin.bottom; + if( metric.height() <= (int)mh ) + { + size.height = 1; + } + else + { + size.height = metric.height() - mh; + } + + return( size ); +} + diff --git a/khexedit/hexprinter.h b/khexedit/hexprinter.h new file mode 100644 index 0000000..2d6eeba --- /dev/null +++ b/khexedit/hexprinter.h @@ -0,0 +1,108 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_PRINTER_H_ +#define _HEX_PRINTER_H_ + +#include <kprinter.h> +#include <qpaintdevicemetrics.h> + +struct SPageSize +{ + uint width; + uint height; +}; + +struct SPageMargin +{ + uint top; + uint right; + uint bottom; + uint left; +}; + + +struct SPageHeader +{ + enum EHeaderString + { + NoString = 0, + DateTime, + PageNumber, + FileName + }; + + enum EHeaderLine + { + NoLine = 0, + SingleLine, + Rectangle + }; + + bool enable; + EHeaderString pos[3]; // left, center, right + EHeaderLine line; +}; + + + + +class CHexPrinter : public KPrinter +{ + public: + CHexPrinter( void ); + + void setPageMarginMM( uint top, uint bottom, int right, int left ); + void setTopMarginMM( uint value ); + void setLeftMarginMM( uint value ); + void setBottomMarginMM( uint value ); + void setRightMarginMM( uint value ); + void setPageHeader( bool enable, uint left, uint center, uint right, + uint line ); + void setPageFooter( bool enable, uint left, uint center, uint right, + uint line ); + + inline SPageHeader pageHeader( void ); + inline SPageHeader pageFooter( void ); + SPageMargin pageMargin( void ); + SPageMargin pageMarginMM( void ); + SPageSize pageFullSize( void ); + SPageSize pageUsableSize( void ); + + private: + SPageMargin mPageMargin; + SPageHeader mHeader; + SPageHeader mFooter; + + +}; + + +inline SPageHeader CHexPrinter::pageHeader( void ) +{ + return( mHeader ); +} + +inline SPageHeader CHexPrinter::pageFooter( void ) +{ + return( mFooter ); +} + +#endif diff --git a/khexedit/hextoolwidget.cc b/khexedit/hextoolwidget.cc new file mode 100644 index 0000000..f0baf09 --- /dev/null +++ b/khexedit/hextoolwidget.cc @@ -0,0 +1,416 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <kdialog.h> +#include <klocale.h> + +#include "hextoolwidget.h" +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qcheckbox.h> +#include <qcombobox.h> + + +CHexToolWidget::CHexToolWidget( QWidget *parent, const char *name ) + : QFrame( parent, name ) +{ + setFrameStyle( QFrame::Panel | QFrame::Raised ); + setLineWidth( 1 ); + + QString text; + mUtilBox = new QGridLayout( this, 5, 4, KDialog::marginHint(), KDialog::spacingHint() ); + mUtilBox->setColStretch( 3, 10 ); + + QString msg1[4] = + { + i18n("Signed 8 bit:"), i18n("Unsigned 8 bit:"), + i18n("Signed 16 bit:"), i18n("Unsigned 16 bit:") + }; + + QString msg2[4] = + { + i18n("Signed 32 bit:"), i18n("Unsigned 32 bit:"), + i18n("32 bit float:"), i18n("64 bit float:") + }; + + QString msg3[4] = + { + i18n("Hexadecimal:"), i18n("Octal:"), + i18n("Binary:"), i18n("Text:") + }; + + QGridLayout *ValuesBox = new QGridLayout( this, 4, 6, 0, KDialog::spacingHint() ); + ValuesBox->setColStretch( 2, 10 ); + ValuesBox->setColStretch( 5, 10 ); + + for( int i=0; i<4; i++ ) + { + QLabel *Label = new QLabel( msg1[i], this ); + Label->setAlignment( AlignRight|AlignVCenter ); + ValuesBox->addWidget( Label, i, 0 ); + + mText1[i] = new QLineEdit( this ); + mText1[i]->setReadOnly( true ); + mText1[i]->setAlignment( AlignRight ); + ValuesBox->addWidget( mText1[i], i, 1 ); + + Label = new QLabel( msg2[i], this ); + Label->setAlignment( AlignRight|AlignVCenter ); + ValuesBox->addWidget( Label, i, 3 ); + + mText2[i] = new QLineEdit( this ); + mText2[i]->setReadOnly( true ); + mText2[i]->setAlignment( AlignRight ); + ValuesBox->addWidget( mText2[i], i, 4 ); + + Label = new QLabel( msg3[i], this ); + Label->setAlignment( AlignRight|AlignVCenter ); + mUtilBox->addWidget( Label, i, 1 ); + + mText3[i] = new QLineEdit( this ); + mText3[i]->setReadOnly( true ); + mText3[i]->setAlignment( AlignRight ); + mUtilBox->addWidget( mText3[i], i, 2 ); + } + + QBoxLayout * SettingsBox = new QHBoxLayout( this, 0, KDialog::spacingHint() ); + + text = i18n("Show little endian decoding"); + mCheckIntelFormat = new QCheckBox( text, this ); + mCheckIntelFormat->setMinimumSize( mCheckIntelFormat->sizeHint() ); + connect( mCheckIntelFormat, SIGNAL(clicked()), this, SLOT(intelFormat()) ); + SettingsBox->addWidget( mCheckIntelFormat, 0, AlignVCenter ); + mCheckIntelFormat->setChecked( // default value to please endian system users +#ifdef WORDS_BIGENDIAN + false // Big Endian: SUN, Motorola machines (amongst others) +#else + true // Little Endian: Intel, Alpha +#endif + ); + // TODO: make this a pulldown box, adding PDP endianess + + text = i18n("Show unsigned as hexadecimal"); + mCheckHexadecimal = new QCheckBox( text, this ); + mCheckHexadecimal->setMinimumSize( mCheckHexadecimal->sizeHint() ); + connect( mCheckHexadecimal, SIGNAL(clicked()), this, SLOT(unsignedFormat()) ); + SettingsBox->addWidget( mCheckHexadecimal, 0, AlignVCenter ); + + mUtilBox->addMultiCellLayout( ValuesBox, 0, 3, 0, 0, AlignLeft|AlignVCenter ); + mUtilBox->addMultiCellLayout( SettingsBox, 4, 4, 0, 0, AlignLeft|AlignVCenter ); + + // + // Variable bitwidth. Based on Craig Graham's work. + // + QLabel *bitLabel = new QLabel( i18n("Stream length:"), this ); + bitLabel->setAlignment( AlignRight|AlignVCenter ); + mUtilBox->addWidget( bitLabel, 4, 1 ); + + mBitCombo = new QComboBox( false, this ); + text = i18n("Fixed 8 Bit" ); + mBitCombo->insertItem( text ); + for( int i=0; i<16; i++ ) + { + text.sprintf("%u ", i+1 ); + text += i==0 ? i18n("Bit Window") : i18n("Bits Window"); + mBitCombo->insertItem( text ); + } + mBitCombo->setMinimumSize( mBitCombo->sizeHint() ); + connect( mBitCombo, SIGNAL(activated(int)), SLOT(bitWidthChanged(int))); + mUtilBox->addWidget( mBitCombo, 4, 2 ); + + /* load font metrics */ + fontChanged(); + + mUtilBox->activate(); + + connect( kapp, SIGNAL( kdisplayFontChanged() ), + SLOT( fontChanged() ) ); + + mCursorState.valid = false; + mViewHexCaps = true; + + setMinimumSize( sizeHint() ); + show(); +} + + +CHexToolWidget::~CHexToolWidget( void ) +{ +} + + +void CHexToolWidget::writeConfiguration( KConfig &config ) +{ + config.setGroup("Conversion" ); + config.writeEntry("LittleEndian", mCheckIntelFormat->isChecked() ); + config.writeEntry("UnsignedAsHex", mCheckHexadecimal->isChecked() ); + config.writeEntry("StreamWindow", mBitCombo->currentItem() ); +} + +void CHexToolWidget::readConfiguration( KConfig &config ) +{ + config.setGroup("Conversion" ); + bool s1 = config.readBoolEntry( "LittleEndian", true ); + bool s2 = config.readBoolEntry( "UnsignedAsHex", false ); + int val = config.readNumEntry( "StreamWindow", 0 ); + + mCheckIntelFormat->setChecked( s1 ); + mCheckHexadecimal->setChecked( s2 ); + mBitCombo->setCurrentItem( val ); +} + +//++cg[6/7/1999]: handler for change signal from bit width combo +void CHexToolWidget::bitWidthChanged( int /*i*/ ) +{ + cursorChanged( mCursorState ); +} + + +// +// Variable bitwidth. Based on Craig Graham's work. +// +// ++cg[6/7/1999]: Read n bit's from a bitstream (allows N length bit +// values to cross byte boundarys). +// +unsigned long CHexToolWidget::bitValue( SCursorState &state, int n ) +{ + static const unsigned char bitmask[9] = + { + 0, 1<<7, 3<<6, 7<<5, 15<<4, 31<<3, 63<<2, 127<<1, 255 + }; + + unsigned long rtn = 0; + unsigned char *byte = state.data; + int bit = 7 - state.cell; + + while( n ) + { + // + // c hold's current byte, shifted to put remaining bits in + // high bits of byte + // + unsigned char c = *byte << bit; + + // + // if there are n bits or more remaining in this byte, we + // swallow n bits, otherwise we swallow as many + // bits as we can (8-bit) + // + int this_time = ((8-bit)>=n)?n:(8-bit); + + // + // mask to get only the bit's we're swallowing + // + c &= bitmask[this_time]; + + // + // shift down to get bit's in low part of byte + // + c >>= 8-this_time; + + // + // shift up previous results to make room and OR in the extracted bits. + // + rtn = (rtn<<this_time)|c; + + n -= this_time; // update the count of remaining bits + bit += this_time; // tell the stream we swallowed some swallowed bits + + // + // if we've swallowed 8 bits, we zero the bit count and move on to + // the next byte + // + if( bit==8 ) + { + bit=0; + byte++; + } + } + + return( rtn ); +} + + +void CHexToolWidget::cursorChanged( SCursorState &state ) +{ + if( state.valid == true ) + { + QString buf; + // change by Kossebau[03.11.2003]: + // checking for system endianess, using the compiler for the byte interpretation and cutting bloaded code + // TODO: add PDP endianess + void *P8Bit, *P16Bit, *P32Bit, *P64Bit; + // ensure strict alignment for double as needed on some architectures (e.g. PA-RISC) + typedef union { unsigned char b[8]; double d; } aligned_t; + aligned_t Data; + if( +#ifdef WORDS_BIGENDIAN + ! // Assume Big Endian. This is the case for SUN machines (amongst others) +#else + // Assume Little Endian. This is the case for the Intel architecture. +#endif + mCheckIntelFormat->isChecked() ) + { + // take it as it is + memcpy( Data.b, state.data, 8 ); + P8Bit = P16Bit = P32Bit = P64Bit = Data.b; + } + else + { + // reverse order + for( int i=0,j=7; i<8; ++i,--j ) + Data.b[i] = state.data[j]; + + P8Bit = &Data.b[7]; + P16Bit = &Data.b[6]; + P32Bit = &Data.b[4]; + P64Bit = Data.b; + } + + bool NoHex = !mCheckHexadecimal->isChecked(); + + // unsigned 8 bit + buf.sprintf( NoHex?"%u":mViewHexCaps?"0x%02X":"0x%02x", *(unsigned char*)P8Bit ); + mText1[1]->setText( buf ); + // signed int 8 bit + buf.sprintf( "%d", *(signed char*)P8Bit ); + mText1[0]->setText( buf ); + + // unsigned int 16 bit + buf.sprintf( NoHex?"%u":mViewHexCaps?"0x%04X":"0x%04x", *(unsigned short*)P16Bit ); + mText1[3]->setText( buf ); + // signed int 16 bit + buf.sprintf( "%d", *(short*)P16Bit ); + mText1[2]->setText( buf ); + + // unsigned int 32 bit + buf.sprintf( NoHex?"%u":mViewHexCaps?"0x%08X":"0x%08x", *(unsigned int*)P32Bit ); + mText2[1]->setText( buf ); + // signed int 32 bit + buf.sprintf( "%d", *(int*)P32Bit ); + mText2[0]->setText( buf ); + + // float 32 bit + buf.sprintf( "%E", *(float*)P32Bit ); + mText2[2]->setText( buf ); + // float 64 bit + buf.sprintf( "%E", *(double*)P64Bit ); + mText2[3]->setText( buf ); + + int numBits = mBitCombo->currentItem(); + if( numBits == 0 ) + { + // + // This is the original stuff + // + unsigned char data = (unsigned char)state.data[0]; + buf.sprintf( mViewHexCaps?"%02X":"%02x", data ); + mText3[0]->setText( buf ); + buf.sprintf( "%03o", data ); + mText3[1]->setText( buf ); + + char bitBuf[32]; + for( int i = 0; i < 8; i++ ) + bitBuf[7-i] = (data&(1<<i)) ? '1' : '0'; + + bitBuf[8] = 0; + mText3[2]->setText( QString(bitBuf) ); + } + else + { + // + // Variable bitwidth. Based on Craig Graham's work. + // + unsigned long data = bitValue( state, numBits ); + buf.sprintf( mViewHexCaps?"%02lX %02lX":"%02lx %02lx", (data>>8)&0xFF, data&0xFF ); + mText3[0]->setText( buf ); + buf.sprintf( "%03lo %03lo", (data>>8)&0xFF, data&0xFF ); + mText3[1]->setText( buf ); + char bitBuf[32]; + for( int i = 0; i<numBits; i++ ) + bitBuf[numBits-i-1] = (data&(1L<<i)) ? '1' : '0'; + bitBuf[numBits] = 0; + mText3[2]->setText( QString(bitBuf) ); + } + + // Fix by Sergey A. Sukiyazov + unsigned char data[2] = { 0, 0 }; + data[0] = state.charValid == false ? '.' : + (char)((unsigned char)state.data[0]&0xff ); + buf = QString::fromLocal8Bit( (const char *)data ); + + mText3[3]->setText( buf ); + } + else + { + QString str; + for( int i=0; i<4; i++) + { + mText1[i]->setText( str ); + mText2[i]->setText( str ); + mText3[i]->setText( str ); + } + } + + mCursorState = state; +} + + +void CHexToolWidget::fontChanged( void ) +{ + QFontMetrics fm( mText1[0]->font() ); + int W1 = fm.width( "XXXXXXXX" ); + int W2 = fm.width( "XXXXXXXXXXXX" ); + int W3 = fm.width( "888888888888888888" ); + for( int i=0; i<4; i++ ) + { + mText1[i]->setFixedWidth( W1 ); + mText2[i]->setFixedWidth( W2 ); + mText3[i]->setFixedWidth( W3 ); + } +} + + +void CHexToolWidget::intelFormat( void ) +{ + cursorChanged( mCursorState ); +} + + +void CHexToolWidget::unsignedFormat( void ) +{ + cursorChanged( mCursorState ); +} + + +void CHexToolWidget::resizeEvent( QResizeEvent */*e*/ ) +{ +} + + + +void CHexToolWidget::closeEvent( QCloseEvent *e ) +{ + e->accept(); + emit closed(); +} + +#include "hextoolwidget.moc" diff --git a/khexedit/hextoolwidget.h b/khexedit/hextoolwidget.h new file mode 100644 index 0000000..d2ce892 --- /dev/null +++ b/khexedit/hextoolwidget.h @@ -0,0 +1,81 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_TOOL_WIDGET_H_ +#define _HEX_TOOL_WIDGET_H_ + +#include <kconfig.h> + +class QGridLayout; +class QComboBox; +class QLineEdit; +class QCheckBox; + +#include "hexbuffer.h" +#include <qframe.h> + +class CHexToolWidget : public QFrame +{ + Q_OBJECT + + public: + CHexToolWidget( QWidget *parent = 0, const char *name = 0 ); + ~CHexToolWidget( void ); + + void writeConfiguration( KConfig &config ); + void readConfiguration( KConfig &config ); + unsigned long bitValue( SCursorState &state, int n ); + + protected: + void resizeEvent( QResizeEvent *e ); + void closeEvent( QCloseEvent *e ); + + public slots: + void cursorChanged( SCursorState &state ); + void fontChanged( void ); + void intelFormat( void ); + void unsignedFormat( void ); + void bitWidthChanged( int i ); + + signals: + void closed( void ); + + + private: + + private: + SCursorState mCursorState; + bool mViewHexCaps; + + QGridLayout *mUtilBox; + QLineEdit *mText1[4]; + QLineEdit *mText2[4]; + QLineEdit *mText3[4]; + QCheckBox *mCheckIntelFormat; + QCheckBox *mCheckHexadecimal; + QComboBox *mBitCombo; +}; + + + + + + +#endif diff --git a/khexedit/hexvalidator.cc b/khexedit/hexvalidator.cc new file mode 100644 index 0000000..e8c1731 --- /dev/null +++ b/khexedit/hexvalidator.cc @@ -0,0 +1,329 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <ctype.h> +#include <stdio.h> +#include <qwidget.h> +#include "hexvalidator.h" + +CHexValidator::CHexValidator( QWidget *parent, EState state, + const char *name ) + :QValidator( parent, name ) +{ + setState( state ); +} + +CHexValidator::~CHexValidator( void ) +{ +} + +QValidator::State CHexValidator::validate( QString &string, int &/*pos*/ ) const +{ + if( mState == hexadecimal ) + { + for( uint i=0; i < string.length(); i++ ) + { + int val = string[i].latin1(); + if( isxdigit( val ) == 0 && isspace( val ) == 0 ) + { + return( QValidator::Invalid ); + } + } + return( QValidator::Valid ); + } + if( mState == decimal ) + { + for( uint i=0; i < string.length(); i++ ) + { + int val = string[i].latin1(); + if( isdigit( val ) == 0 && isspace( val ) == 0 ) + { + return( QValidator::Invalid ); + } + } + return( QValidator::Valid ); + } + else if( mState == octal ) + { + for( uint i=0; i < string.length(); i++ ) + { + int val = string[i].latin1(); + if( (isdigit( val ) == 0 || val == '8' || val == '9') && + isspace( val ) == 0 ) + { + return( QValidator::Invalid ); + } + } + return( QValidator::Valid ); + } + else if( mState == binary ) + { + for( uint i=0; i < string.length(); i++ ) + { + int val = string[i].latin1(); + if( val != '0' && val != '1' && isspace( val ) == 0 ) + { + return( QValidator::Invalid ); + } + } + return( QValidator::Valid ); + } + else if( mState == regularText ) + { + return( QValidator::Valid ); + } + else + { + return( QValidator::Invalid ); + } + +} + + +void CHexValidator::setState( EState state ) +{ + mState = state; +} + + +void CHexValidator::convert( QByteArray &dest, const QString &src ) +{ + uint value; + uint k=0; + + if( mState == hexadecimal ) + { + dest.resize(0); + + char buf[3]; + for( uint i=0; i < src.length(); i++ ) + { + int val = src[i].latin1(); + if( isxdigit(val) ) + { + buf[k++] = val; + if( k == 2 ) + { + buf[k] = 0; + sscanf( buf, "%X", &value ); + + dest.resize( dest.size()+1 ); + dest[ dest.size()-1 ] = value; + k = 0; + } + } + } + + if( k == 1 ) + { + buf[1] = buf[0]; + buf[0] = '0'; + buf[2] = 0; + sscanf( buf, "%X", &value ); + + dest.resize( dest.size()+1 ); + dest[ dest.size()-1 ] = value; + } + + } + else if( mState == decimal ) + { + dest.resize(0); + + char buf[4]; + for( uint i=0; i < src.length(); i++ ) + { + int val = src[i].latin1(); + if( isdigit(val) ) + { + buf[k++] = val; + if( k == 3 ) + { + buf[k] = 0; + sscanf( buf, "%u", &value ); + + dest.resize( dest.size()+1 ); + dest[ dest.size()-1 ] = value; + k = 0; + } + } + } + + if( k == 1 || k == 2 ) + { + if( k == 1 ) + { + buf[2] = buf[0]; + buf[0] = buf[1] = '0'; + } + else + { + buf[2] = buf[1]; + buf[1] = buf[0]; + buf[0] = '0'; + } + buf[3] = 0; + sscanf( buf, "%u", &value ); + + dest.resize( dest.size()+1 ); + dest[ dest.size()-1 ] = value; + } + } + + else if( mState == octal ) + { + dest.resize(0); + + char buf[4]; + for( uint i=0; i < src.length(); i++ ) + { + int val = src[i].latin1(); + if( isdigit(val) ) + { + buf[k++] = val; + if( k == 3 ) + { + if( buf[0] > '3' ) { buf[0] = '3'; } + buf[k] = 0; + sscanf( buf, "%o", &value ); + + dest.resize( dest.size()+1 ); + dest[ dest.size()-1 ] = value; + k = 0; + } + } + } + + if( k == 1 || k == 2 ) + { + if( k == 1 ) + { + buf[2] = buf[0]; + buf[0] = buf[1] = '0'; + } + else + { + buf[2] = buf[1]; + buf[1] = buf[0]; + buf[0] = '0'; + } + buf[3] = 0; + sscanf( buf, "%o", &value ); + + dest.resize( dest.size()+1 ); + dest[ dest.size()-1 ] = value; + } + } + else if( mState == binary ) + { + dest.resize(0); + + char buf[9]; + for( uint i=0; i < src.length(); i++ ) + { + int val = src[i].latin1(); + if( isdigit(val) ) + { + buf[k++] = val; + if( k == 8 ) + { + value = 0; + for( uint j=0; j < 8; j++ ) + { + value |= (buf[8-j-1] == '1') ? 1<<j : 0; + } + + dest.resize( dest.size()+1 ); + dest[ dest.size()-1 ] = value; + k = 0; + } + } + } + + if( k > 0 ) + { + value = 0; + for( uint j=0; j < k; j++ ) + { + value |= (buf[k-j-1] == '1') ? 1<<j : 0; + } + + dest.resize( dest.size()+1 ); + dest[ dest.size()-1 ] = value; + } + } + else if( mState == regularText ) + { + dest.resize(src.length()); + for( uint i=0; i < src.length(); i++ ) + { + dest[i] = src[i].latin1(); + } + + } + else + { + dest.resize(0); + } +} + + + +void CHexValidator::format( QString &dest, const QByteArray &src ) +{ + for( uint i=0; i<src.size(); ++i ) + { + unsigned char srcCh = (unsigned char)src[i]; + QString formattedCh; + + switch( mState ) + { + case hexadecimal: + formattedCh = zeroExtend( QString::number( srcCh, 16 ), 2 ); + break; + case decimal: + formattedCh = zeroExtend( QString::number( srcCh, 10), 3 ); + break; + case octal: + formattedCh = zeroExtend( QString::number( srcCh, 8), 3 ); + break; + case binary: + formattedCh = zeroExtend( QString::number( srcCh, 2), 8 ); + break; + case regularText: + formattedCh = QString( QChar( srcCh ) ); + break; + } + + dest += formattedCh + " "; + } +} + + +QString CHexValidator::zeroExtend( const QString &src, unsigned destLen) const +{ + if( src.length() >= destLen ) + return src; + + QString zeroes; + zeroes.fill( '0', destLen - src.length() ); + return zeroes + src; +} +#include "hexvalidator.moc" diff --git a/khexedit/hexvalidator.h b/khexedit/hexvalidator.h new file mode 100644 index 0000000..cfe9f95 --- /dev/null +++ b/khexedit/hexvalidator.h @@ -0,0 +1,63 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_VALIDATOR_H_ +#define _HEX_VALIDATOR_H_ + +#include <qvalidator.h> + +class CHexValidator: public QValidator +{ + Q_OBJECT + + public: + enum EState + { + hexadecimal = 0, + decimal, + octal, + binary, + regularText + }; + + public: + CHexValidator( QWidget *parent, EState state, const char *name = 0 ); + ~CHexValidator( void ); + QValidator::State validate( QString &string, int &pos ) const; + void setState( EState state ); + void convert( QByteArray &dest, const QString &src ); + void format( QString &dest, const QByteArray &src ); + + private: + /** + * Returns a string that is at least as long as @p destLen number of characters, + * by adding zeroes to the left as necessary. + * + * e.g. zeroExtend( "32", 3 ) => "032" + */ + QString zeroExtend( const QString &src, unsigned destLen ) const; + + EState mState; + + +}; + + +#endif diff --git a/khexedit/hexviewwidget.cc b/khexedit/hexviewwidget.cc new file mode 100644 index 0000000..12226ed --- /dev/null +++ b/khexedit/hexviewwidget.cc @@ -0,0 +1,2286 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <iostream> + +#include <qclipboard.h> +#include <qdrawutil.h> + + +#include <kglobalsettings.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kdebug.h> +#include <kurldrag.h> + +#include "hexdrag.h" +#include "hexerror.h" +#include "hexviewwidget.h" + +// +// The usage of the WNorthWestGravity flag should make screen update +// faster (less paintEvents). I have had to add update() some places +// to ensure proper redrawing. Undefine if something goes wrong +// (i.e. not updated ) +// +#define USE_NORTHWEST_GRAVITY 1 + +// +// I don't want to decide what is best: Drag starts when mouse is moved or +// after a timeout. +// +#define USE_DRAG_MOVEMENT 1 + + + + + + +CDragManager::CDragManager( void ) +{ + mActivateMode = Movement; + mPending = false; + mTimerId = 0; +} + +void CDragManager::setActivateMode( EDragActivateMode mode ) +{ + clear(); + mActivateMode = mode; // Movement or Timer +} + +void CDragManager::setup( int x, int y ) +{ + if( mActivateMode == Movement ) + { + mOrigin.setX(x); + mOrigin.setY(y); + } + else + { + setupTimer(); + } + mPending = true; +} + +bool CDragManager::start( QMouseEvent *e ) +{ + if( mPending == false ) + { + return( false ); + } + + if( mActivateMode == Movement ) + { + if( (mOrigin - e->pos()).manhattanLength() > KGlobalSettings::dndEventDelay() ) + { + mPending = false; + emit startDrag( e->state() & ShiftButton ? true : false ); + } + return( true ); + } + else // Timer + { + if( mTimerId != 0 ) + { + removeTimer(); + mPending = false; + emit startDrag( e->state() & ShiftButton ? true : false ); + return( true ); + } + else + { + // Should never happen! + mPending = false; + return( false ); + } + } + +} + +bool CDragManager::clear( void ) +{ + if( mPending == false ) + { + return( false ); + } + + if( mActivateMode == Timer ) + { + removeTimer(); + } + + mPending = false; + return( true ); +} + +void CDragManager::timerEvent( QTimerEvent *e ) +{ + if( e->timerId() == mTimerId ) + { + removeTimer(); + if( mPending == true ) + { + mPending = false; + emit startDrag( ( kapp->keyboardModifiers() & KApplication::ShiftModifier ) ); + } + } +} + +void CDragManager::removeTimer( void ) +{ + if( mTimerId != 0 ) + { + killTimer( mTimerId ); + mTimerId = 0; + } +} + +void CDragManager::setupTimer( void ) +{ + if( mTimerId != 0 ) + { + killTimer( mTimerId ); + mTimerId = 0; + } + mTimerId = startTimer( 500 ); +} + + +// +// This widget will use the entire space of the parent widget +// +CHexViewWidget::CHexViewWidget( QWidget *parent, const char *name, + CHexBuffer *hexBuffer ) + : QFrame( parent, name, + #ifdef USE_NORTHWEST_GRAVITY + Qt::WStaticContents + #else + 0 + #endif + ), mScrollBarSize( 16 ) +{ + if( parent == 0 || hexBuffer == 0 ) { return; } + + // + // Qt 2.0: + // ------- + // I use the "CScrollBar" because sometimes (very seldom) when I + // do a mHorzScroll->hide() the mHorzScroll->isVisible() remains true + // in updateView() for a short while. I need the correct visibility + // because I have to redraw the area - due to the "WNorthWestGravity" usage. + // + // I tried to do a + // "while( mHorzScroll->isVisible() ) { mHorzScroll->hide(); }" + // but then the loop never ended. The "CScrollBar" emits a "hidden()" + // signal whenever is receives a QHideEvent. + // + + mVertScroll = new CScrollBar( QScrollBar::Vertical, this ); + if( mVertScroll == 0 ) { return; } + mHorzScroll = new CScrollBar( QScrollBar::Horizontal, this ); + if( mHorzScroll == 0 ) { return; } + mCorner = new QWidget( this ); + if( mCorner == 0 ) { return; } + connect( mHorzScroll, SIGNAL(valueChanged(int)), SLOT(changeXPos(int)) ); + connect( mVertScroll, SIGNAL(valueChanged(int)), SLOT(changeYPos(int)) ); + connect( mHorzScroll, SIGNAL(hidden()), SLOT(update()) ); + connect( mVertScroll, SIGNAL(hidden()), SLOT(update()) ); + mHorzScroll->hide(); + mVertScroll->hide(); + + mDragManager = new CDragManager(); + if( mDragManager == 0 ) { return; } + #ifdef USE_DRAG_MOVEMENT + mDragManager->setActivateMode( CDragManager::Movement ); + #else + mDragManager->setActivateMode( CDragManager::Timer ); + #endif + connect( mDragManager, SIGNAL(startDrag(bool)), SLOT(startDrag(bool)) ); + + setFrameStyle( QFrame::WinPanel|QFrame::Sunken ); + setWFlags( WResizeNoErase ); + setFocusPolicy( StrongFocus ); + + mHexBuffer = hexBuffer; + mHexBuffer->cursorReset(); + + mEditMode = mHexBuffer->editMode(); + mShowCursor = false; + mCursorTimerId = 0; + + mDocumentMenu = 0; + + setTextBufferSize(); // Make sure there is a pixmap buffer + setStartX(0); + setStartY(0); + + setAcceptDrops(true); + setDropHighlight(false); // Init state + frame shape + setBackgroundColor( mHexBuffer->backgroundColor() ); +} + + +CHexViewWidget::~CHexViewWidget( void ) +{ + delete mVertScroll; + delete mHorzScroll; + delete mCorner; + delete mDragManager; +} + + +int CHexViewWidget::readFile( QFile &file, const QString &url, CProgress &p ) +{ + int errCode = mHexBuffer->readFile( file, url, p ); + if( errCode != Err_Success ) + { + return( errCode ); + } + + initFile(); + return( Err_Success ); +} + + +int CHexViewWidget::insertFile( QFile &file, CProgress &p ) +{ + int errCode = mHexBuffer->insertFile( file, p ); + if( errCode != Err_Success ) + { + return( errCode ); + } + + updateWindow( true, true ); + + emit dataChanged(); + emit cursorChanged( mHexBuffer->cursorState() ); + emit layoutChanged( mLayout ); + return( Err_Success ); +} + + +int CHexViewWidget::newFile( const QString &url ) +{ + int errCode = mHexBuffer->newFile( url ); + if( errCode != Err_Success ) + { + return( errCode ); + } + + initFile(); + return( Err_Success ); +} + + +int CHexViewWidget::writeFile( QFile &file, CProgress &p ) +{ + int errCode = mHexBuffer->writeFile( file, p ); + if( errCode == Err_Success ) + { + emit fileState( mHexBuffer->fileState() ); + } + return( errCode ); +} + + +void CHexViewWidget::closeFile( void ) +{ + emit fileClosed( mHexBuffer->url() ); + mHexBuffer->closeFile(); + initFile(); +} + + + +void CHexViewWidget::initFile( void ) +{ + setStartX(0); + setStartY(0); + + mHexBuffer->cursorReset(); + mHexBuffer->setLayout( mLayout ); + mHexBuffer->setFont( mFontInfo ); + setEditMode( mEditMode ); + setColor( mColor, false ); + setCursor( mCursor, false ); + setMisc( mMisc ); + + setBackgroundColor( mHexBuffer->backgroundColor() ); + setBackgroundMode( NoBackground ); + + updateView( true, false ); + resizeEvent( 0 ); + + emit dataChanged(); + emit cursorChanged( mHexBuffer->cursorState() ); + emit fileState( mHexBuffer->fileState() ); + emit encodingChanged( mHexBuffer->encoding() ); + emit fileName( mHexBuffer->url(), mHexBuffer->hasFileName() ); + emit bookmarkChanged( mHexBuffer->bookmarkList() ); +} + + +void CHexViewWidget::setBuffer( CHexBuffer *hexBuffer ) +{ + if( hexBuffer == 0 || mHexBuffer == hexBuffer ) + { + return; + } + + unselect(); + unmark(); + + mHexBuffer = hexBuffer; + mHexBuffer->setLayout( mLayout ); + mHexBuffer->setFont( mFontInfo ); + setEditMode( mEditMode ); + setColor( mColor, false ); + setCursor( mCursor, false ); + setMisc( mMisc ); + + if( mLayout.lockLine == false ) + { + mHexBuffer->matchWidth( width() ); + } + + setBackgroundColor( hexBuffer->backgroundColor() ); + setBackgroundMode( NoBackground ); + + setEditMode( mEditMode ); + updateWindow(); + + emit dataChanged(); + emit cursorChanged( mHexBuffer->cursorState() ); + emit fileState( mHexBuffer->fileState() ); + emit encodingChanged( mHexBuffer->encoding() ); + emit layoutChanged( mLayout ); + emit inputModeChanged( mHexBuffer->inputMode() ); + emit fileName( mHexBuffer->url(), mHexBuffer->hasFileName() ); + emit bookmarkChanged( mHexBuffer->bookmarkList() ); +} + + + + +void CHexViewWidget::changeXPos( int p ) +{ + int dx = startX() - p; + setStartX(p); + + + if( QABS(dx) < width() ) + { + scroll( dx, 0, contentsRect() ); + } + else + { + QWidget::update(); + } + + // + // If the start position has become 0, then update the view. This + // will remove the scrollbar (if it is visible) if the textarea width + // is wider than the text. The scrollbar will then disappear under the + // mouse pointer. + // + if( startX() == 0 ) + { + updateView( false, false ); + } + +} + + +void CHexViewWidget::changeYPos( int p ) +{ + int dy = startY() - p; + setStartY(p); + + if( QABS( dy ) < height() ) + { + scroll( 0, dy, contentsRect() ); + } + else + { + QWidget::update(); + } + + // + // If the start position has become 0, then update the view. This + // will remove the scrollbar (if it is visible) if the textarea height + // is taller than the text. The scrollbar will then disappear under the + // mouse pointer. + // + if( startY() == 0 ) + { + updateView( false, false ); + } +} + + +void CHexViewWidget::clipboardChanged( void ) +{ + disconnect(QApplication::clipboard(),SIGNAL(dataChanged()), + this,SLOT(clipboardChanged())); + unselect(); +} + +void CHexViewWidget::paletteChanged( void ) +{ + setColor( mColor, true ); +} + + +void CHexViewWidget::fontChanged( void ) +{ + //setFont( kapp->fixedFont, true ); +} + +void CHexViewWidget::filter( SFilterControl &fc ) +{ + int errCode = mHexBuffer->filter( fc ); + if( errCode == Err_Success ) + { + repaint(); + emit dataChanged(); + emit cursorChanged( mHexBuffer->cursorState() ); + } +} + + + +void CHexViewWidget::insert( SInsertData &id ) +{ + if( id.onCursor == false ) + { + mHexBuffer->cursorGoto( id.offset, 7 ); + } + SCursorConfig cc; + updateCursor( cc, true ); + + if( id.size == 0 ) + { + return; + } + + QByteArray buf( id.size ); + if( buf.isNull() == true ) + { + return; + } + buf.fill( 0 ); + + if( id.pattern.size() > 0 ) + { + uint size = id.pattern.size()>buf.size() ? buf.size() : id.pattern.size(); + if( id.repeatPattern == false ) + { + memcpy( &buf[0], &id.pattern[0], size ); + if( size < buf.size() ) + { + memset( &buf[size], id.pattern[id.pattern.size()-1], buf.size()-size ); + } + } + else + { + for( uint i=0; i < buf.size(); i+= size ) + { + uint s = i+size > buf.size() ? buf.size()-i : size; + memcpy( &buf[i], &id.pattern[0], s ); + } + } + } + + insert( buf ); +} + + +void CHexViewWidget::insert( const QByteArray &buf ) +{ + if( mHexBuffer->documentPresent() == false ) + { + emit pleaseOpenNewFile(); + if( mHexBuffer->documentPresent() == false ) + { + return; + } + } + + uint offset = mHexBuffer->cursorOffset(); + int errCode = mHexBuffer->inputAtCursor( buf, 0 ); + if( errCode == Err_Success ) + { + updateWindow( offset, true ); + emit dataChanged(); + } +} + + +void CHexViewWidget::append( const QByteArray &buf ) +{ + if( mHexBuffer->documentPresent() == false ) + { + insert( buf ); + } + else + { + SCursorConfig cc; + cc.emulateControlButton( true ); + cursorEnd( cc ); + + int errCode = mHexBuffer->inputAtCursor( buf, 0 ); + if( errCode == Err_Success ) + { + updateWindow( true, true ); + emit dataChanged(); + } + } +} + + +void CHexViewWidget::valueOnCursor( QByteArray &buf, uint size ) +{ + mHexBuffer->valueOnCursor( buf, size ); +} + + + +void CHexViewWidget::updateView( bool redraw, bool fixCursor ) +{ + int f2 = frameWidth() * 2; + int scrollBarCount = 0; // Number of visible scrollbars + int editWidth = 0; + int editHeight = 0; + + for( uint i=0; i < 2; i++ ) + { + editWidth = width() - f2; // Total available width + editHeight = height() - f2; // Total available height + int textWidth = dataWidth(); + int textHeight = mHexBuffer->totalHeight(); + + // + // This will move the start position of the horizontal scrollbar + // to the left (if possible) if the text width is smaller than the + // edit width. + // + if( startX() > 0 ) + { + int size = mVertScroll->isVisible() == true ? mScrollBarSize : 0; + if( startX() + editWidth - size > textWidth ) + { + int position = textWidth - editWidth + size; + setStartX( position > 0 ? position : 0 ); + #ifdef USE_NORTHWEST_GRAVITY + redraw = true; + #endif + } + } + + int tooMuchX = textWidth - editWidth; + bool horzScrollbarVisible = startX() > 0 || tooMuchX > 0 ? true : false; + if( horzScrollbarVisible == true ) + { + editHeight -= mScrollBarSize; + } + + + // + // This will move the start position of the vertical scrollbar + // to the top (if possible) if the text height is smaller than the + // edit height. + // + if( startY() > 0 ) + { + if( startY() + editHeight > textHeight ) + { + int position = textHeight - editHeight; + setStartY( position > 0 ? position : 0 ); + #ifdef USE_NORTHWEST_GRAVITY + redraw = true; + #endif + } + } + + int tooMuchY = textHeight - editHeight; + int startLine = startY() / textHeight; + + if( startLine > 0 || tooMuchY > 0 ) + { + editWidth -= mScrollBarSize; + tooMuchX += mScrollBarSize; + if( horzScrollbarVisible == false && tooMuchX > 0 ) + { + // Horizontal scrollbar will be visible after all. + editHeight -= mScrollBarSize; + tooMuchY += mScrollBarSize; + } + } + + if( tooMuchX < startX() ) { tooMuchX = startX(); } + if( tooMuchY < startY() ) { tooMuchY = startY(); } + + scrollBarCount = 0; + if( tooMuchX > 0 && documentPresent() == true ) + { + mHorzScroll->blockSignals( true ); + mHorzScroll->setGeometry( 0, editHeight+f2, editWidth+f2,mScrollBarSize); + mHorzScroll->setRange( 0, tooMuchX ); + mHorzScroll->setValue( startX() ); + mHorzScroll->setSteps(mHexBuffer->lineHeight(),editWidth-mScrollBarSize); + mHorzScroll->blockSignals( false ); + if( mHorzScroll->isVisible() == false ) { mHorzScroll->show(); } + scrollBarCount ++; + } + else + { + if( mHorzScroll->isVisible() == true ) { mHorzScroll->hide(); } + } + + if( tooMuchY > 0 && documentPresent() == true ) + { + mVertScroll->blockSignals( true ); + mVertScroll->setGeometry( editWidth+f2, 0, mScrollBarSize,editHeight+f2); + mVertScroll->setRange( 0, tooMuchY ); + mVertScroll->setValue( startY() ); + mVertScroll->setSteps(mHexBuffer->lineHeight(), + editHeight-mScrollBarSize ); + mVertScroll->blockSignals( false ); + if( mVertScroll->isVisible() == false ) { mVertScroll->show(); } + scrollBarCount ++; + } + else + { + if( mVertScroll->isVisible() == true ) { mVertScroll->hide(); } + } + + if( fixCursor == true ) + { + int position = mHexBuffer->cursorFixedPosition( startY(), height() ); + if( position != startY() ) + { + setStartY( position ); + fixCursor = false; + continue; + } + } + break; + } + + + if( scrollBarCount == 2 ) + { + mCorner->setGeometry( editWidth+f2, editHeight+f2, mScrollBarSize, + mScrollBarSize ); + mCorner->show(); + } + else + { + mCorner->hide(); + } + + + updateFrameSize(); + + if( redraw == true ) + { + QWidget::update(); + } +} + + +void CHexViewWidget::setPalette( const QPalette &p ) +{ + QWidget::setPalette( p ); + mCorner->setPalette( p ); + mVertScroll->setPalette( p ); + mHorzScroll->setPalette( p ); +} + + +void CHexViewWidget::setLayout( SDisplayLayout &layout ) +{ + mLayout = layout; + mHexBuffer->setLayout( mLayout ); + updateWindow(); + + emit layoutChanged( mLayout ); + emit cursorChanged( mHexBuffer->cursorState() ); + emit textWidth( defaultWidth() ); +} + + +void CHexViewWidget::setInputMode( SDisplayInputMode &input ) +{ + mHexBuffer->setInputMode( input ); + emit inputModeChanged( mHexBuffer->inputMode() ); +} + + +void CHexViewWidget::setCursor( const SDisplayCursor &cursor, + bool /*updateDisplay*/ ) +{ + mCursor = cursor; + mHexBuffer->setCursorShapeModifier( cursor.alwaysBlockShape, + cursor.thickInsertShape ); + setupCursorTimer(); + redrawFromOffset( mHexBuffer->cursorOffset(), false ); +} + +void CHexViewWidget::setColor( const SDisplayColor &color, + bool updateDisplay ) +{ + mColor = color; + mHexBuffer->setColor( mColor ); + if( updateDisplay == true ) + { + repaint(); + } +} + +void CHexViewWidget::setFont( const SDisplayFontInfo &fontInfo, + bool updateDisplay ) +{ + mFontInfo = fontInfo; + mHexBuffer->setFont( mFontInfo ); + emit textWidth( defaultWidth() ); + if( updateDisplay == true ) + { + updateWindow(); + } +} + + + +void CHexViewWidget::setMisc( SDisplayMisc &misc ) +{ + mMisc = misc; + mHexBuffer->setUndoLevel( misc.undoLevel ); + mHexBuffer->setSoundState( misc.inputSound, misc.fatalSound ); + mHexBuffer->setBookmarkVisibility( misc.bookmarkOffsetColumn, + misc.bookmarkEditor ); + if( mHexBuffer->documentPresent() == true ) + { + QWidget::update(); + } +} + + +void CHexViewWidget::setInsertMode( bool insertMode ) +{ + setEditMode( insertMode == true ? CHexBuffer::EditInsert : + CHexBuffer::EditReplace ); +} + + +int CHexViewWidget::setEncoding( CConversion::EMode mode, CProgress &p ) +{ + int errCode = mHexBuffer->setEncoding( mode, p ); + if( errCode == Err_Success ) + { + repaint(); + emit cursorChanged( mHexBuffer->cursorState() ); + emit encodingChanged( mHexBuffer->encoding() ); + } + return( errCode ); +} + + +void CHexViewWidget::reportEncoding( void ) +{ + emit encodingChanged( mHexBuffer->encoding() ); +} + + +void CHexViewWidget::selectAll( void ) +{ + setSelection( 0, true ); + setSelection( mHexBuffer->documentSize(), false ); + autoCopy(); + emit cursorChanged( mHexBuffer->cursorState() ); +} + +void CHexViewWidget::unselect( void ) +{ + setSelection( 0, true ); + emit cursorChanged( mHexBuffer->cursorState() ); +} + +void CHexViewWidget::unmark( void ) +{ + setMark( 0, 0, false ); +} + + +int CHexViewWidget::findFirst( SSearchControl &sc ) +{ + int errCode = mHexBuffer->findFirst( sc ); + if( errCode == Err_Success ) { updateWindow( true, false ); } + return( errCode ); +} + +int CHexViewWidget::findNext( SSearchControl &sc ) +{ + int errCode = mHexBuffer->findNext( sc ); + if( errCode == Err_Success ) { updateWindow( true, false ); } + return( errCode ); +} + +int CHexViewWidget::findWrap( SSearchControl &sc ) +{ + int errCode = mHexBuffer->findWrap( sc ); + if( errCode == Err_Success ) { updateWindow( true, false ); } + return( errCode ); +} + +int CHexViewWidget::replaceAll( SSearchControl &sc, bool init ) +{ + int errCode = mHexBuffer->replaceAll( sc, init ); + if( errCode == Err_Success ) + { + updateWindow( true, false ); + emit dataChanged(); + } + return( errCode ); +} + +int CHexViewWidget::replaceMarked( SSearchControl &sc ) +{ + int errCode = mHexBuffer->replaceMarked( sc ); + if( errCode == Err_Success ) + { + updateWindow( true, false ); + emit dataChanged(); + } + return( errCode ); +} + +int CHexViewWidget::collectStrings( CStringCollectControl &sc ) +{ + int errCode = mHexBuffer->collectStrings( sc ); + return( errCode ); +} + + +int CHexViewWidget::collectStatistic( SStatisticControl &sc, CProgress &p ) +{ + int errCode = mHexBuffer->collectStatistic( sc, p ); + return( errCode ); +} + + +void CHexViewWidget::gotoOffset( uint offset, uint bit, bool fromCursor, + bool forward ) +{ + bool reverse = forward == true ? false : true; + mHexBuffer->cursorGoto( offset, bit, reverse, fromCursor ); + updateWindow( true, false ); +} + + +void CHexViewWidget::gotoOffset( uint offset ) +{ + gotoOffset( offset, 7, true, true ); +} + + +int CHexViewWidget::print( CHexPrinter &printer, CProgress &p ) +{ + return( mHexBuffer->print( printer, p ) ); +} + + +uint CHexViewWidget::numPage( CHexPrinter &printer ) +{ + return( mHexBuffer->numPage( printer ) ); +} + + +int CHexViewWidget::exportText( const SExportText &ex, CProgress &p ) +{ + return( mHexBuffer->exportText( ex, p ) ); +} + + +int CHexViewWidget::exportHtml( const SExportHtml &ex, CProgress &p ) +{ + return( mHexBuffer->exportHtml( ex, p ) ); +} + + +int CHexViewWidget::exportCArray( const SExportCArray &ex, CProgress &p ) +{ + return( mHexBuffer->exportCArray( ex, p ) ); +} + + +void CHexViewWidget::startDrag( bool asText ) +{ + QByteArray buf; + if( asText == true ) + { + if( mHexBuffer->copySelectedText( buf ) != Err_Success ) + { + return; + } + QDragObject *d = new QTextDrag( buf.data(), this ); + d->dragCopy(); + } + else + { + if( mHexBuffer->copySelectedData( buf ) != Err_Success ) + { + return; + } + QDragObject *d = new CHexDrag( buf, this ); + d->dragCopy(); + } +} + + + +void CHexViewWidget::copy( void ) +{ + QByteArray buf; + if( mHexBuffer->copySelectedData( buf ) != Err_Success ) + { + return; + } + disconnect(QApplication::clipboard(),SIGNAL(dataChanged()), + this,SLOT(clipboardChanged())); + // + // Note: Do no give the CHexDrag a parent != 0. The clipboard + // owns the current dragdata and will destroy it on exit or + // when it receives a new object. If the CHexDrag has a parent + // != 0, the CHexDrag object will be destroyed when the parent + // is destroyed. We will then have a double destroy situation + // when the app. is closed (=> segfault). + // + QApplication::clipboard()->setData(new CHexDrag( buf )); + connect(QApplication::clipboard(),SIGNAL(dataChanged()), + this,SLOT(clipboardChanged())); +} + + +void CHexViewWidget::copyText( int columnSegment ) +{ + QByteArray buf; + if( mHexBuffer->copySelectedText( buf, columnSegment ) != Err_Success ) + { + return; + } + + disconnect(QApplication::clipboard(),SIGNAL(dataChanged()), + this,SLOT(clipboardChanged())); + QApplication::clipboard()->setText( buf.data() ); + connect(QApplication::clipboard(),SIGNAL(dataChanged()), + this,SLOT(clipboardChanged())); +} + + + +void CHexViewWidget::paste( void ) +{ + QMimeSource *data = QApplication::clipboard()->data(); + if( data != 0 ) + { + QByteArray buf; + if( CHexDrag::decode( data, buf ) == true ) + { + insert( buf ); + return; + } + + QString text; + if( QTextDrag::decode( data, text ) == true ) + { + QByteArray buf; + if( mClipConvert.decode( buf, text ) == true ) + { + insert( buf ); + } + return; + } + } + +} + + +void CHexViewWidget::cut( void ) +{ + copy(); // Always make a copy to the clipboard of what we remove. + bool success = mHexBuffer->cutSelection(); + if( success == false ) + { + return; + } + + updateWindow( false, true ); + emit dataChanged(); +} + + +void CHexViewWidget::undo( void ) +{ + bool success = mHexBuffer->undo(); + if( success == false ) + { + return; + } + + updateWindow( true, true ); + emit dataChanged(); +} + + +void CHexViewWidget::redo( void ) +{ + bool success = mHexBuffer->redo(); + if( success == false ) + { + return; + } + + updateWindow( true, true ); + emit dataChanged(); +} + + +void CHexViewWidget::addBookmark( int position ) +{ + int errCode = mHexBuffer->addBookmark( position ); + if( errCode != Err_Success ) + { + if( errCode == Err_ListFull ) + { + replaceBookmark(); + } + return; + } + redrawFromOffset( mHexBuffer->cursorOffset(), false ); + + emit bookmarkChanged( mHexBuffer->bookmarkList() ); +} + + + +int CHexViewWidget::bookmarkMenu( const QString &title ) +{ + QPtrList<SCursorOffset> &list = mHexBuffer->bookmarkList(); + if( list.count() == 0 ) + { + return( -1 ); + } + + QString text; + KPopupMenu *popup = new KPopupMenu( 0 ); + popup->insertTitle( title ); + for( uint i=0; i < list.count(); i++ ) + { + const SCursorOffset *p = list.at( i ); + if( p == 0 ) { continue; } + + text.sprintf("%04X:%04X", p->offset>>16, p->offset&0x0000FFFF ); + text.prepend( QString("[%1] %2: ").arg(i+1).arg(i18n("Offset")) ); + popup->insertItem( text, i ); + } + + QSize s(popup->sizeHint()); + QPoint center( (width()-s.width())/2, (height()-s.height())/2 ); + int position = popup->exec( mapToGlobal(center) ); + delete popup; + + return( position ); +} + + +void CHexViewWidget::removeBookmark( bool all ) +{ + if( all == true ) + { + bool success = mHexBuffer->removeBookmark( -1 ); + if( success == false ) + { + return; + } + QWidget::update(); // Redraw visisble area. + } + else + { + int position = bookmarkMenu( i18n("Remove Bookmark") ); + if( position < 0 ) + { + return; + } + + const SCursorOffset *p = mHexBuffer->bookmarkList().at(position); + uint offset = p ? p->offset : 0; + + bool success = mHexBuffer->removeBookmark( position ); + if( success == false ) + { + return; + } + + redrawFromOffset( offset, false ); + } + + emit bookmarkChanged( mHexBuffer->bookmarkList() ); +} + + +void CHexViewWidget::replaceBookmark( void ) +{ + QPtrList<SCursorOffset> &list = mHexBuffer->bookmarkList(); + if( list.count() == 0 ) + { + return; + } + + int position = bookmarkMenu( i18n("Replace Bookmark") ); + if( position < 0 ) + { + return; + } + addBookmark( position ); +} + + +void CHexViewWidget::gotoBookmark( uint position ) +{ + QPtrList<SCursorOffset> &list = mHexBuffer->bookmarkList(); + if( position >= list.count() ) + { + return; + } + + SCursorOffset *p = list.at( position ); + if( p == 0 ) + { + return; + } + + mHexBuffer->cursorGoto( p->offset, p->bit ); + updateWindow(); +} + + + +void CHexViewWidget::gotoNextBookmark( bool next ) +{ + QPtrList<SCursorOffset> &list = mHexBuffer->bookmarkList(); + uint offset = mHexBuffer->cursorOffset(); + uint diff = ~0; + + SCursorOffset *match = 0; + + // + // Note: the list is unsorted. + // + if( next == true ) + { + for( SCursorOffset *co = list.first(); co != 0; co = list.next() ) + { + if( co->offset > offset ) + { + if( co->offset-offset < diff ) + { + diff = co->offset-offset; + match = co; + } + } + } + } + else + { + for( SCursorOffset *co = list.first(); co != 0; co = list.next() ) + { + if( co->offset < offset ) + { + if( offset-co->offset < diff ) + { + diff = offset-co->offset; + match = co; + } + } + } + } + + + if( match == 0 ) + { + if( next == true ) + { + // Wrap: Locate entry with smallest offset. + offset = ~0; + for( SCursorOffset *co = list.first(); co != 0; co = list.next() ) + { + if( co->offset < offset ) + { + offset = co->offset; + match = co; + } + } + } + else + { + // Wrap: Locate entry with largest offset. + offset=0; + for( SCursorOffset *co = list.first(); co != 0; co = list.next() ) + { + if( co->offset > offset ) + { + offset = co->offset; + match = co; + } + } + } + } + + if( match != 0 ) + { + mHexBuffer->cursorGoto( match->offset, match->bit ); + updateWindow(); + } +} + + + + + + +// +// Used to test the speed of drawing +// +#include <sys/time.h> +#include <unistd.h> +void CHexViewWidget::benchmark( void ) +{ + struct timeval t1, t2; + uint loop = 10; + + gettimeofday( &t1, 0 ); + for( uint i=0; i< loop; i++ ) + { + paintText( contentsRect(), false ); + } + gettimeofday( &t2, 0 ); + + + uint area = width() * height(); + uint last = (t2.tv_sec-t1.tv_sec) * 1000000 + (t2.tv_usec - t1.tv_usec); + + kdDebug(1501) << "Duration: " << (float)last/ 1000000.0 << endl; + kdDebug(1501) << "Duration/loop: " << (float)last/ (1000000.0*(float)loop) << endl; + kdDebug(1501) << "Area: " << area << endl; + kdDebug(1501) << "Loop: " << loop << endl; +} + + + + + +void CHexViewWidget::resizeEvent( QResizeEvent * ) +{ + setTextBufferSize(); + + if( mLayout.lockLine == true ) + { + updateView( false, false ); + #ifdef USE_NORTHWEST_GRAVITY + paintFrame(); + #endif + } + else + { + bool state = mVertScroll->isVisible(); + int size = (state == true ? mScrollBarSize : 0) + frameWidth()*2; + #ifdef USE_NORTHWEST_GRAVITY + int w = dataWidth(); + #endif + + bool bufferChanged = mHexBuffer->matchWidth( width() - size ); + updateView( false, bufferChanged ); + + if( mVertScroll->isVisible() != state ) + { + size = (mVertScroll->isVisible() ? mScrollBarSize : 0) + frameWidth()*2; + bufferChanged = mHexBuffer->matchWidth( width() - size ); + updateView( false, bufferChanged ); + } + + #ifdef USE_NORTHWEST_GRAVITY + if( w != dataWidth() ) + { + QWidget::update(); + } + else + { + paintFrame(); + } + #endif + } +} + + + +void CHexViewWidget::paintEvent( QPaintEvent *e ) +{ + paintText( e->rect(), true ); +} + + + +void CHexViewWidget::updateFrameSize( void ) +{ + int w = width() - (mVertScroll->isVisible() ? mScrollBarSize : 0); + if( w < 0 ) { w = 0; } + int h = height() - (mHorzScroll->isVisible() ? mScrollBarSize : 0); + if( h < 0 ) { h = 0; } + + setFrameRect( QRect(0,0,w,h) ); +} + + + +void CHexViewWidget::paintFrame( void ) +{ + QPainter paint; + paint.begin( this ); + drawFrame( &paint ); + paint.end(); +} + + + +void CHexViewWidget::drawFrame( QPainter *p ) +{ + // + // 2000-01-10 Espen Sand + // I want to display the frame with a custom color whenever the widget + // accepts a drop. The setPalette() function causes quite a bit of flicker + // in the scrollbars (even when PropagationMode is NoChildren), so I + // draw the frame manually when it can accept a drop. Note that the + // code below is for the frame shape "QFrame::WinPanel|QFrame::Plain" + // + if( mDropHighlight == true ) + { + qDrawPlainRect( p, frameRect(), QColor("SteelBlue2"), lineWidth() ); + } + else + { + QFrame::drawFrame(p); // Use standard drawFrame + } +} + + + +void CHexViewWidget::keyPressEvent( QKeyEvent *e ) +{ + SCursorConfig cc; + cc.state = e->state(); + + // + // Some special actions that we have to trap here + // + if( e->state() & ControlButton ) + { + switch( e->key() ) + { + case Key_Space: + e->accept(); + toggleEditor(); + return; + break; + + case Key_1: + e->accept(); + cursorStep( cc, 1 ); + return; + break; + + case Key_2: + e->accept(); + cursorStep( cc, 2 ); + return; + break; + + case Key_4: + e->accept(); + cursorStep( cc, 4 ); + return; + break; + + case Key_8: + e->accept(); + cursorStep( cc, 8 ); + return; + break; + } + } + + if( e->state() & AltButton ) + { + if( e->key() == Key_Left || e->key() == Key_Right ) + { + emit pleaseStepFile( e->key() == Key_Left ? true : false ); + e->accept(); + } + else if( e->key() == Key_Up || e->key() == Key_Down ) + { + gotoNextBookmark( e->key() == Key_Down ? true : false ); + e->accept(); + } + else + { + e->ignore(); + } + return; + } + + switch ( e->key() ) + { + case Key_Left: + cursorLeft( cc ); + break; + + case Key_Right: + cursorRight( cc ); + break; + + case Key_Up: + cursorUp( cc ); + break; + + case Key_Down: + cursorDown( cc ); + break; + + case Key_Home: + cursorHome( cc ); + break; + + case Key_End: + cursorEnd( cc ); + break; + + case Key_Next: + cursorPageDown( cc ); + break; + + case Key_Prior: + cursorPageUp( cc ); + break; + + case Key_Insert: + cursorInsert( cc ); + break; + + case Key_Delete: + cursorDelete( cc ); + break; + + case Key_Backspace: + cursorBackspace( cc ); + break; + + default: + if( (e->text()[0]).isPrint() == true ) + { + cursorInput( e->text()[0] ); + } + break; + } + + e->accept(); +} + + +void CHexViewWidget::keyReleaseEvent( QKeyEvent *e ) +{ + if( ( e->state() & ShiftButton ) && shiftButtonState() == false ) + { + // + // The shift button was pressed when event was triggered, but is + // now released. I use this as a sign to copy selected data to the + // clipboard. + // + autoCopy(); + } +} + + +void CHexViewWidget::mousePressEvent( QMouseEvent *e ) +{ + // + // The RMB popup menu is managed by the KContextMenuManager + // + + if( e->button() == LeftButton ) + { + if( e->state() & ControlButton ) + { + if( KContextMenuManager::showOnButtonPress() == true + && mDocumentMenu != 0 ) + { + mDocumentMenu->popup( e->globalPos() ); + } + } + else + { + bool cellLevel = mMisc.cursorJump == false; + setCursorPosition( e->x(), e->y(), true, cellLevel ); + } + } + else if( e->button() == MidButton ) + { + paste(); + } + +} + +void CHexViewWidget::mouseMoveEvent( QMouseEvent *e ) +{ + if( e->state() & LeftButton ) + { + if( mDragManager->start( e ) == false ) + { + bool cellLevel = mMisc.cursorJump == false||e->state() & ControlButton; + setCursorPosition( e->x(), e->y(), false, cellLevel ); + } + } +} + +void CHexViewWidget::mouseReleaseEvent( QMouseEvent *e ) +{ + // + // The RMB popup menu is managed by the KContextMenuManager + // + + if( e->button() == LeftButton ) + { + if( e->state() & ControlButton ) + { + if( KContextMenuManager::showOnButtonPress() == false + && mDocumentMenu != 0 ) + { + mDocumentMenu->popup( e->globalPos() ); + } + } + else + { + if( mDragManager->clear() == true ) + { + // Remove any selection + SCursorConfig cc; + cc.setKeepSelection( false ); + updateCursor( cc, true ); + } + else + { + mHexBuffer->cursorResetEditArea(); + autoCopy(); + } + } + } + +} + + + +void CHexViewWidget::wheelEvent( QWheelEvent *e ) +{ + if( mVertScroll->isVisible() == true ) + { + QApplication::sendEvent( mVertScroll, e ); + } +} + + +void CHexViewWidget::dragEnterEvent( QDragEnterEvent *e ) +{ + if( QTextDrag::canDecode(e) || CHexDrag::canDecode(e) || + KURLDrag::canDecode(e)) + { + e->accept(); + setDropHighlight( true ); + } +} + + +void CHexViewWidget::dragLeaveEvent( QDragLeaveEvent * ) +{ + setDropHighlight( false ); +} + + +void CHexViewWidget::dragMoveEvent( QDragMoveEvent *e ) +{ + // + // Move the cursor if we are dragging (readable) text or binary + // data. Note: the QTextDrag::canDecode() will return true if we + // are dragging a file so we have to test for KURLDrag::canDecode() + // first. + // + + if( KURLDrag::canDecode(e) == true ) + { + return; + } + + if( QTextDrag::canDecode(e) == true || CHexDrag::canDecode(e) == true ) + { + int x = startX() + e->pos().x(); + int y = startY() + e->pos().y(); + if( mHexBuffer->setCursorPosition( x, y, false, false ) == true ) + { + SCursorConfig cc; + cc.setKeepSelection( true ); + updateCursor( cc, false, false ); + } + } +} + + +void CHexViewWidget::dropEvent( QDropEvent *e ) +{ + QMimeSource &m = *(QDropEvent*)e; + setDropHighlight( false ); + + KURL::List list; + if( KURLDrag::decode( &m, list ) == true ) + { + // + // This widget can not itself open a file so it will simply pass + // the request to a parent that can (hopefully) do this + // + for( KURL::List::ConstIterator it = list.begin(); it != list.end(); it++ ) + { + emit pleaseOpenFile( (*it).url(), true, 0 ); + } + return; + } + + QByteArray buf; + if( CHexDrag::decode( &m, buf ) == true ) + { + insert( buf ); + return; + } + + QString text; + if( QTextDrag::decode( &m, text ) == true ) + { + bool success = mClipConvert.decode( buf, text ); + if( success == true ) + { + insert( buf ); + } + return; + } + +} + + +void CHexViewWidget::showEvent( QShowEvent * ) +{ + // Currently we do nothing here. +} + + + + +void CHexViewWidget::timerEvent( QTimerEvent *e ) +{ + if( e->timerId() == mCursorTimerId ) + { + if( hasFocus() == true ) + { + if( mCursor.alwaysVisible == true ) + { + mShowCursor = true; + } + else + { + mShowCursor = mShowCursor == true ? false : true; + } + } + else if( mCursor.focusMode == SDisplayCursor::hide ) + { + mShowCursor = false; + } + else if( mCursor.focusMode == SDisplayCursor::stopBlinking ) + { + mShowCursor = true; + } + else + { + mShowCursor = mShowCursor == true ? false : true; + } + mHexBuffer->setShowCursor( mShowCursor ); + paintCursor( CHexBuffer::cursor_curr ); + } +} + +void CHexViewWidget::focusInEvent( QFocusEvent * ) +{ + setupCursorTimer(); + paintCursor( CHexBuffer::cursor_curr ); +} + +void CHexViewWidget::focusOutEvent( QFocusEvent * ) +{ + if( mCursor.focusMode != SDisplayCursor::ignore ) + { + setupCursorTimer(); + paintCursor( CHexBuffer::cursor_curr ); + } +} + + +void CHexViewWidget::setSelection( uint offset, bool init ) +{ + bool selectionChanged = mHexBuffer->selectionSet( offset, init ); + if( selectionChanged == true ) + { + uint off1, off2; + mHexBuffer->selectionStartChange( off1, off2 ); + if( off1 != off2 ) + { + redrawInterval( off1, off2 ); + } + mHexBuffer->selectionStopChange( off1, off2 ); + if( off1 != off2 ) + { + redrawInterval( off1, off2 ); + } + } + mHexBuffer->selectionSyncronize(); +} + + + +void CHexViewWidget::setMark( uint offset, uint size, bool moveCursor ) +{ + bool changed; + if( size == 0 ) + { + changed = mHexBuffer->markRemove(); + } + else + { + mHexBuffer->markSet( offset, size ); + if( moveCursor == true ) + { + changed = false; + gotoOffset( offset, 7, false, true ); + } + else + { + changed = true; + } + } + + if( changed == true ) + { + uint off1, off2; + mHexBuffer->markStartChange( off1, off2 ); + if( off1 != off2 ) + { + redrawInterval( off1, off2 ); + } + + mHexBuffer->markStopChange( off1, off2 ); + if( off1 != off2 ) + { + redrawInterval( off1, off2 ); + } + } + mHexBuffer->markSyncronize(); +} + + + +void CHexViewWidget::setCursorPosition(int x, int y, bool init, bool cellLevel) +{ + x += startX(); + y += startY(); + + if( mHexBuffer->setCursorPosition( x, y, init, cellLevel ) == false ) + { + if( init == true ) + { + unselect(); + unmark(); + } + } + else if( init == false ) + { + SCursorConfig cc; + cc.setKeepSelection( true ); + updateCursor( cc, false ); + } + else + { + SCursorConfig cc; + if( mHexBuffer->cursorInsideSelection() == true ) + { + mDragManager->setup( x - startX(), y - startY() ); + cc.setKeepSelection( true ); + updateCursor( cc, true, false ); + } + else + { + cc.setKeepSelection( false ); + updateCursor( cc, true ); + } + } +} + + + +void CHexViewWidget::redrawInterval( uint startOffset, uint stopOffset ) +{ + // + // Can be improved, I repaint the entire line even if the offsets + // only specify one byte. + // + uint lineStart = mHexBuffer->calculateLine( startOffset ); + uint lineStop = mHexBuffer->calculateLine( stopOffset ); + if( lineStart <= lineStop ) + { + redrawLines( lineStart, lineStop - lineStart + 1 ); + } + else + { + redrawLines( lineStop, lineStart - lineStop + 1 ); + } +} + + + +void CHexViewWidget::redrawLines( uint docLine, int numLine ) +{ + int lineHeight = mHexBuffer->lineHeight(); + int lineOffset = startY() / lineHeight; + + // FIXME: startY() should return uint + if( (uint)lineOffset > docLine ) + { + numLine -= (lineOffset-docLine); + if( numLine <= 0 ) { return; } + docLine = lineOffset; + } + + int t = docLine * lineHeight - startY() + frameWidth(); + if( mEditMode == CHexBuffer::EditInsert ) + { + QRect r = contentsRect(); + r.setTop( t ); + paintText( contentsRect().intersect( r ), false ); + } + else + { + int h = (numLine + (startY() % lineHeight ? 1 : 0)) * lineHeight; + QRect r( contentsRect().left(), t, contentsRect().width(), h ); + paintText( contentsRect().intersect( r ), false ); + } +} + + + +void CHexViewWidget::redrawFromOffset( uint offset, bool finishWindow ) +{ + int lineHeight = mHexBuffer->lineHeight(); + uint docLine = mHexBuffer->calculateLine( offset ); + + int t = docLine * lineHeight - startY() + frameWidth(); + if( finishWindow == true ) + { + QRect r = contentsRect(); + r.setTop( t ); + paintText( contentsRect().intersect( r ), false ); + } + else + { + int h = t + lineHeight; + QRect r( contentsRect().left(), t, contentsRect().width(), h ); + paintText( contentsRect().intersect( r ), false ); + } +} + + + + +void CHexViewWidget::paintText( const QRect &rect, bool expand ) +{ + QRect r = rect; + + if( expand == true ) + { + #ifdef USE_NORTHWEST_GRAVITY + r.setLeft( r.left() - frameWidth() ); + r.setTop( r.top() - frameWidth() ); + #endif + } + + if( contentsRect().contains( r ) == false ) + { + paintFrame(); + if( r.left() < frameWidth() ) { r.setLeft( frameWidth() ); } + if( r.top() < frameWidth() ) { r.setTop( frameWidth() ); } + } + + int maxX = width() - frameWidth() - 1 - + (mVertScroll->isVisible() ? mScrollBarSize : 0); + int maxY = height() - frameWidth() - 1 - + (mHorzScroll->isVisible() ? mScrollBarSize : 0); + + if( r.right() > maxX ) { r.setRight( maxX ); } + if( r.bottom() > maxY ) { r.setBottom( maxY ); } + + QPainter paint( &mTextBuffer ); + paint.setFont( mHexBuffer->font() ); + + int lineHeight = mHexBuffer->lineHeight(); + int docLine = (startY() + r.y() - frameWidth()) / lineHeight; + if( docLine < 0 ) { docLine = 0; } + int y = docLine * lineHeight - startY(); + int yMax = r.height(); + int xMax = r.x() + r.width(); + + y += frameWidth(); + + int s = 0; + int d = r.y()-y; + int h; + while( yMax > 0 ) + { + mHexBuffer->drawText( paint, docLine, startX()-frameWidth(), r.x(), xMax ); + + if( d != 0 ) + { + h = lineHeight - d; + if( h > yMax ) { h = yMax; } + } + else + { + h = yMax > lineHeight ? lineHeight : yMax; + } + bitBlt( this, r.x(), r.y()+s, &mTextBuffer, r.x(), d, r.width(), h ); + + s += h; + yMax -= h; + docLine += 1; + d = 0; + } + paint.end(); +} + + + +void CHexViewWidget::paintCursor( int cursorMode ) +{ + QPainter paint; + paint.begin( &mTextBuffer ); + paint.setFont( mHexBuffer->font() ); + + int f = frameWidth(); + + if( cursorMode == CHexBuffer::cursor_prev ) + { + int line = mHexBuffer->prevCursorLine(); + SCursorPosition p; + + mHexBuffer->prevCursor( CHexBuffer::edit_primary, p ); + mHexBuffer->drawText( paint, line, startX(), p.x, p.x + p.w ); + if( p.y + p.h + f > contentsRect().bottom() ) + p.h = contentsRect().bottom() - p.y - f + 1; + bitBlt( this, p.x+f, p.y+f, &mTextBuffer, p.x, 0, p.w, p.h ); + + mHexBuffer->prevCursor( CHexBuffer::edit_secondary, p ); + mHexBuffer->drawText( paint, line, startX(), p.x, p.x + p.w ); + if( p.y + p.h + f > contentsRect().bottom() ) + p.h = contentsRect().bottom() - p.y - f + 1; + bitBlt( this, p.x+f, p.y+f, &mTextBuffer, p.x, 0, p.w, p.h ); + } + else + { + int line = mHexBuffer->cursorLine(); + SCursorPosition p; + + mHexBuffer->currCursor( CHexBuffer::edit_primary, p ); + mHexBuffer->drawText( paint, line, startX(), p.x, p.x + p.w ); + if( p.y + p.h + f > contentsRect().bottom() ) + p.h = contentsRect().bottom() - p.y - f + 1; + bitBlt( this, p.x+f, p.y+f, &mTextBuffer, p.x, 0, p.w, p.h ); + + mHexBuffer->currCursor( CHexBuffer::edit_secondary, p ); + mHexBuffer->drawText( paint, line, startX(), p.x, p.x + p.w ); + if( p.y + p.h + f > contentsRect().bottom() ) + p.h = contentsRect().bottom() - p.y - f + 1; + bitBlt( this, p.x+f, p.y+f, &mTextBuffer, p.x, 0, p.w, p.h ); + } + + paint.end(); +} + + + + + +void CHexViewWidget::updateCursor( SCursorConfig &cc, bool always, + bool touchSelection ) +{ + if( mHexBuffer->cursorChanged() == false && always == false ) + { + return; + } + + // + // Make blinking (and perhaps invisible) cursor visible + // + setupCursorTimer(); + + // + // Clear cursor at old location + // + paintCursor( CHexBuffer::cursor_prev ); + + // + // Compute the new position of the vertical scroll bar. + // + int position, h; + if( cc.controlButton() == true ) + { + // + // The cursor should stay fixed (if possible) in the window while + // the text is scrolled (e.g., PageUp/Down behavior). The position + // of the vertical scrollbar must change just as much as the cursor + // has changed in the vertical direction. + // + h = frameWidth()*2; + h += mHorzScroll->isVisible() == false ? 0 : mScrollBarSize; + position = mHexBuffer->cursorFixedPosition( startY(), height()-h ); + changeYPos( position ); + } + else + { + h = frameWidth()*2; + h += mHorzScroll->isVisible() == false ? 0 : mScrollBarSize; + position = mHexBuffer->cursorChangePosition( startY(), height()-h ); + changeYPos( position ); + } + + // + // Paint cursor at new location and update the vertical scroll bar. + // + paintCursor( CHexBuffer::cursor_curr ); + mVertScroll->blockSignals( true ); + mVertScroll->setValue( position ); + mVertScroll->blockSignals( false ); + + if( touchSelection == true ) + { + setSelection( mHexBuffer->cursorOffset(), cc.removeSelection() ); + unmark(); + } + emit cursorChanged( mHexBuffer->cursorState() ); +} + + + +void CHexViewWidget::toggleEditor( void ) +{ + bool success = mHexBuffer->toggleEditor(); + if( success == false ) + { + return; + } + + SCursorConfig cc; + updateCursor( cc, true ); + redrawFromOffset( mHexBuffer->cursorOffset(), false ); +} + + +void CHexViewWidget::cursorStep( SCursorConfig &cc, uint stepSize ) +{ + mHexBuffer->cursorStep( stepSize, cc.altButton() ? false : true, true ); + cc.emulateControlButton( false ); + updateCursor( cc ); +} + + + +void CHexViewWidget::cursorLeft( SCursorConfig &cc ) +{ + bool cellLevel = mMisc.cursorJump == false || cc.controlButton(); + cc.emulateControlButton( false ); + mHexBuffer->cursorLeft( cellLevel ); + updateCursor( cc, cellLevel ); +} + + +void CHexViewWidget::cursorRight( SCursorConfig &cc ) +{ + bool cellLevel = mMisc.cursorJump == false || cc.controlButton(); + cc.emulateControlButton( false ); + mHexBuffer->cursorRight( cellLevel ); + updateCursor( cc, cellLevel ); +} + + + +void CHexViewWidget::cursorUp( SCursorConfig &cc ) +{ + mHexBuffer->cursorUp( 1 ); + updateCursor( cc ); +} + + +void CHexViewWidget::cursorDown( SCursorConfig &cc ) +{ + mHexBuffer->cursorDown( 1 ); + updateCursor( cc ); +} + + +void CHexViewWidget::cursorHome( SCursorConfig &cc ) +{ + mHexBuffer->cursorHome( cc.controlButton() ); + updateCursor( cc ); +} + + +void CHexViewWidget::cursorEnd( SCursorConfig &cc ) +{ + mHexBuffer->cursorEnd( cc.controlButton() ); + updateCursor( cc ); +} + + +void CHexViewWidget::cursorPageDown( SCursorConfig &cc ) +{ + mHexBuffer->cursorDown( height() / mHexBuffer->lineHeight() ); + cc.emulateControlButton( true ); + updateCursor( cc ); +} + + +void CHexViewWidget::cursorPageUp( SCursorConfig &cc ) +{ + mHexBuffer->cursorUp( height() / mHexBuffer->lineHeight() ); + cc.emulateControlButton( true ); + updateCursor( cc ); +} + + +void CHexViewWidget::cursorInsert( SCursorConfig &/*cc*/ ) +{ + // Toggle mode + setEditMode( mEditMode == CHexBuffer::EditInsert ? + CHexBuffer::EditReplace : CHexBuffer::EditInsert ); +} + + + +void CHexViewWidget::cursorDelete( SCursorConfig &/*cc*/ ) +{ + int numLine = mHexBuffer->numLines(); + + bool success = mHexBuffer->removeAtCursor( false ); + if( success == false ) + { + return; + } + + updateWindow( numLine == mHexBuffer->numLines() ? false : true, true ); + emit dataChanged(); +} + + +void CHexViewWidget::cursorBackspace( SCursorConfig &/*cc*/ ) +{ + int numLine = mHexBuffer->numLines(); + + bool success = mHexBuffer->removeAtCursor( true ); + if( success == false ) + { + return; + } + + updateWindow( numLine == mHexBuffer->numLines() ? false : true, true ); + emit dataChanged(); +} + + +void CHexViewWidget::cursorInput( QChar c ) +{ + uint cursorLine = mHexBuffer->cursorLine(); + bool success = mHexBuffer->inputAtCursor( c ); + if( success == false ) + { + return; + } + + updateWindow( cursorLine ); + emit dataChanged(); +} + + +void CHexViewWidget::setEditMode( CHexBuffer::EEditMode mode ) +{ + mEditMode = mode; + mHexBuffer->setEditMode( mEditMode, mCursor.alwaysBlockShape, + mCursor.thickInsertShape ); + setupCursorTimer(); + + // + // This will redraw the current line (which contains the cursor) + // + redrawFromOffset( mHexBuffer->cursorOffset(), false ); + emit editMode( mEditMode ); +} + + +void CHexViewWidget::setDropHighlight( bool dropHighlight ) +{ + mDropHighlight = dropHighlight; + if( mDropHighlight == true ) + { + // + // 2000-01-10 Espen Sand + // Highlight. I have reimplemented QFrame::drawFrame(QPainter *) + // to support a custom frame color. I assume the frame shape is + // "QFrame::WinPanel|QFrame::Plain" in that function. + // + setFrameStyle( QFrame::WinPanel|QFrame::Plain ); + } + else + { + setFrameStyle( QFrame::WinPanel|QFrame::Sunken ); + } +} + + + +#include "hexviewwidget.moc" diff --git a/khexedit/hexviewwidget.h b/khexedit/hexviewwidget.h new file mode 100644 index 0000000..9dc55e4 --- /dev/null +++ b/khexedit/hexviewwidget.h @@ -0,0 +1,584 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _HEX_VIEW_WIDGET_H_ +#define _HEX_VIEW_WIDGET_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <qframe.h> +#include <qpixmap.h> +#include <qpopupmenu.h> +#include <qscrollbar.h> + +#include <kapplication.h> +#include <kcmenumngr.h> + +#include "hexclipboard.h" +#include "hexbuffer.h" + +class CScrollBar : public QScrollBar +{ + Q_OBJECT + + public: + CScrollBar( Orientation o, QWidget *parent, const char *name = 0 ) + : QScrollBar( o, parent, name ) + { + } + + signals: + void hidden( void ); + + protected: + virtual void hideEvent( QHideEvent * ) + { + emit hidden(); + } +}; + + +class CDragManager : public QWidget +{ + Q_OBJECT + + public: + enum EDragActivateMode + { + Movement = 0, + Timer = 1 + }; + + public: + CDragManager( void ); + void setActivateMode( EDragActivateMode mode ); + void setup( int x, int y ); + bool start( QMouseEvent *e ); + bool clear( void ); + + protected: + virtual void timerEvent( QTimerEvent *e ); + + private: + void removeTimer( void ); + void setupTimer( void ); + + signals: + void startDrag( bool asText ); + + private: + EDragActivateMode mActivateMode; + bool mPending; + int mTimerId; + QPoint mOrigin; +}; + + + +class CHexViewWidget : public QFrame +{ + Q_OBJECT + + public: + CHexViewWidget( QWidget *parent, const char *name, CHexBuffer *hexBuffer ); + ~CHexViewWidget( void ); + inline bool widgetValid( void ); + + int readFile( QFile &file, const QString &url, CProgress &p ); + int insertFile( QFile &file, CProgress &p ); + int writeFile( QFile &file, CProgress &p ); + int newFile( const QString &url ); + void closeFile( void ); + void initFile( void ); + void setBuffer( CHexBuffer *hexBuffer ); + void updateView( bool redraw, bool fixCursor ); + + void selectAll( void ); + void unselect( void ); + void unmark( void ); + uint numPage( CHexPrinter &printer ); + int print( CHexPrinter &printer, CProgress &p ); + int exportText( const SExportText &ex, CProgress &p ); + int exportHtml( const SExportHtml &ex, CProgress &p ); + int exportCArray( const SExportCArray &ex, CProgress &p ); + + void copy( void ); + void copyText( int columnSegment=CHexBuffer::VisibleColumn ); + void paste( void ); + void cut( void ); + void undo( void ); + void redo( void ); + void addBookmark( int position ); + void removeBookmark( bool all ); + void replaceBookmark( void ); + void gotoBookmark( uint position ); + void gotoNextBookmark( bool next ); + void benchmark( void ); + + virtual void setPalette( const QPalette & ); + void setInputMode( SDisplayInputMode &mode ); + void setLayout( SDisplayLayout &layout ); + void setCursor( const SDisplayCursor &cursor, bool updateDisplay ); + void setColor( const SDisplayColor &color, bool updateDisplay ); + void setFont( const SDisplayFontInfo &fontInfo, bool updateDisplay ); + void setMisc( SDisplayMisc &misc ); + void setInsertMode( bool insertMode ); + int setEncoding( CConversion::EMode mode, CProgress &p ); + void reportEncoding( void ); + + int findFirst( SSearchControl &sc ); + int findNext( SSearchControl &sc ); + int findWrap( SSearchControl &sc ); + int replaceAll( SSearchControl &sc, bool init ); + int replaceMarked( SSearchControl &sc ); + int collectStrings( CStringCollectControl &sc ); + int collectStatistic( SStatisticControl &sc, CProgress &p ); + + + inline void setPopupMenu( QPopupMenu *popupMenu ); + inline void setDocumentMenu( QPopupMenu *popupMenu ); + inline bool insertMode( void ); + inline int scrollBarWidth( void ); + inline int dataWidth( void ); + inline int defaultWidth( void ); + inline uint offset( void ); + inline uint bookmarkCount( void ); + inline bool modified( void ); + inline void setModified( bool modified ); + inline const QDateTime &diskModifyTime( void ); + inline bool losslessEncoding( CConversion::EMode mode ); + inline const SEncodeState &encoding( void ); + inline bool documentPresent( void ); + inline bool urlValid( void ); + inline QString &url( void ); + inline void setUrl( QString &url ); + inline const CHexBuffer *hexBuffer( void ); + + public slots: + void filter( SFilterControl &fc ); + void insert( SInsertData &id ); + void insert( const QByteArray &buf ); + void append( const QByteArray &buf ); + void valueOnCursor( QByteArray &buf, uint size ); + void paletteChanged( void ); + void fontChanged( void ); + void gotoOffset( uint offset, uint bit, bool fromCursor, bool forward ); + void gotoOffset( uint offset ); + void setMark( uint offset, uint size, bool moveCursor ); + void setDropHighlight( bool mode ); + + protected: + virtual void drawFrame( QPainter *p ); + virtual void paintEvent( QPaintEvent *e ); + virtual void resizeEvent( QResizeEvent *e ); + virtual void keyPressEvent( QKeyEvent *e ); + virtual void keyReleaseEvent( QKeyEvent *e ); + virtual void mousePressEvent( QMouseEvent *e ); + virtual void mouseMoveEvent( QMouseEvent *e ); + virtual void wheelEvent( QWheelEvent * ); + virtual void mouseReleaseEvent( QMouseEvent *e ); + virtual void dragEnterEvent( QDragEnterEvent *e ); + virtual void dragLeaveEvent( QDragLeaveEvent *e ); + virtual void dragMoveEvent( QDragMoveEvent *e ); + virtual void dropEvent( QDropEvent *e ); + virtual void showEvent( QShowEvent * ); + virtual void timerEvent( QTimerEvent *e ); + virtual void focusInEvent( QFocusEvent *e ); + virtual void focusOutEvent( QFocusEvent *e ); + + protected slots: + void changeXPos( int pos ); + void changeYPos( int pos ); + void clipboardChanged( void ); + + signals: + void cursorChanged( SCursorState &state ); + void fileState( SFileState &state ); + void dataChanged( void ); + void layoutChanged( const SDisplayLayout &layout ); + void inputModeChanged( const SDisplayInputMode &mode ); + void bookmarkChanged( QPtrList<SCursorOffset> &list ); + void editMode( CHexBuffer::EEditMode editMode ); + void encodingChanged( const SEncodeState &state ); + void textWidth( uint width ); + void fileName( const QString &url, bool onDisk ); + void fileRename( const QString &curName, const QString &newName ); + void fileClosed( const QString &url ); + + void pleaseOpenNewFile( void ); + void pleaseStepFile( bool next ); + void pleaseOpenFile(const QString &url,bool reloadWhenChanged,uint offset); + + private: + void setSelection( uint offset, bool init ); + void setCursorPosition( int x, int y, bool init, bool cellLevel ); + void updateCursor( SCursorConfig &cc, bool always = false, + bool touchSelection = true ); + void setEditMode( CHexBuffer::EEditMode mode ); + + void paintFrame( void ); + void updateFrameSize( void ); + + void redrawInterval( uint start, uint stop ); + void redrawLines( uint docLine, int numLine ); + void redrawFromOffset( uint offset, bool finishWindow ); + void paintText( const QRect &r, bool expand ); + void paintCursor( int cursorMode ); + + + void toggleEditor( void ); + void cursorStep( SCursorConfig &cc, uint stepSize ); + void cursorLeft( SCursorConfig &cc ); + void cursorRight( SCursorConfig &cc ); + void cursorHome( SCursorConfig &cc ); + void cursorEnd( SCursorConfig &cc ); + void cursorUp( SCursorConfig &cc ); + void cursorDown( SCursorConfig &cc ); + void cursorPageUp( SCursorConfig &cc ); + void cursorPageDown( SCursorConfig &cc ); + void cursorInsert( SCursorConfig &cc ); + void cursorDelete( SCursorConfig &cc ); + void cursorBackspace( SCursorConfig &cc ); + void cursorInput( QChar c ); + + int bookmarkMenu( const QString &title ); + + static inline bool shiftButtonState( void ); + + inline void setupCursorTimer( void ); + inline int startX( void ); + inline int startY( void ); + inline void setStartX( int val ); + inline void setStartY( int val ); + inline void updateWindow( bool completeRedraw, bool touchSelection ); + inline void updateWindow( uint line ); + inline void updateWindow( uint fromOffset, bool finishWindow ); + inline void updateWindow( void ); + inline void setTextBufferSize( void ); + inline void autoCopy( void ); + + private slots: + void startDrag( bool asText ); + + private: + CScrollBar *mVertScroll; + CScrollBar *mHorzScroll; + QWidget *mCorner; + + CHexBuffer *mHexBuffer; + QPixmap mTextBuffer; + SDisplayLayout mLayout; + SDisplayCursor mCursor; + SDisplayColor mColor; + SDisplayFontInfo mFontInfo; + SDisplayMisc mMisc; + + QPopupMenu *mDocumentMenu; + + int mScrollBarSize; + CHexBuffer::EEditMode mEditMode; + bool mShowCursor; + bool mDropHighlight; + + int mCursorTimerId; + + CDragManager *mDragManager; + CHexClipboard mClipConvert; +}; + + +inline bool CHexViewWidget::shiftButtonState( void ) +{ + return kapp->keyboardModifiers() & KApplication::ShiftModifier; +} + + + +inline bool CHexViewWidget::widgetValid( void ) +{ + if( mVertScroll == 0 || mHorzScroll == 0 || mHexBuffer == 0 ) + { + return( false ); + } + else + { + return( true ); + + } +} + +inline void CHexViewWidget::setupCursorTimer( void ) +{ + if( mCursorTimerId != 0 ) + { + killTimer( mCursorTimerId ); + mCursorTimerId = 0; + } + + if( hasFocus() == true ) + { + if( mCursor.alwaysVisible == false ) + { + mCursorTimerId = startTimer( mCursor.interval ); + } + mShowCursor = true; + mHexBuffer->setDisableCursor( false ); + } + else + { + if( mCursor.alwaysVisible == false ) + { + if( mCursor.focusMode == SDisplayCursor::ignore ) + { + mCursorTimerId = startTimer( mCursor.interval ); + } + } + if( mCursor.focusMode != SDisplayCursor::hide ) + { + mShowCursor = true; + } + else + { + mShowCursor = false; + mHexBuffer->setDisableCursor( true ); + } + } + + mHexBuffer->setShowCursor( mShowCursor ); +} + +inline void CHexViewWidget::setPopupMenu( QPopupMenu *popupMenu ) +{ + KContextMenuManager::insert( this, popupMenu ); +} + + +inline void CHexViewWidget::setDocumentMenu( QPopupMenu *popupMenu ) +{ + mDocumentMenu = popupMenu; +} + + +inline int CHexViewWidget::startX( void ) +{ + return( mHexBuffer->startX() ); +} + +inline int CHexViewWidget::startY( void ) +{ + return( mHexBuffer->startY() ); +} + +inline void CHexViewWidget::setStartX( int val ) +{ + mHexBuffer->setStartX( val ); +} + +inline void CHexViewWidget::setStartY( int val ) +{ + mHexBuffer->setStartY( val ); +} + + +inline void CHexViewWidget::updateWindow( bool completeRedraw, + bool touchSelection ) +{ + if( completeRedraw == true ) + { + SCursorConfig cc; + updateCursor( cc, true, touchSelection ); + updateView( true, false ); + } + else + { + SCursorConfig cc; + updateCursor( cc, false, touchSelection ); + redrawFromOffset( mHexBuffer->cursorOffset(), true ); + updateView( false, false ); + } + + emit fileState( mHexBuffer->fileState() ); +} + + + +inline void CHexViewWidget::updateWindow( uint line ) +{ + SCursorConfig cc; + updateCursor( cc, false, true ); + if( line == mHexBuffer->cursorLine() ) + { + redrawLines( line, 1 ); + } + else if( line < mHexBuffer->cursorLine() ) + { + redrawLines( line, mHexBuffer->cursorLine() - line ); + } + else + { + redrawLines( line, line - mHexBuffer->cursorLine() ); + } + emit fileState( mHexBuffer->fileState() ); +} + + +inline void CHexViewWidget::updateWindow( uint fromOffset, bool finishWindow ) +{ + SCursorConfig cc; + updateCursor( cc, true, true ); + updateView( false, false ); + redrawFromOffset( fromOffset, finishWindow ); + + emit fileState( mHexBuffer->fileState() ); +} + + +inline void CHexViewWidget::updateWindow( void ) +{ + setTextBufferSize(); + mHexBuffer->cursorUp(0); // Makes sure cursor is visible + + SCursorConfig cc; + cc.emulateControlButton( true ); + updateCursor( cc, true, false ); + updateView( true, false ); + + emit fileState( mHexBuffer->fileState() ); +} + + +inline void CHexViewWidget::setTextBufferSize( void ) +{ + int w = width(); + int h = mHexBuffer->lineHeight(); + + if( w != mTextBuffer.width() || h != mTextBuffer.height() ) + { + mTextBuffer.resize( w, h ); + } +} + + +inline void CHexViewWidget::autoCopy( void ) +{ + if( mMisc.autoCopyToClipboard == true ) + { + copy(); + } +} + + +inline bool CHexViewWidget::insertMode( void ) +{ + return mEditMode == CHexBuffer::EditInsert; +} + + +inline int CHexViewWidget::scrollBarWidth( void ) +{ + return( mScrollBarSize ); +} + +inline int CHexViewWidget::dataWidth( void ) +{ + return( mHexBuffer->lineWidth() ); +} + +inline int CHexViewWidget::defaultWidth( void ) +{ + return( dataWidth() + scrollBarWidth() + frameWidth()*2 ); +} + + +inline uint CHexViewWidget::offset( void ) +{ + return( mHexBuffer->cursorOffset() ); +} + +inline uint CHexViewWidget::bookmarkCount( void ) +{ + const QPtrList<SCursorOffset> &list = mHexBuffer->bookmarkList(); + return( list.count() ); +} + +inline bool CHexViewWidget::modified( void ) +{ + return( mHexBuffer->modified() ); +} + +inline void CHexViewWidget::setModified( bool modified ) +{ + mHexBuffer->setModified( modified ); + emit fileState( mHexBuffer->fileState() ); +} + +inline const QDateTime &CHexViewWidget::diskModifyTime( void ) +{ + return( mHexBuffer->diskModifyTime() ); +} + +inline bool CHexViewWidget::losslessEncoding( CConversion::EMode mode ) +{ + return( mHexBuffer->losslessEncoding(mode) ); +} + +inline const SEncodeState &CHexViewWidget::encoding( void ) +{ + return( mHexBuffer->encoding() ); +} + +inline bool CHexViewWidget::documentPresent( void ) +{ + return( mHexBuffer->documentPresent() ); +} + +inline bool CHexViewWidget::urlValid( void ) +{ + return( mHexBuffer->hasFileName() ); +} + +inline QString &CHexViewWidget::url( void ) +{ + return( mHexBuffer->url() ); +} + +inline void CHexViewWidget::setUrl( QString &url ) +{ + if( mHexBuffer->url() != url ) + { + emit fileRename( mHexBuffer->url(), url ); + mHexBuffer->setUrl( url ); + } +} + +inline const CHexBuffer *CHexViewWidget::hexBuffer( void ) +{ + return( mHexBuffer ); +} + + +#endif + + + + diff --git a/khexedit/hi16-app-khexedit.png b/khexedit/hi16-app-khexedit.png Binary files differnew file mode 100644 index 0000000..9b23931 --- /dev/null +++ b/khexedit/hi16-app-khexedit.png diff --git a/khexedit/hi32-app-khexedit.png b/khexedit/hi32-app-khexedit.png Binary files differnew file mode 100644 index 0000000..cc64da0 --- /dev/null +++ b/khexedit/hi32-app-khexedit.png diff --git a/khexedit/hi48-app-khexedit.png b/khexedit/hi48-app-khexedit.png Binary files differnew file mode 100644 index 0000000..429c424 --- /dev/null +++ b/khexedit/hi48-app-khexedit.png diff --git a/khexedit/khexedit.desktop b/khexedit/khexedit.desktop new file mode 100644 index 0000000..befa3d7 --- /dev/null +++ b/khexedit/khexedit.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +GenericName=Binary Editor +GenericName[af]=Binêre Redigeerder +GenericName[ar]=Ù…Øرر ثنائى +GenericName[bg]=Двоичен редактор +GenericName[br]=Aozer binarel +GenericName[bs]=Binarni editor +GenericName[ca]=Editor binari +GenericName[cs]=Binárnà editor +GenericName[cy]=Golygydd Deuaidd +GenericName[da]=Binær editor +GenericName[de]=Binäreditor +GenericName[el]=ΕπεξεÏγαστής δυαδικών αÏχείων +GenericName[eo]=Deksesuma redaktilo +GenericName[es]=Editor binario +GenericName[et]=Binaarfailide redaktor +GenericName[eu]=Editore Binarioa +GenericName[fa]=ویرایشگر دوگانی +GenericName[fi]=Binäärieditori +GenericName[fr]=Éditeur hexadécimal +GenericName[ga]=Eagarthóir Dénártha +GenericName[he]=עורך ×‘×™× ×¨×™ +GenericName[hi]=दà¥à¤µà¤¿à¤šà¤° संपादक +GenericName[hr]=Binarni ureÄ‘ivaÄ +GenericName[hu]=HexaszerkesztÅ‘ +GenericName[is]=TvÃunda-ritill +GenericName[it]=Editor binario +GenericName[ja]=ãƒã‚¤ãƒŠãƒªã‚¨ãƒ‡ã‚£ã‚¿ +GenericName[ka]=ბინáƒáƒ ული რედáƒáƒ¥áƒ¢áƒáƒ ი +GenericName[kk]=Бинарлық редактор +GenericName[km]=កម្មវិធី​និពន្ធ​គោលពីរ +GenericName[lt]=Dvejetainio kodo redaktorius +GenericName[lv]=BinÄrais Redaktors +GenericName[mk]=Бинарен уредувач +GenericName[ms]=Penyunting Binari +GenericName[mt]=Editur binarju +GenericName[nb]=Binærredigerer +GenericName[nds]=Hexeditor +GenericName[ne]=बाइनरी समà¥à¤ªà¤¾à¤¦à¤• +GenericName[nl]=Binaire bestanden bewerken +GenericName[nn]=Program for binærredingerig +GenericName[pa]=ਬਾਈਨਰੀ ਸੰਪਾਦਕ +GenericName[pl]=Editor Binarny +GenericName[pt]=Editor Binário +GenericName[pt_BR]=Editor de Binários +GenericName[ro]=Editor date binare +GenericName[ru]=Двоичный редактор +GenericName[sk]=Binárny editor +GenericName[sl]=Binarni urejevalnik +GenericName[sr]=Уређивач бинарних фајлова +GenericName[sr@Latn]=UreÄ‘ivaÄ binarnih fajlova +GenericName[sv]=Binäreditor +GenericName[ta]=இரà¯à®¨à®¿à®²à¯ˆ தொகà¯à®ªà¯à®ªà®¾à®©à¯ +GenericName[tg]=Муҳаррири Дуӣ +GenericName[th]=เครื่à¸à¸‡à¸¡à¸·à¸à¹à¸à¹‰à¹„ขเลขà¸à¸²à¸™ +GenericName[tr]=Ä°kili dosya düzenleyici +GenericName[uk]=Двійковий редактор +GenericName[ven]=Musengulusi kavhili +GenericName[vi]=Trình biên táºp nhị phân +GenericName[wa]=Aspougneu binaire +GenericName[xh]=Umphathi Webhetri +GenericName[zh_CN]=二进制编辑器 +GenericName[zh_TW]=二進ä½ç·¨è¼¯å™¨ +GenericName[zu]=Umhleli Ohambisana ngambili +Name=KHexEdit +Name[af]=Khex-redigeerder +Name[eo]=Deksesuma redaktilo +Name[hi]=के-हेकà¥à¤¸-à¤à¤¡à¤¿à¤Ÿ +Name[pl]=Edytor binarny +Name[pt_BR]=Editor Hexadecimal +Name[sv]=Khexedit +Name[ta]=KHexதொகà¯à®ªà¯à®ªà¯ +Name[th]=à¹à¸à¹‰à¹„ขเลขà¸à¸²à¸™ +Name[tr]=Onaltılı Düzenleyici +Name[ven]=U sengulusa ha KHex +Name[zh_TW]=KHex 編輯器 +Exec=khexedit -caption "%c" %i %m %U +Icon=khexedit +Path= +Type=Application +DocPath=khexedit/index.html +Terminal=false +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Utility;X-KDE-Utilities-File; + diff --git a/khexedit/khexeditui.rc b/khexedit/khexeditui.rc new file mode 100644 index 0000000..5be593a --- /dev/null +++ b/khexedit/khexeditui.rc @@ -0,0 +1,137 @@ +<!DOCTYPE kpartgui> +<kpartgui name="khexedit" version="1"> +<MenuBar> + <Menu name="file"> + <Action name="insert_file" append="open_merge"/> + <Action name="export" append="print_merge"/> + <Separator/> + <Action name="cancel"/> + <Menu name="permission"> + <text>Permissions</text> + <Action name="read_only"/> + <Action name="resize_lock"/> + </Menu> + <Separator/> + <Action name="new_window"/> + <Action name="close_window"/> + </Menu> + <Menu name="edit"> + <Menu name="special" append="edit_paste_merge"><text>Spec&ial</text> + <Action name="copy_as_text"/> + <Action name="paste_into_new_file"/> + <Action name="paste_into_new_window"/> + </Menu> + <Action name="goto_offset"/> + <Action name="insert_pattern"/> + </Menu> + <Menu name="view"> + <Action name="mode_hex"/> + <Action name="mode_dec"/> + <Action name="mode_oct"/> + <Action name="mode_bin"/> + <Action name="mode_text"/> + <Separator/> + <Action name="show_offset_column"/> + <Action name="show_text_field"/> + <Separator/> + <Action name="offset_as_decimal"/> + <Separator/> + <Action name="upper_case_data"/> + <Action name="upper_case_offset"/> + <Separator/> + <Menu name="encoding"><text>Document &Encoding</text> + <Action name="enc_default"/> + <Action name="enc_ascii"/> + <Action name="enc_ebcdic"/> +<!-- <Action name="enc_custom"/> //--> + </Menu> + </Menu> + <Menu name="bookmarks"> + <Action name="replace_bookmark"/> + <Action name="remove_bookmark"/> + <Action name="remove_all_bookmarks"/> + <Separator/> + <Action name="next_bookmark"/> + <Action name="prev_bookmark"/> + <ActionList name="bookmark_list"/> + </Menu> + <Menu name="tools"> + <Action name="extract_strings"/> +<!-- <Action name="record_viewer"/> //--> + <Action name="binary_filter"/> + <Action name="char_table"/> + <Action name="converter"/> + <Separator/> + <Action name="statistics"/> + </Menu> + <Menu name="documents"><text>&Documents</text> + </Menu> + <Menu name="settings"> + <Separator append="show_merge"/> + <Action name="show_full_path" append="show_merge"/> + <Separator append="show_merge"/> + <Menu name="doctab" append="show_merge"><text>&Document Tabs</text> + <Action name="doctab_hide"/> + <Action name="doctab_above"/> + <Action name="doctab_below"/> + </Menu> + <Menu name="conversion_field" append="show_merge"><text>Conversion &Field</text> + <Action name="conversion_field_hide"/> + <Action name="conversion_field_float"/> + <Action name="conversion_field_embed"/> + </Menu> + <Menu name="searchbar" append="show_merge"><text>Searc&hbar</text> + <Action name="searchbar_hide"/> + <Action name="searchbar_above"/> + <Action name="searchbar_below"/> + </Menu> +<!-- <Action name="favorites"/> //--> + </Menu> +</MenuBar> + +<!-- main toolbar //--> +<ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text> + <Action name="drag_document"/> + <Separator lineSeparator="true"/> + <Action name="file_new"/> + <Action name="file_open"/> + <Action name="file_save"/> + <Action name="file_revert"/> + <Action name="file_print"/> + <Separator/> + <Action name="edit_undo"/> + <Action name="edit_redo"/> + <Action name="edit_cut"/> + <Action name="edit_copy"/> + <Action name="edit_paste"/> + <Separator/> + <Action name="edit_find"/> + <Action name="edit_find_last"/> + <Action name="edit_find_next"/> + <Separator/> + <Action name="cancel"/> + <Action name="help"/> +</ToolBar> + +<!-- Editor popup menu //--> +<Menu name="editor_popup"> + <Action name="file_open"/> + <Action name="file_save"/> + <Action name="file_save_as"/> + <Separator/> + <Menu name="editor_bookmark_popup"> + <text>&Bookmarks</text> + <Action name="bookmark_add"/> + <ActionList name="bookmark_list"/> + </Menu> + <Separator/> + <Action name="mode_hex"/> + <Action name="mode_dec"/> + <Action name="mode_oct"/> + <Action name="mode_bin"/> + <Action name="mode_text"/> + <Separator/> + <Action name="read_only"/> + <Action name="resize_lock"/> +</Menu> +</kpartgui> diff --git a/khexedit/lib/Makefile.am b/khexedit/lib/Makefile.am new file mode 100644 index 0000000..c0c92cc --- /dev/null +++ b/khexedit/lib/Makefile.am @@ -0,0 +1,39 @@ +SUBDIRS = controller codecs + +INCLUDES = $(all_includes) + +METASOURCES = AUTO + +# this library is used by the kbytesedit part and the khepart part +lib_LTLIBRARIES = libkhexeditcommon.la +libkhexeditcommon_la_LDFLAGS = $(all_libraries) -no-undefined +libkhexeditcommon_la_LIBADD = controller/libkcontroller.la codecs/libkhecodecs.la $(LIB_KDECORE) +libkhexeditcommon_la_SOURCES = kcolumn.cpp kbordercolumn.cpp koffsetcolumn.cpp \ + kbuffercolumn.cpp kvaluecolumn.cpp kcharcolumn.cpp \ + kcolumnsview.cpp khexedit.cpp kbytesedit.cpp \ + koffsetformat.cpp \ + kdatabuffer.cpp kwrappingrobuffer.cpp \ + kplainbuffer.cpp kfixedsizebuffer.cpp kbigbuffer.cpp \ + kbuffercursor.cpp kbufferlayout.cpp kbufferranges.cpp \ + kcursor.cpp kbufferdrag.cpp \ + kwordbufferservice.cpp \ + ksectionlist.cpp kcoordrangelist.cpp \ + kbordercoltextexport.cpp koffsetcoltextexport.cpp \ + kbuffercoltextexport.cpp kvaluecoltextexport.cpp kcharcoltextexport.cpp + +# no public API for a direct use by now +noinst_HEADERS = kcolumn.h kbordercolumn.h koffsetcolumn.h \ + kbuffercolumn.h kvaluecolumn.h kcharcolumn.h \ + kbytecodec.h koffsetformat.h khexedit_export.h \ + kbuffercursor.h kbufferlayout.h kbufferranges.h \ + kbuffercoord.h kselection.h \ + kcursor.h kbufferdrag.h \ + kcoordrange.h ksectionlist.h kcoordrangelist.h \ + khechar.h kcharcodec.h \ + kcoltextexport.h kbordercoltextexport.h koffsetcoltextexport.h \ + kbuffercoltextexport.h kvaluecoltextexport.h kcharcoltextexport.h \ + kadds.h khe.h krange.h ksection.h \ + kwordbufferservice.h \ + kcolumnsview.h khexedit.h kbytesedit.h \ + kplainbuffer.h kfixedsizebuffer.h kbigbuffer.h \ + kdatabuffer.h kreadonlybuffer.h kwrappingrobuffer.h diff --git a/khexedit/lib/README b/khexedit/lib/README new file mode 100644 index 0000000..ad5f346 --- /dev/null +++ b/khexedit/lib/README @@ -0,0 +1,36 @@ +hex editor library +================== +part of the KHexEdit 2 project (kdenonbeta/khexedit2) +Author/Maintainer: Friedrich W. H. Kossebau <Friedrich.W.H@Kossebau.de> + + +description: +----------- +The lib is the main work of KHexEdit2. It offers +a general usable hex edit widget "KHexEdit" +that interacts with an abstract data buffer +interface called "KDataBuffer". This interface can +be subclassed to offer access to different data buffers +like paged gigabyte big files, video memory or whatever +you can imagine (hopefully). + +For those simply needing a widget for a plain array of bytes +there is the widget subclass "KBytesEdit", which hides the +databuffer interface and publically simply interacts with +arrays (like "char Array[25];"). + + +installing: +----------- +As these widgets and the databuffer interface have not got +much testing the API might not be finished. Because of that +it won't be made public available, i.e. there will be no headers +installed. + + +usage: +------ +This lib is by now only used by the KBytesEdit part, to be found +in "../parts/kbytesedit". +It is _not_ used by the current KHexEdit 1 app. This will change once +the successor app from KHexEdit2 is done.
\ No newline at end of file diff --git a/khexedit/lib/codecs/Makefile.am b/khexedit/lib/codecs/Makefile.am new file mode 100644 index 0000000..0c208b7 --- /dev/null +++ b/khexedit/lib/codecs/Makefile.am @@ -0,0 +1,15 @@ +INCLUDES = -I$(srcdir)/.. $(all_includes) + +METASOURCES = AUTO + +# +noinst_LTLIBRARIES = libkhecodecs.la +libkhecodecs_la_SOURCES = kcharcodec.cpp kbytecodec.cpp \ + ktextcharcodec.cpp kebcdic1047charcodec.cpp \ + kbinarybytecodec.cpp koctalbytecodec.cpp \ + kdecimalbytecodec.cpp khexadecimalbytecodec.cpp + +# no public API +noinst_HEADERS = ktextcharcodec.h kebcdic1047charcodec.h \ + kbinarybytecodec.h koctalbytecodec.h \ + kdecimalbytecodec.h khexadecimalbytecodec.h
\ No newline at end of file diff --git a/khexedit/lib/codecs/README b/khexedit/lib/codecs/README new file mode 100644 index 0000000..b4a0e52 --- /dev/null +++ b/khexedit/lib/codecs/README @@ -0,0 +1 @@ +This directory holds all the char codecs. All it exports is the call "createCodec()", the rest in hidden. diff --git a/khexedit/lib/codecs/kbinarybytecodec.cpp b/khexedit/lib/codecs/kbinarybytecodec.cpp new file mode 100644 index 0000000..d665a05 --- /dev/null +++ b/khexedit/lib/codecs/kbinarybytecodec.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + kbinarybytecodec.cpp - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kbinarybytecodec.h" + +using namespace KHE; + + +void KBinaryByteCodec::encode( QString &Digits, unsigned int Pos, const unsigned char Char ) const +{ + for( unsigned char M=1<<7; M>0; M>>=1 ) + Digits.at(Pos++) = (Char & M) ? '1' : '0'; +} + +void KBinaryByteCodec::encodeShort( QString &Digits, unsigned int Pos, unsigned char Char ) const +{ + unsigned char M = 1<<7; + // find first set bit + for( ; M>0; M>>=1 ) + if( Char & M ) + break; + // now set the + for( ; M>0; M>>=1 ) + Digits.at(Pos++) = (Char & M) ? '1' : '0'; +} + + +bool KBinaryByteCodec::isValidDigit( unsigned char Digit ) const +{ + return Digit == '0' || Digit == '1'; +} + + +bool KBinaryByteCodec::turnToValue( unsigned char *Digit ) const +{ + if( isValidDigit(*Digit) ) + { + *Digit -= '0'; + return true; + } + return false; +} + + +bool KBinaryByteCodec::appendDigit( unsigned char *Byte, unsigned char Digit ) const +{ + if( turnToValue(&Digit) ) + { + unsigned char B = *Byte; + if( B < 128 ) + { + B <<= 1; + B += Digit; + *Byte = B; + return true; + } + } + return false; +} + + +void KBinaryByteCodec::removeLastDigit( unsigned char *Byte ) const +{ + *Byte >>= 1; +} diff --git a/khexedit/lib/codecs/kbinarybytecodec.h b/khexedit/lib/codecs/kbinarybytecodec.h new file mode 100644 index 0000000..d0354fa --- /dev/null +++ b/khexedit/lib/codecs/kbinarybytecodec.h @@ -0,0 +1,59 @@ +/*************************************************************************** + kbinarybytecodec.h - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBINARYBYTECODEC_H +#define KHE_KBINARYBYTECODEC_H + +// lib specific +#include "kbytecodec.h" + +namespace KHE +{ + +/** class that is able to convert codings to and from binary + * + * the buffer will be always filled up to CodingWidth, if not using shortCodingFunction + * a closing '\0' will be always added + * + *@author Friedrich W. H. Kossebau + */ + +class KBinaryByteCodec : public KByteCodec +{ + public: // API to be implemented + /** */ + virtual unsigned int encodingWidth() const { return 8; } + /** */ + virtual unsigned char digitsFilledLimit() const { return 128; } + + /** encodes the Char and writes the result to */ + virtual void encode( QString &Digits, unsigned int Pos, const unsigned char Char ) const; + /** */ + virtual void encodeShort( QString &Digits, unsigned int Pos, const unsigned char Char ) const; + /** */ + virtual bool appendDigit( unsigned char *Byte, const unsigned char Digit ) const; + /** */ + virtual void removeLastDigit( unsigned char *Byte ) const; + /** */ + virtual bool isValidDigit( const unsigned char Digit ) const; + /** */ + virtual bool turnToValue( unsigned char *Digit ) const; +}; + +} + +#endif diff --git a/khexedit/lib/codecs/kbytecodec.cpp b/khexedit/lib/codecs/kbytecodec.cpp new file mode 100644 index 0000000..dc5137f --- /dev/null +++ b/khexedit/lib/codecs/kbytecodec.cpp @@ -0,0 +1,63 @@ +/*************************************************************************** + kbytecodec.cpp - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kbinarybytecodec.h" +#include "koctalbytecodec.h" +#include "kdecimalbytecodec.h" +#include "khexadecimalbytecodec.h" + +using namespace KHE; + + +KByteCodec *KByteCodec::createCodec( KCoding C ) +{ + KByteCodec *Codec; + switch( C ) + { + case DecimalCoding: Codec = new KDecimalByteCodec(); break; + case OctalCoding: Codec = new KOctalByteCodec(); break; + case BinaryCoding: Codec = new KBinaryByteCodec(); break; + case HexadecimalCoding: + default: Codec = new KHexadecimalByteCodec(); + } + return Codec; +} + +unsigned int KByteCodec::decode( unsigned char *Char, const QString &Digits, uint Pos ) const +{ + //kdDebug() << QString("KByteCodec::decode(%1,%2)").arg(Digits).arg(Pos) << endl; + const uint P = Pos; + + // remove leading 0s + while( Digits.at(Pos) == '0' ) { ++Pos; } + + unsigned char C = 0; + unsigned int d = encodingWidth(); + do + { + if( !appendDigit(&C,Digits.at(Pos)) ) + break; + + ++Pos; + --d; + } + while( d > 0 ); + + *Char = C; + return Pos - P; +} diff --git a/khexedit/lib/codecs/kcharcodec.cpp b/khexedit/lib/codecs/kcharcodec.cpp new file mode 100644 index 0000000..5a58320 --- /dev/null +++ b/khexedit/lib/codecs/kcharcodec.cpp @@ -0,0 +1,74 @@ +/*************************************************************************** + kcharcodec.cpp - description + ------------------- + begin : Do Nov 25 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kcharcodec.h" +#include "ktextcharcodec.h" +#include "kebcdic1047charcodec.h" + +using namespace KHE; + + +QStringList KCharCodec::CodecNames; + +const QStringList &KCharCodec::codecNames() +{ + // first call? + if( CodecNames.isEmpty() ) + { + CodecNames = KTextCharCodec::codecNames(); + CodecNames.append( KEBCDIC1047CharCodec::codecName() ); + } + + return CodecNames; +} + + +KCharCodec *KCharCodec::createCodec( const QString &Name ) +{ + KCharCodec *Codec = 0; + + if( KTextCharCodec::codecNames().findIndex(Name) != -1 ) + Codec = KTextCharCodec::createCodec( Name ); + else if( KEBCDIC1047CharCodec::codecName() == Name ) + Codec = KEBCDIC1047CharCodec::create(); + + // ensure at least a codec + if( Codec == 0 ) + Codec = KTextCharCodec::createLocalCodec(); + + return Codec; +} + + +KCharCodec *KCharCodec::createCodec( KEncoding C ) +{ + KCharCodec *Codec; + if( C == EBCDIC1047Encoding ) + Codec = KEBCDIC1047CharCodec::create(); + else if( C == ISO8859_1Encoding ) + Codec = KTextCharCodec::createCodec( "ISO 8859-1" ); + // LocalEncoding + else + Codec = 0; + + // ensure at least a codec + if( Codec == 0 ) + Codec = KTextCharCodec::createLocalCodec(); + + return Codec; +} diff --git a/khexedit/lib/codecs/kdecimalbytecodec.cpp b/khexedit/lib/codecs/kdecimalbytecodec.cpp new file mode 100644 index 0000000..9470382 --- /dev/null +++ b/khexedit/lib/codecs/kdecimalbytecodec.cpp @@ -0,0 +1,92 @@ +/*************************************************************************** + kdecimalbytecodec.cpp - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kdecimalbytecodec.h" + +using namespace KHE; + + +void KDecimalByteCodec::encode( QString &Digits, unsigned int Pos, unsigned char Char ) const +{ + unsigned char C = Char / 100; + Digits.at(Pos++) = '0'+C; + Char -= C * 100; + C = Char / 10; + Digits.at(Pos++) = '0'+C; + Char -= C * 10; + Digits.at(Pos) = '0'+Char; +} + + +void KDecimalByteCodec::encodeShort( QString &Digits, unsigned int Pos, unsigned char Char ) const +{ + unsigned char C; + if( (C = Char / 100) ) + { + Digits.at(Pos++) = '0'+C; + Char -= C * 100; + } + if( (C = Char / 10) ) + { + Digits.at(Pos++) = '0'+C; + Char -= C * 10; + } + Digits.at(Pos) = '0'+Char; +} + + + +bool KDecimalByteCodec::isValidDigit( unsigned char Digit ) const +{ + return Digit >= '0' && Digit <= '9'; +} + +bool KDecimalByteCodec::turnToValue( unsigned char *Digit ) const +{ + if( isValidDigit(*Digit) ) + { + *Digit -= '0'; + return true; + } + return false; +} + + +bool KDecimalByteCodec::appendDigit( unsigned char *Byte, unsigned char Digit ) const +{ + if( turnToValue(&Digit) ) + { + unsigned char B = *Byte; + if( B < 26 ) + { + B *= 10; + if( Digit <= 255-B ) + { + B += Digit; + *Byte = B; + return true; + } + } + } + return false; +} + +void KDecimalByteCodec::removeLastDigit( unsigned char *Byte ) const +{ + *Byte /= 10; +} diff --git a/khexedit/lib/codecs/kdecimalbytecodec.h b/khexedit/lib/codecs/kdecimalbytecodec.h new file mode 100644 index 0000000..31f61d0 --- /dev/null +++ b/khexedit/lib/codecs/kdecimalbytecodec.h @@ -0,0 +1,59 @@ +/*************************************************************************** + kdecimalbytecodec.h - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KDECIMALBYTECODEC_H +#define KHE_KDECIMALBYTECODEC_H + +// lib specific +#include "kbytecodec.h" + +namespace KHE +{ + +/** class that is able to convert codings to and from binary + * + * the buffer will be always filled up to CodingWidth, if not using shortCodingFunction + * a closing '\0' will be always added + * + *@author Friedrich W. H. Kossebau + */ + +class KDecimalByteCodec : public KByteCodec +{ + public: // API to be implemented + /** */ + virtual unsigned int encodingWidth() const { return 3; } + /** */ + virtual unsigned char digitsFilledLimit() const { return 26; } + + /** encodes the Char and writes the result to */ + virtual void encode( QString &Digits, unsigned int Pos, const unsigned char Char ) const; + /** */ + virtual void encodeShort( QString &Digits, unsigned int Pos, const unsigned char Char ) const; + /** */ + virtual bool appendDigit( unsigned char *Byte, const unsigned char Digit ) const; + /** */ + virtual void removeLastDigit( unsigned char *Byte ) const; + /** */ + virtual bool isValidDigit( const unsigned char Digit ) const; + /** */ + virtual bool turnToValue( unsigned char *Digit ) const; +}; + +} + +#endif diff --git a/khexedit/lib/codecs/kebcdic1047charcodec.cpp b/khexedit/lib/codecs/kebcdic1047charcodec.cpp new file mode 100644 index 0000000..f26da37 --- /dev/null +++ b/khexedit/lib/codecs/kebcdic1047charcodec.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + kebcdic1047charcodec.cpp - description + ------------------- + begin : Sa Nov 27 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kebcdic1047charcodec.h" + + +using namespace KHE; + +static Q_UINT16 UnicodeChars[256] = +{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, + 0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087, + 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007, + 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, + 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A, + 0x0020, 0x00A0, 0x00E2, 0x00E4, 0x00E0, 0x00E1, 0x00E3, 0x00E5, + 0x00E7, 0x00F1, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, + 0x0026, 0x00E9, 0x00EA, 0x00EB, 0x00E8, 0x00ED, 0x00EE, 0x00EF, + 0x00EC, 0x00DF, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x005E, + 0x002D, 0x002F, 0x00C2, 0x00C4, 0x00C0, 0x00C1, 0x00C3, 0x00C5, + 0x00C7, 0x00D1, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F, + 0x00F8, 0x00C9, 0x00CA, 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, + 0x00CC, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, + 0x00D8, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x00AB, 0x00BB, 0x00F0, 0x00FD, 0x00FE, 0x00B1, + 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, + 0x0071, 0x0072, 0x00AA, 0x00BA, 0x00E6, 0x00B8, 0x00C6, 0x00A4, + 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, + 0x0079, 0x007A, 0x00A1, 0x00BF, 0x00D0, 0x005B, 0x00DE, 0x00AE, + 0x00AC, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC, + 0x00BD, 0x00BE, 0x00DD, 0x00A8, 0x00AF, 0x005D, 0x00B4, 0x00D7, + 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x00AD, 0x00F4, 0x00F6, 0x00F2, 0x00F3, 0x00F5, + 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, + 0x0051, 0x0052, 0x00B9, 0x00FB, 0x00FC, 0x00F9, 0x00FA, 0x00FF, + 0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, + 0x0059, 0x005A, 0x00B2, 0x00D4, 0x00D6, 0x00D2, 0x00D3, 0x00D5, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x00B3, 0x00DB, 0x00DC, 0x00D9, 0x00DA, 0x009F +}; + +static unsigned char EBCDICChars[256] = +{ + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + 0x16, 0x05, 0x25, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x09, 0x0A, 0x1B, + 0x30, 0x31, 0x1A, 0x33, 0x34, 0x35, 0x36, 0x08, + 0x38, 0x39, 0x3A, 0x3B, 0x04, 0x14, 0x3E, 0xFF, + 0x41, 0xAA, 0x4A, 0xB1, 0x9F, 0xB2, 0x6A, 0xB5, + 0xBB, 0xB4, 0x9A, 0x8A, 0xB0, 0xCA, 0xAF, 0xBC, + 0x90, 0x8F, 0xEA, 0xFA, 0xBE, 0xA0, 0xB6, 0xB3, + 0x9D, 0xDA, 0x9B, 0x8B, 0xB7, 0xB8, 0xB9, 0xAB, + 0x64, 0x65, 0x62, 0x66, 0x63, 0x67, 0x9E, 0x68, + 0x74, 0x71, 0x72, 0x73, 0x78, 0x75, 0x76, 0x77, + 0xAC, 0x69, 0xED, 0xEE, 0xEB, 0xEF, 0xEC, 0xBF, + 0x80, 0xFD, 0xFE, 0xFB, 0xFC, 0xBA, 0xAE, 0x59, + 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, + 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, + 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, + 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF +}; + +static const char KEBCDIC1047CharCodecName[] = "EBCDIC 1047"; + + +bool KEBCDIC1047CharCodec::encode( char *D, const QChar &C ) const +{ + int I = C.unicode(); + // not in range? + if( 0x00FF < I ) + return false; + + *D = EBCDICChars[I]; + return true; +} + +KHEChar KEBCDIC1047CharCodec::decode( char Byte ) const +{ + return QChar(UnicodeChars[(unsigned char)Byte]); +} + +const QString& KEBCDIC1047CharCodec::name() const +{ + return codecName(); +} + +const QString& KEBCDIC1047CharCodec::codecName() +{ + static const QString Name( QString::fromLatin1(KEBCDIC1047CharCodecName) ); + return Name; +} diff --git a/khexedit/lib/codecs/kebcdic1047charcodec.h b/khexedit/lib/codecs/kebcdic1047charcodec.h new file mode 100644 index 0000000..7c30956 --- /dev/null +++ b/khexedit/lib/codecs/kebcdic1047charcodec.h @@ -0,0 +1,50 @@ +/*************************************************************************** + kebcdic1047charcodec.h - description + ------------------- + begin : Sa Nov 27 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KEBCDIC1047CHARCODEC_H +#define KHE_KEBCDIC1047CHARCODEC_H + + +#include "kcharcodec.h" + +namespace KHE +{ + +// +class KEBCDIC1047CharCodec : public KCharCodec +{ + protected: + KEBCDIC1047CharCodec(); + + public: // KCharCodec API + virtual KHEChar decode( char Byte ) const; + virtual bool encode( char *D, const QChar &C ) const; + virtual const QString& name() const; + + public: + static KEBCDIC1047CharCodec *create(); + static const QString& codecName(); +}; + + +inline KEBCDIC1047CharCodec::KEBCDIC1047CharCodec() {} + +inline KEBCDIC1047CharCodec *KEBCDIC1047CharCodec::create() { return new KEBCDIC1047CharCodec(); } + +} + +#endif diff --git a/khexedit/lib/codecs/khexadecimalbytecodec.cpp b/khexedit/lib/codecs/khexadecimalbytecodec.cpp new file mode 100644 index 0000000..7072464 --- /dev/null +++ b/khexedit/lib/codecs/khexadecimalbytecodec.cpp @@ -0,0 +1,113 @@ +/*************************************************************************** + khexadecimalbytecodec.cpp - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "khexadecimalbytecodec.h" + +using namespace KHE; + + +static const QChar BigDigit[16] = +{ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; +static const QChar SmallDigit[16] = +{ '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; + + +KHexadecimalByteCodec::KHexadecimalByteCodec( bool S ) : Digit( S?SmallDigit:BigDigit ) {} + +bool KHexadecimalByteCodec::setSmallDigits( bool S ) +{ + bool Change = ( S && Digit == BigDigit ); + Digit = S?SmallDigit:BigDigit; + return Change; +} + +bool KHexadecimalByteCodec::smallDigits() const { return Digit != BigDigit; } + + +void KHexadecimalByteCodec::encode( QString &Digits, unsigned int Pos, unsigned char Char ) const +{ + Digits.at(Pos++) = Digit[Char>>4]; + Digits.at(Pos) = Digit[Char&0x0F]; +} + +void KHexadecimalByteCodec::encodeShort( QString &Digits, unsigned int Pos, unsigned char Char ) const +{ + unsigned char C; + if( (C = (Char>>4)) ) + Digits.at(Pos++) = Digit[C]; + Digits.at(Pos) = Digit[Char&0x0F]; +} + + +static inline bool isValidBigDigit( unsigned char Digit ) +{ + return (Digit >= 'A' && Digit <= 'F'); +} + +static inline bool isValidSmallDigit( unsigned char Digit ) +{ + return (Digit >= 'a' && Digit <= 'f'); +} + +static inline bool isValidDecimalDigit( unsigned char Digit ) +{ + return Digit >= '0' && Digit <= '9'; +} + + +bool KHexadecimalByteCodec::isValidDigit( unsigned char Digit ) const +{ + return isValidDecimalDigit(Digit) || isValidBigDigit(Digit) || isValidSmallDigit(Digit); +} + +bool KHexadecimalByteCodec::turnToValue( unsigned char *Digit ) const +{ + if( isValidDecimalDigit(*Digit) ) + *Digit -= '0'; + else if( isValidBigDigit(*Digit) ) + *Digit -= 'A' - 10; + else if( isValidSmallDigit(*Digit) ) + *Digit -= 'a' - 10; + else + return false; + + return true; +} + +bool KHexadecimalByteCodec::appendDigit( unsigned char *Byte, unsigned char Digit ) const +{ + if( turnToValue(&Digit) ) + { + unsigned char B = *Byte; + if( B < 16 ) + { + B <<= 4; + B += Digit; + *Byte = B; + return true; + } + } + return false; +} + + + +void KHexadecimalByteCodec::removeLastDigit( unsigned char *Byte ) const +{ + *Byte >>= 4; +} diff --git a/khexedit/lib/codecs/khexadecimalbytecodec.h b/khexedit/lib/codecs/khexadecimalbytecodec.h new file mode 100644 index 0000000..9bb1969 --- /dev/null +++ b/khexedit/lib/codecs/khexadecimalbytecodec.h @@ -0,0 +1,69 @@ +/*************************************************************************** + khexadecimalbytecodec.h - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KHEXADECIMALBYTECODEC_H +#define KHE_KHEXADECIMALBYTECODEC_H + +// lib specific +#include "kbytecodec.h" + +namespace KHE +{ + +/** class that is able to convert codings to and from hexadecimal + * + * the buffer will be always filled up to CodingWidth, if not using shortCodingFunction + * a closing '\0' will be always added + * + *@author Friedrich W. H. Kossebau + */ + +class KHexadecimalByteCodec : public KByteCodec +{ + public: + KHexadecimalByteCodec( bool S = false ); + + public: + bool setSmallDigits( bool S ); + bool smallDigits() const; + + public: // API to be implemented + /** */ + virtual unsigned int encodingWidth() const { return 2; } + /** */ + virtual unsigned char digitsFilledLimit() const { return 16; } + + /** encodes the Char and writes the result to */ + virtual void encode( QString &Digits, unsigned int Pos, const unsigned char Char ) const; + /** */ + virtual void encodeShort( QString &Digits, unsigned int Pos, const unsigned char Char ) const; + /** */ + virtual bool appendDigit( unsigned char *Byte, const unsigned char Digit ) const; + /** */ + virtual void removeLastDigit( unsigned char *Byte ) const; + /** */ + virtual bool isValidDigit( const unsigned char Digit ) const; + /** */ + virtual bool turnToValue( unsigned char *Digit ) const; + + protected: + const QChar* Digit; +}; + +} + +#endif diff --git a/khexedit/lib/codecs/koctalbytecodec.cpp b/khexedit/lib/codecs/koctalbytecodec.cpp new file mode 100644 index 0000000..1167941 --- /dev/null +++ b/khexedit/lib/codecs/koctalbytecodec.cpp @@ -0,0 +1,80 @@ +/*************************************************************************** + koctalbytecodec.cpp - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "koctalbytecodec.h" + +using namespace KHE; + + +void KOctalByteCodec::encode( QString &Digits, unsigned int Pos, unsigned char Char ) const +{ + Digits.at(Pos++) = '0'+(Char>>6); + Digits.at(Pos++) = '0'+((Char>>3)&0x07); + Digits.at(Pos) = '0'+((Char) &0x07); +} + + +void KOctalByteCodec::encodeShort( QString &Digits, unsigned int Pos, unsigned char Char ) const +{ + unsigned char C; + if( (C = (Char>>6)&0x07) ) + Digits.at(Pos++) = '0'+C; + if( (C = (Char>>3)&0x07) ) + Digits.at(Pos++) = '0'+C; + Digits.at(Pos) = '0'+((Char)&0x07); +} + + +bool KOctalByteCodec::isValidDigit( unsigned char Digit ) const +{ + return Digit >= '0' && Digit <= '7'; +} + + +bool KOctalByteCodec::turnToValue( unsigned char *Digit ) const +{ + if( isValidDigit(*Digit) ) + { + *Digit -= '0'; + return true; + } + return false; +} + + +bool KOctalByteCodec::appendDigit( unsigned char *Byte, unsigned char Digit ) const +{ + if( turnToValue(&Digit) ) + { + unsigned char B = *Byte; + if( B < 64 ) + { + B <<= 3; + B += Digit; + *Byte = B; + return true; + } + } + return false; +} + + +void KOctalByteCodec::removeLastDigit( unsigned char *Byte ) const +{ + *Byte >>= 3; +} diff --git a/khexedit/lib/codecs/koctalbytecodec.h b/khexedit/lib/codecs/koctalbytecodec.h new file mode 100644 index 0000000..e05ca66 --- /dev/null +++ b/khexedit/lib/codecs/koctalbytecodec.h @@ -0,0 +1,59 @@ +/*************************************************************************** + koctalbytecodec.h - description + ------------------- + begin : Mo Nov 29 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KOCTALBYTECODEC_H +#define KHE_KOCTALBYTECODEC_H + +// lib specific +#include "kbytecodec.h" + +namespace KHE +{ + +/** class that is able to convert codings to and from binary + * + * the buffer will be always filled up to CodingWidth, if not using shortCodingFunction + * a closing '\0' will be always added + * + *@author Friedrich W. H. Kossebau + */ + +class KOctalByteCodec : public KByteCodec +{ + public: // API to be implemented + /** */ + virtual unsigned int encodingWidth() const { return 3; } + /** */ + virtual unsigned char digitsFilledLimit() const { return 64; } + + /** encodes the Char and writes the result to */ + virtual void encode( QString &Digits, unsigned int Pos, const unsigned char Char ) const; + /** */ + virtual void encodeShort( QString &Digits, unsigned int Pos, const unsigned char Char ) const; + /** */ + virtual bool appendDigit( unsigned char *Byte, const unsigned char Digit ) const; + /** */ + virtual void removeLastDigit( unsigned char *Byte ) const; + /** */ + virtual bool isValidDigit( const unsigned char Digit ) const; + /** */ + virtual bool turnToValue( unsigned char *Digit ) const; +}; + +} + +#endif diff --git a/khexedit/lib/codecs/ktextcharcodec.cpp b/khexedit/lib/codecs/ktextcharcodec.cpp new file mode 100644 index 0000000..613dedd --- /dev/null +++ b/khexedit/lib/codecs/ktextcharcodec.cpp @@ -0,0 +1,236 @@ +/*************************************************************************** + ktextcharcodec.cpp - description + ------------------- + begin : Sa Nov 27 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include "qtextcodec.h" +// kde specific +#include <kglobal.h> +#include <klocale.h> +#include <kcharsets.h> +// lib specific +#include "ktextcharcodec.h" + + +using namespace KHE; + +static const char QTextCodecWhiteSpace = 63; + +static struct KEncodingNames { + KEncoding Encoding; + const char *Name; +} +const EncodingNames[] = { +{ ISO8859_1Encoding, "ISO 8859-1" }, +{ ISO8859_2Encoding, "ISO 8859-2" }, +{ ISO8859_3Encoding, "ISO 8859-3" }, +{ ISO8859_4Encoding, "ISO 8859-4" }, +{ ISO8859_5Encoding, "ISO 8859-5" }, +{ ISO8859_6Encoding, "ISO 8859-6" }, +{ ISO8859_7Encoding, "ISO 8859-7" }, +{ ISO8859_8Encoding, "ISO 8859-8" }, +{ ISO8859_8_IEncoding, "ISO 8859-8-I" }, +{ ISO8859_9Encoding, "ISO 8859-9" }, +{ ISO8859_11Encoding, "ISO 8859-11" }, +{ ISO8859_13Encoding, "ISO 8859-13" }, +{ ISO8859_15Encoding, "ISO 8859-15" }, +{ CP1250Encoding, "CP 1250" }, +{ CP1251Encoding, "CP 1251" }, +{ CP1252Encoding, "CP 1252" }, +{ CP1253Encoding, "CP 1253" }, +{ CP1254Encoding, "CP 1254" }, +{ CP1255Encoding, "CP 1255" }, +{ CP1256Encoding, "CP 1256" }, +{ CP1257Encoding, "CP 1257" }, +{ CP1258Encoding, "CP 1258" }, +{ IBM850Encoding, "IBM 850" }, +{ IBM866Encoding, "IBM 866" }, +{ KOI8_REncoding, "KOI8-R" }, +{ KOI8_UEncoding, "KOI8-U" } }; +//TODO: WS2 +static const unsigned int NoOfEncodings = 26; + +static bool is8Bit( QTextCodec *Codec ) +{ + bool Found = false; + for( unsigned int i=0; i<NoOfEncodings; ++i ) + { + if( qstrcmp(Codec->name(),EncodingNames[i].Name) == 0 ) + { + Found = true; + break; + } + } + return Found; +} + +static QTextCodec *createLatin1() +{ + return KGlobal::charsets()->codecForName( EncodingNames[0].Name ); +} + +/** heuristic seems to be doomed :( +static bool is8Bit( QTextCodec *Codec ) +{ + bool Result = true; + + // first test different for 0 + unsigned char c[4]; + c[0] = 0; + c[1] = c[2] = c[3] = 230; + QString S = Codec->toUnicode( (const char*)&c,4 ); + int Length = 1; + QCString CS = Codec->fromUnicode( S, Length ); + //kdDebug() << Codec->name() << " "<<Length << endl; + if( Length > 0 ) + Result = false; + // test if all chars survive the recoding + else + do + { + ++c[0]; + S = Codec->toUnicode( (const char*)&c,4 ); + Length = 1; + CS = Codec->fromUnicode( S, Length ); + //kdDebug() << Codec->name() << " "<<c[0]<<"->"<<CS[0]<<":"<<Length << endl; + if( Length != 1 || (CS[0] != (char)c[0] && CS[0] != QTextCodecWhiteSpace) ) + { + Result = false; + break; + } + } + while( c[0] < 255 ); + return Result; +} +const QStringList &KTextCharCodec::codecNames() +{ + // first call? + if( CodecNames.isEmpty() ) +{ + const QStringList &CharSets = KGlobal::charsets()->availableEncodingNames(); + + for( QStringList::ConstIterator it = CharSets.begin(); it != CharSets.end(); ++it ) +{ + bool Found = true; + QTextCodec* Codec = KGlobal::charsets()->codecForName( *it, Found ); + if( Found && is8Bit(Codec) ) + CodecNames.append( QString::fromLatin1(Codec->name()) ); +} +} + + return CodecNames; +} + +QString KTextCharCodec::nameOfEncoding( KEncoding C ) +{ + KTextCharCodec *Codec = 0; + + const char* N = 0; + for( unsigned int i=0; i<NoOfEncodings; ++i ) + { + if( EncodingNames[i].Encoding == C ) + { + N = EncodingNames[i].Name; + break; + } + } + + if( N != 0 ) + { + QString CodeName = QString::fromLatin1( N ); + } + return Codec; +} + */ + + +QStringList KTextCharCodec::CodecNames; + +KTextCharCodec *KTextCharCodec::createLocalCodec() +{ + QTextCodec *Codec = KGlobal::locale()->codecForEncoding(); + if( !is8Bit(Codec) ) + Codec = createLatin1(); + return new KTextCharCodec( Codec ); +} + + +KTextCharCodec *KTextCharCodec::createCodec( const QString &CodeName ) +{ + bool Ok; + QTextCodec *Codec = KGlobal::charsets()->codecForName( CodeName, Ok ); + if( Ok ) + Ok = is8Bit( Codec ); + return Ok ? new KTextCharCodec( Codec ) : 0; +} + + +const QStringList &KTextCharCodec::codecNames() +{ + // first call? + if( CodecNames.isEmpty() ) + { + for( unsigned int i=0; i<NoOfEncodings; ++i ) + { + bool Found = true; + QString Name = QString::fromLatin1( EncodingNames[i].Name ); + QTextCodec* Codec = KGlobal::charsets()->codecForName( Name, Found ); + if( Found ) + CodecNames.append( QString::fromLatin1(Codec->name()) ); + } + } + + return CodecNames; +} + + +KTextCharCodec::KTextCharCodec( QTextCodec *C ) + : Codec( C ), + Decoder( C->makeDecoder() ), + Encoder( C->makeEncoder() ) +{} + +KTextCharCodec::~KTextCharCodec() +{ + delete Decoder; + delete Encoder; +} + +bool KTextCharCodec::encode( char *D, const QChar &C ) const +{ + if( !Codec->canEncode(C) ) // TODO: do we really need the codec? + return false; + int dummy; + char T = Encoder->fromUnicode( C, dummy )[0]; + + *D = T; + return true; +} + + +KHEChar KTextCharCodec::decode( char Byte ) const +{ + QString S( Decoder->toUnicode(&Byte,1) ); + return KHEChar(S.at(0)); +} + + +const QString& KTextCharCodec::name() const +{ + if( Name.isNull() ) + Name = QString::fromLatin1( Codec->name() ); + return Name; +} diff --git a/khexedit/lib/codecs/ktextcharcodec.h b/khexedit/lib/codecs/ktextcharcodec.h new file mode 100644 index 0000000..683919c --- /dev/null +++ b/khexedit/lib/codecs/ktextcharcodec.h @@ -0,0 +1,66 @@ +/*************************************************************************** + ktextcharcodec.h - description + ------------------- + begin : Sa Nov 27 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KTEXTCHARCODEC_H +#define KHE_KTEXTCHARCODEC_H + + +#include "kcharcodec.h" + +class QTextCodec; +class QTextDecoder; +class QTextEncoder; + +namespace KHE +{ + +// used by all codecs with full char coping, i.e. there are no undefined chars +class KTextCharCodec : public KCharCodec +{ + public: + static KTextCharCodec *createCodec( const QString &CodeName ); + static KTextCharCodec *createCodec( KEncoding C ); + static KTextCharCodec *createLocalCodec(); + + static const QStringList &codecNames(); + + protected: + KTextCharCodec( QTextCodec *C ); + public: + virtual ~KTextCharCodec(); + + public: // KCharCodec API + virtual bool encode( char *D, const QChar &C ) const; + virtual KHEChar decode( char Byte ) const; + virtual const QString& name() const; + + + protected: + QTextCodec *Codec; + /** decodes the chars to unicode */ + QTextDecoder *Decoder; + /** encodes the chars from unicode */ + QTextEncoder *Encoder; + /** */ + mutable QString Name; + + static QStringList CodecNames; +}; + +} + +#endif diff --git a/khexedit/lib/controller/Makefile.am b/khexedit/lib/controller/Makefile.am new file mode 100644 index 0000000..5fd894b --- /dev/null +++ b/khexedit/lib/controller/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES = -I$(srcdir)/.. $(all_includes) + +METASOURCES = AUTO + +# +noinst_LTLIBRARIES = libkcontroller.la +libkcontroller_la_SOURCES = kcontroller.cpp ktabcontroller.cpp knavigator.cpp \ + keditor.cpp kvalueeditor.cpp kchareditor.cpp + +# no public API +noinst_HEADERS = kcontroller.h ktabcontroller.h knavigator.h \ + keditor.h kvalueeditor.h kchareditor.h diff --git a/khexedit/lib/controller/kchareditor.cpp b/khexedit/lib/controller/kchareditor.cpp new file mode 100644 index 0000000..5b48fc6 --- /dev/null +++ b/khexedit/lib/controller/kchareditor.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + kchareditor.cpp - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qevent.h> +// lib specific +#include "kcharcolumn.h" +#include "kcharcodec.h" +#include "khexedit.h" +#include "kchareditor.h" + + +using namespace KHE; + + +KCharEditor::KCharEditor( KCharColumn *CC, KBufferCursor *BC, KHexEdit *HE, KController *P ) + : KEditor( BC, HE, P ), + CharColumn( CC ) +{ +} + + +bool KCharEditor::handleKeyPress( QKeyEvent *KeyEvent ) +{ + bool KeyUsed = false; + // some input that should be inserted? + if( KeyEvent->text().length() > 0 + && !(KeyEvent->state()&( Qt::ControlButton | Qt::AltButton | Qt::MetaButton )) ) + { + QChar C = KeyEvent->text()[0]; + if( C.isPrint() ) + { + QByteArray D( 1 ); + if( CharColumn->codec()->encode(&D[0],C) ) + { + // clearUndoRedoInfo = false; + HexEdit->insert( D ); + KeyUsed = true; + } + } + } + + return KeyUsed ? true : KEditor::handleKeyPress(KeyEvent); +} diff --git a/khexedit/lib/controller/kchareditor.h b/khexedit/lib/controller/kchareditor.h new file mode 100644 index 0000000..74c3d8d --- /dev/null +++ b/khexedit/lib/controller/kchareditor.h @@ -0,0 +1,43 @@ +/*************************************************************************** + kchareditor.h - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCHAREDITOR_H +#define KHE_KCHAREDITOR_H + +// lib specific +#include "keditor.h" + +namespace KHE +{ + +class KCharColumn; + +class KCharEditor : public KEditor +{ + public: + KCharEditor( KCharColumn *CC, KBufferCursor *BC, KHexEdit *HE, KController *P ); + + public: // KEditor API + virtual bool handleKeyPress( QKeyEvent *KeyEvent ); + + protected: + KCharColumn *CharColumn; +}; + +} + +#endif diff --git a/khexedit/lib/controller/kcontroller.cpp b/khexedit/lib/controller/kcontroller.cpp new file mode 100644 index 0000000..490da93 --- /dev/null +++ b/khexedit/lib/controller/kcontroller.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + kcontroller.cpp - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + + +// lib specific +#include "khexedit.h" +#include "kcontroller.h" + + +using namespace KHE; + +KController::KController( KHexEdit* HE, KController *P ) + : Parent( P ), HexEdit( HE ) +{ +} + +bool KController::handleKeyPress( QKeyEvent *KeyEvent ) +{ + return Parent ? Parent->handleKeyPress( KeyEvent ) : false; +} diff --git a/khexedit/lib/controller/kcontroller.h b/khexedit/lib/controller/kcontroller.h new file mode 100644 index 0000000..daeb0d5 --- /dev/null +++ b/khexedit/lib/controller/kcontroller.h @@ -0,0 +1,44 @@ +/*************************************************************************** + kcontroller.h - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCONTROLLER_H +#define KHE_KCONTROLLER_H + + +class QKeyEvent; + +namespace KHE +{ + +class KHexEdit; + +class KController +{ + protected: + KController( KHexEdit *HE, KController *P ); + + public: // KController API + virtual bool handleKeyPress( QKeyEvent *KeyEvent ); + + protected: + KController *Parent; + KHexEdit *HexEdit; +}; + +} + +#endif diff --git a/khexedit/lib/controller/keditor.cpp b/khexedit/lib/controller/keditor.cpp new file mode 100644 index 0000000..7d4e92f --- /dev/null +++ b/khexedit/lib/controller/keditor.cpp @@ -0,0 +1,197 @@ +/*************************************************************************** + keditor.cpp - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + + +// lib specific +#include "kdatabuffer.h" +#include "kbufferranges.h" +#include "kbufferlayout.h" +#include "kbuffercursor.h" +#include "kwordbufferservice.h" +#include "khexedit.h" +#include "keditor.h" + + +using namespace KHE; + +KEditor::KEditor( KBufferCursor *BC, KHexEdit* HE, KController *P ) + : KController( HE, P ), + BufferCursor( BC ) +{ +} + + +bool KEditor::handleKeyPress( QKeyEvent *KeyEvent ) +{ + bool clearUndoRedoInfo = true; + bool ShiftPressed = KeyEvent->state() & Qt::ShiftButton; + bool ControlPressed = KeyEvent->state() & Qt::ControlButton; + bool AltPressed = KeyEvent->state() & Qt::AltButton; + + bool KeyUsed = true; + // we only care for cursor keys and the like, won't hardcode any other keys + // we also don't check whether the commands are allowed + // as the commands are also available as API so the check has to be done + // in each command anyway + switch( KeyEvent->key() ) + { + case Qt::Key_Delete: + if( ShiftPressed ) + HexEdit->cut(); + else if( HexEdit->BufferRanges->hasSelection() ) + HexEdit->removeSelectedData(); + else + { + doEditAction( ControlPressed ? WordDelete : CharDelete ); + clearUndoRedoInfo = false; + } + break; + + case Qt::Key_Insert: + if( ShiftPressed ) + HexEdit->paste(); + else if( ControlPressed ) + HexEdit->copy(); + else + HexEdit->setOverwriteMode( !HexEdit->OverWrite ); + break; + + case Qt::Key_Backspace: + if( AltPressed ) + { + if( ControlPressed ) + break; + else if( ShiftPressed ) + { +// HexEdit->redo(); + break; + } + else + { +// HexEdit->undo(); + break; + } + } + else if( HexEdit->BufferRanges->hasSelection() ) + { + HexEdit->removeSelectedData(); + break; + } + + doEditAction( ControlPressed ? WordBackspace : CharBackspace ); + clearUndoRedoInfo = false; + break; + case Qt::Key_F16: // "Copy" key on Sun keyboards + HexEdit->copy(); + break; + case Qt::Key_F18: // "Paste" key on Sun keyboards + HexEdit->paste(); + break; + case Qt::Key_F20: // "Cut" key on Sun keyboards + HexEdit->cut(); + break; + + default: + KeyUsed = false; + } + +// if( clearUndoRedoInfo ) +// clearUndoRedo(); +// changeIntervalTimer->start( 100, true ); + + return KeyUsed ? true : KController::handleKeyPress(KeyEvent); +} + + + +void KEditor::doEditAction( KEditAction Action ) +{ + KSection ChangedRange; + + HexEdit->pauseCursor( true ); + + switch( Action ) + { + case CharDelete: + if( !HexEdit->OverWrite ) + { + int Index = BufferCursor->realIndex(); + if( Index < HexEdit->BufferLayout->length() ) + { + ChangedRange = HexEdit->removeData( KSection(Index,1,false) ); + if( Index == HexEdit->BufferLayout->length() ) + BufferCursor->gotoEnd(); + } + } + break; + + case WordDelete: // kills data until the start of the next word + if( !HexEdit->OverWrite ) + { + int Index = BufferCursor->realIndex(); + if( Index < HexEdit->BufferLayout->length() ) + { + KWordBufferService WBS( HexEdit->DataBuffer, HexEdit->Codec ); + int End = WBS.indexOfBeforeNextWordStart( Index ); + ChangedRange = HexEdit->removeData( KSection(Index,End) ); + if( Index == HexEdit->BufferLayout->length() ) + BufferCursor->gotoEnd(); + } + } + break; + + case CharBackspace: + if( HexEdit->OverWrite ) + BufferCursor->gotoPreviousByte(); + else + { + int DeleteIndex = BufferCursor->realIndex() - 1; + if( DeleteIndex >= 0 ) + { + ChangedRange = HexEdit->removeData( KSection(DeleteIndex,1,false) ); + if( DeleteIndex == HexEdit->BufferLayout->length() ) + BufferCursor->gotoEnd(); + else + BufferCursor->gotoPreviousByte(); + } + } + break; + case WordBackspace: + { + int LeftIndex = BufferCursor->realIndex() - 1; + if( LeftIndex >= 0 ) + { + KWordBufferService WBS( HexEdit->DataBuffer, HexEdit->Codec ); + int WordStart = WBS.indexOfPreviousWordStart( LeftIndex ); + if( !HexEdit->OverWrite ) + ChangedRange = HexEdit->removeData( KSection(WordStart,LeftIndex) ); + if( WordStart == HexEdit->BufferLayout->length() ) + BufferCursor->gotoEnd(); + else + BufferCursor->gotoIndex(WordStart); + } + } + } + + HexEdit->repaintChanged(); + HexEdit->ensureCursorVisible(); + + HexEdit->unpauseCursor(); + + emit HexEdit->cursorPositionChanged( BufferCursor->index() ); + if( ChangedRange.isValid() ) emit HexEdit->bufferChanged( ChangedRange.start(), ChangedRange.end() ); +} diff --git a/khexedit/lib/controller/keditor.h b/khexedit/lib/controller/keditor.h new file mode 100644 index 0000000..dc2b0fd --- /dev/null +++ b/khexedit/lib/controller/keditor.h @@ -0,0 +1,52 @@ +/*************************************************************************** + keditor.h - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KEDITOR_H +#define KHE_KEDITOR_H + + +// lib specific +#include "kcontroller.h" + + +namespace KHE +{ + +class KBufferCursor; + +class KEditor : public KController +{ + protected: + enum KEditAction { CharDelete, WordDelete, CharBackspace, WordBackspace }; + + protected: + KEditor( KBufferCursor *BC, KHexEdit *HE, KController *P ); + + public: // API + virtual bool handleKeyPress( QKeyEvent *KeyEvent ); + + protected: + /** executes keyboard Action \a Action. This is normally called by a key event handler. */ + void doEditAction( KEditAction Action ); + + protected: + KBufferCursor *BufferCursor; +}; + +} + +#endif diff --git a/khexedit/lib/controller/knavigator.cpp b/khexedit/lib/controller/knavigator.cpp new file mode 100644 index 0000000..51c8048 --- /dev/null +++ b/khexedit/lib/controller/knavigator.cpp @@ -0,0 +1,142 @@ +/*************************************************************************** + knavigator.cpp - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + + +// qt specific +#include <qevent.h> +// lib specific +#include "kdatabuffer.h" +#include "kbufferranges.h" +#include "kbuffercursor.h" +#include "kwordbufferservice.h" +#include "khexedit.h" +#include "knavigator.h" + + +using namespace KHE; + +KNavigator::KNavigator( KHexEdit* HE, KController *P ) + : KController( HE, P ) +{ +} + +bool KNavigator::handleKeyPress( QKeyEvent *KeyEvent ) +{ + bool KeyUsed = true; + + //bool clearUndoRedoInfo = true; + bool ShiftPressed = KeyEvent->state() & Qt::ShiftButton; + bool ControlPressed = KeyEvent->state() & Qt::ControlButton; + //bool AltPressed = KeyEvent->state() & AltButton; + + // we only care for cursor keys and the like, won't hardcode any other keys + // we also don't check whether the commands are allowed + // as the commands are also available as API so the check has to be done + // in each command anyway + switch( KeyEvent->key() ) + { + case Qt::Key_Left: + moveCursor( ControlPressed ? MoveWordBackward : MoveBackward, ShiftPressed ); + break; + case Qt::Key_Right: + moveCursor( ControlPressed ? MoveWordForward : MoveForward, ShiftPressed ); + break; + case Qt::Key_Up: + moveCursor( ControlPressed ? MovePgUp : MoveUp, ShiftPressed ); + break; + case Qt::Key_Down: + moveCursor( ControlPressed ? MovePgDown : MoveDown, ShiftPressed ); + break; + case Qt::Key_Home: + moveCursor( ControlPressed ? MoveHome : MoveLineStart, ShiftPressed ); + break; + case Qt::Key_End: + moveCursor( ControlPressed ? MoveEnd : MoveLineEnd, ShiftPressed ); + break; + case Qt::Key_Prior: + moveCursor( MovePgUp, ShiftPressed ); + break; + case Qt::Key_Next: + moveCursor( MovePgDown, ShiftPressed ); + break; + + default: + KeyUsed = false; + } + + return KeyUsed ? true : KController::handleKeyPress(KeyEvent); +} + + +void KNavigator::moveCursor( KMoveAction Action, bool Select ) +{ + HexEdit->pauseCursor( true ); + + KBufferCursor *BufferCursor = HexEdit->BufferCursor; + KBufferRanges *BufferRanges = HexEdit->BufferRanges; + + if( Select ) + { + if( !BufferRanges->selectionStarted() ) + BufferRanges->setSelectionStart( BufferCursor->realIndex() ); + } + else + BufferRanges->removeSelection(); + + HexEdit->resetInputContext(); + switch( Action ) + { + case MoveBackward: BufferCursor->gotoPreviousByte(); break; + case MoveWordBackward: { + KWordBufferService WBS( HexEdit->DataBuffer, HexEdit->Codec ); + int NewIndex = WBS.indexOfPreviousWordStart( BufferCursor->realIndex() ); + BufferCursor->gotoIndex( NewIndex ); + } + break; + case MoveForward: BufferCursor->gotoNextByte(); break; + case MoveWordForward: { + KWordBufferService WBS( HexEdit->DataBuffer, HexEdit->Codec ); + int NewIndex = WBS.indexOfNextWordStart( BufferCursor->realIndex() ); + BufferCursor->gotoCIndex( NewIndex ); + } + break; + case MoveUp: BufferCursor->gotoUp(); break; + case MovePgUp: BufferCursor->gotoPageUp(); break; + case MoveDown: BufferCursor->gotoDown(); break; + case MovePgDown: BufferCursor->gotoPageDown(); break; + case MoveLineStart: BufferCursor->gotoLineStart(); break; + case MoveHome: BufferCursor->gotoStart(); break; + case MoveLineEnd: BufferCursor->gotoLineEnd(); break; + case MoveEnd: BufferCursor->gotoEnd(); break; + } + + if( Select ) + BufferRanges->setSelectionEnd( BufferCursor->realIndex() ); + + HexEdit->repaintChanged(); + HexEdit->ensureCursorVisible(); + + HexEdit->unpauseCursor(); + + if( BufferRanges->isModified() ) + { + if( !HexEdit->isOverwriteMode() ) emit HexEdit->cutAvailable( BufferRanges->hasSelection() ); + emit HexEdit->copyAvailable( BufferRanges->hasSelection() ); + KSection Selection = BufferRanges->selection(); + emit HexEdit->selectionChanged( Selection.start(), Selection.end() ); + } +} diff --git a/khexedit/lib/controller/knavigator.h b/khexedit/lib/controller/knavigator.h new file mode 100644 index 0000000..4615419 --- /dev/null +++ b/khexedit/lib/controller/knavigator.h @@ -0,0 +1,46 @@ +/*************************************************************************** + knavigator.h - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KNAVIGATOR_H +#define KHE_KNAVIGATOR_H + +// lib specific +#include "kcontroller.h" + +namespace KHE +{ + +class KNavigator : public KController +{ + protected: + enum KMoveAction { MoveBackward, MoveWordBackward, MoveForward, MoveWordForward, + MoveUp, MovePgUp, MoveDown, MovePgDown, + MoveLineStart, MoveHome, MoveLineEnd, MoveEnd }; + public: + KNavigator( KHexEdit *HE, KController *P ); + + public: // KEditor API + virtual bool handleKeyPress( QKeyEvent *KeyEvent ); + + protected: + /** moves the cursor according to the action, handles all drawing */ + void moveCursor( KMoveAction Action, bool Select ); +}; + +} + +#endif diff --git a/khexedit/lib/controller/ktabcontroller.cpp b/khexedit/lib/controller/ktabcontroller.cpp new file mode 100644 index 0000000..76c3051 --- /dev/null +++ b/khexedit/lib/controller/ktabcontroller.cpp @@ -0,0 +1,70 @@ +/*************************************************************************** + ktabcontroller.cpp - description + ------------------- + begin : So Dez 5 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qevent.h> +// lib specific +#include "kvaluecolumn.h" +#include "kcharcolumn.h" +#include "khexedit.h" +#include "ktabcontroller.h" + + +using namespace KHE; + +KTabController::KTabController( KHexEdit* HE, KController *P ) + : KController( HE, P ), + TabChangesFocus( false ) +{ +} + + +bool KTabController::handleKeyPress( QKeyEvent *KeyEvent ) +{ + bool KeyUsed = false; + + bool ShiftPressed = KeyEvent->state() & Qt::ShiftButton; + + if( KeyEvent->key() == Qt::Key_Tab ) + { + // are we in the char column? + if( HexEdit->cursorColumn() == KHexEdit::CharColumnId ) + { + // in last column we care about tab changes focus + if( HexEdit->ValueColumn->isVisible() && (!TabChangesFocus || ShiftPressed) ) + { + HexEdit->setCursorColumn( KHexEdit::ValueColumnId ); + KeyUsed = true; + } + } + // value column then + else + { + if( HexEdit->CharColumn->isVisible() ) + { + // in last column we care about tab changes focus + if( HexEdit->CharColumn->isVisible() && (!TabChangesFocus || !ShiftPressed) ) + { + HexEdit->setCursorColumn( KHexEdit::CharColumnId ); + KeyUsed = true; + } + } + } + } + + return KeyUsed ? true : KController::handleKeyPress(KeyEvent); +} diff --git a/khexedit/lib/controller/ktabcontroller.h b/khexedit/lib/controller/ktabcontroller.h new file mode 100644 index 0000000..e1898b4 --- /dev/null +++ b/khexedit/lib/controller/ktabcontroller.h @@ -0,0 +1,52 @@ +/*************************************************************************** + ktabcontroller.h - description + ------------------- + begin : So Dez 5 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KTABCONTROLLER_H +#define KHE_KTABCONTROLLER_H + + +// lib specific +#include "kcontroller.h" + + +namespace KHE +{ + +class KTabController : public KController +{ + public: + KTabController( KHexEdit *HE, KController *P ); + + public: // API + virtual bool handleKeyPress( QKeyEvent *KeyEvent ); + + public: + bool tabChangesFocus() const; + void setTabChangesFocus( bool TCF ); + + protected: + /** flag if tab key should be ignored */ + bool TabChangesFocus:1; +}; + + +inline bool KTabController::tabChangesFocus() const { return TabChangesFocus; } +inline void KTabController::setTabChangesFocus( bool TCF ) { TabChangesFocus = TCF; } + +} + +#endif diff --git a/khexedit/lib/controller/kvalueeditor.cpp b/khexedit/lib/controller/kvalueeditor.cpp new file mode 100644 index 0000000..ebfb589 --- /dev/null +++ b/khexedit/lib/controller/kvalueeditor.cpp @@ -0,0 +1,226 @@ +/*************************************************************************** + kvalueeditor.cpp - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qevent.h> +// lib specific +#include "kvaluecolumn.h" +#include "kbufferranges.h" +#include "kbuffercursor.h" +#include "khexedit.h" +#include "kvalueeditor.h" + + +using namespace KHE; + +KValueEditor::KValueEditor( KValueColumn *VC, KBufferCursor *BC, KHexEdit* HE, KController *P ) + : KEditor( BC, HE, P ), + ValueColumn( VC ), + InEditMode( false ), + EditModeByInsert( false ) +{ +} + + +bool KValueEditor::handleKeyPress( QKeyEvent *KeyEvent ) +{ + bool KeyUsed = true; + + // TODO: for now we don't touch it if there are selections + if( !HexEdit->BufferRanges->hasSelection() ) + { + // + switch( KeyEvent->key() ) + { + case Qt::Key_Plus: + doValueEditAction( IncValue ); + break; + case Qt::Key_Minus: + doValueEditAction( DecValue ); + break; + case Qt::Key_Space: + if( !InEditMode ) + { + KeyUsed = false; + break; + } + case Qt::Key_Enter: + case Qt::Key_Return: + doValueEditAction( InEditMode?LeaveValue:EnterValue ); + break; + case Qt::Key_Escape: + if( InEditMode ) + doValueEditAction( CancelValue ); + else + KeyUsed = false; + break; + case Qt::Key_Backspace: + if( InEditMode ) + doValueEditAction( ValueBackspace ); + else + KeyUsed = false; + break; + default: + // is plain char? + if( KeyEvent->text().length() > 0 + && ( !(KeyEvent->state()&( Qt::ControlButton | Qt::AltButton | Qt::MetaButton )) ) ) + { + QChar C = KeyEvent->text()[0]; + // no usable char? + if( !C.isLetterOrNumber() ) + { + KeyUsed = false; + break; + } + int Input = C.latin1(); + + if( InEditMode ) + doValueEditAction( ValueAppend, Input ); + else + { + unsigned char InputValue = 0; + const KByteCodec *ByteCodec = ValueColumn->byteCodec(); + // valid digit? + if( ByteCodec->appendDigit(&InputValue,Input) ) + { + if( HexEdit->OverWrite ) + doValueEditAction( ValueEdit, InputValue ); + else + { + int Index = BufferCursor->realIndex(); + if( HexEdit->DataBuffer->insert(Index,(char*)&InputValue,1) > 0 ) + { + HexEdit->pauseCursor(); + HexEdit->updateLength(); + + InEditMode = true; + EditModeByInsert = true; + OldValue = EditValue = InputValue; + ByteCodec->encode( ByteBuffer, 0, EditValue ); + + BufferCursor->gotoRealIndex(); + KSection ChangedRange( Index,HexEdit->DataBuffer->size()-1 ); + HexEdit->BufferRanges->addChangedRange( ChangedRange ); + HexEdit->repaintChanged(); + HexEdit->ensureCursorVisible(); + HexEdit->unpauseCursor(); + HexEdit->updateCursor(); + emit HexEdit->bufferChanged( ChangedRange.start(), ChangedRange.end() ); + } + } + } + } + } + else + KeyUsed = false; + } + } + else + KeyUsed = false; + + return KeyUsed ? true : KEditor::handleKeyPress(KeyEvent); +} + + +void KValueEditor::doValueEditAction( KValueEditAction Action, int Input ) +{ + // we are not yet in edit mode? + if( !InEditMode ) + { + int ValidIndex = BufferCursor->validIndex(); + // no valid cursor position? + if( ValidIndex == -1 || (!HexEdit->OverWrite && Input == -1) || BufferCursor->isBehind() ) + return; + + InEditMode = true; + EditModeByInsert = false; // default, to be overwritten if so + + // save old value + OldValue = EditValue = (unsigned char)HexEdit->DataBuffer->datum(ValidIndex); + } + + const KByteCodec *ByteCodec = ValueColumn->byteCodec(); + // + unsigned char NewValue = EditValue; + bool StayInEditMode = true; + bool MoveToNext = false; + + switch( Action ) + { + case ValueEdit: + NewValue = Input; + EditValue = NewValue^255; // force update + EditModeByInsert = true; + break; + case ValueBackspace: + if( NewValue > 0 ) + ByteCodec->removeLastDigit( &NewValue ); + break; + case EnterValue: + EditValue ^= 255; // force update + break; + case IncValue: + if( NewValue < 255 ) + ++NewValue; + break; + case DecValue: + if( NewValue > 0 ) + --NewValue; + break; + case ValueAppend: + if( ByteCodec->appendDigit(&NewValue,Input) ) + if( EditModeByInsert && NewValue >= ByteCodec->digitsFilledLimit() ) + { + StayInEditMode = false; + MoveToNext = true; + } + break; + case LeaveValue: + StayInEditMode = false; + MoveToNext = EditModeByInsert; + break; + case CancelValue: + NewValue = OldValue; + StayInEditMode = false; + break; + } + + bool Changed = (NewValue != EditValue); + int Index = BufferCursor->index(); + if( Changed ) + { + // sync value + EditValue = NewValue; + ByteCodec->encode( ByteBuffer, 0, EditValue ); + + HexEdit->DataBuffer->replace( Index, 1, (char*)&EditValue, 1 ); + } + + HexEdit->updateCursor(); + + if( !StayInEditMode ) + { + HexEdit->pauseCursor(); + InEditMode = false; + if( MoveToNext ) + BufferCursor->gotoNextByte(); + HexEdit->unpauseCursor(); + } + + if( Changed ) + if( Action != EnterValue ) emit HexEdit->bufferChanged( Index, Index ); +} diff --git a/khexedit/lib/controller/kvalueeditor.h b/khexedit/lib/controller/kvalueeditor.h new file mode 100644 index 0000000..496bcde --- /dev/null +++ b/khexedit/lib/controller/kvalueeditor.h @@ -0,0 +1,75 @@ +/*************************************************************************** + kvalueeditor.h - description + ------------------- + begin : Sa Dez 4 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KVALUEEDITOR_H +#define KHE_KVALUEEDITOR_H + + +// lib specific +#include "keditor.h" + +namespace KHE +{ + +class KValueColumn; + + +class KValueEditor: public KEditor +{ + protected: + enum KValueEditAction + { EnterValue, IncValue, DecValue, ValueAppend, ValueEdit, LeaveValue, CancelValue, ValueBackspace }; + + public: + KValueEditor( KValueColumn *VC, KBufferCursor *BC, KHexEdit *HE, KController *P ); + virtual ~KValueEditor(); + + public: // KEditor API + virtual bool handleKeyPress( QKeyEvent *KeyEvent ); + + public: + void reset(); + + public: + bool isInEditMode() const; + + protected: + /** executes keyboard Action \a Action. This is normally called by a key event handler. */ + void doValueEditAction( KValueEditAction Action, int Input = -1 ); + + public://protected: + KValueColumn *ValueColumn; + /** flag whether we are in editing mode */ + bool InEditMode:1; + /** flag whether byte edit mode was reached by inserting */ + bool EditModeByInsert:1; + /** */ + unsigned char EditValue; + /** stores the old byte value */ + unsigned char OldValue; + /** buffer with the */ + QString ByteBuffer; +}; + +inline KValueEditor::~KValueEditor() {} + +inline bool KValueEditor::isInEditMode() const { return InEditMode; } +inline void KValueEditor::reset() { InEditMode = false; } + +} + +#endif diff --git a/khexedit/lib/helper.h b/khexedit/lib/helper.h new file mode 100644 index 0000000..600ac5b --- /dev/null +++ b/khexedit/lib/helper.h @@ -0,0 +1,31 @@ +/*************************************************************************** + helper.h - description + ------------------- + begin : Fri Oct 03 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + +#ifndef KHEXEDIT_HELPER +#define KHEXEDIT_HELPER + +// qt specific +#include <qcolor.h> +// lib specific +#include <khechar.h> + +// temporary solution until syntax highlighting is implemented +static inline QColor colorForChar( const KHE::KHEChar Byte ) +{ + return Byte.isUndefined() ? Qt::yellow : Byte.isPunct() ? Qt::red : Byte.isPrint() ? Qt::black : Qt::blue; +} + +#endif diff --git a/khexedit/lib/kadds.h b/khexedit/lib/kadds.h new file mode 100644 index 0000000..77c86f5 --- /dev/null +++ b/khexedit/lib/kadds.h @@ -0,0 +1,36 @@ +/*************************************************************************** + kadds.h - description + ------------------- + begin : Die Mai 20 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KADDS_H +#define KHE_KADDS_H + +namespace KHE +{ +// some possibly usefull aditions to KDE + +// these are to emphasize that measuring unit is pixel and which direction +typedef int KPixelX; +typedef int KPixelY; + +class KSection; + +typedef KSection KPixelXs; +typedef KSection KPixelYs; + +} + +#endif diff --git a/khexedit/lib/kbigbuffer.cpp b/khexedit/lib/kbigbuffer.cpp new file mode 100644 index 0000000..8505ef7 --- /dev/null +++ b/khexedit/lib/kbigbuffer.cpp @@ -0,0 +1,216 @@ +/*************************************************************************** + kbigbuffer.cpp - description + ------------------- + begin : Mit Jun 02 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// c specific +#include <stdlib.h> +// lib specific +#include "kbigbuffer.h" + +using namespace KHE; + +KBigBuffer::KBigBuffer( int NP, int PS ) + : NoOfUsedPages( NP ), + NoOfFreePages( NP ), + PageSize( PS ), + FirstPage( -1 ), + LastPage( -1 ), + Size( 0 ) +{ + IsOpen = false; + +// if( !filename.empty() ) +// open(filename); +} + + +KBigBuffer::~KBigBuffer() +{ + if( File.isOpen() ) + close(); +} + + + +bool KBigBuffer::prepareRange( KSection /*Range*/ ) const +{ + return true; +} + +const char *KBigBuffer::dataSet( KSection /*Section*/ ) const +{ + return 0; +} + + +char KBigBuffer::datum( unsigned int DatumOffset ) const +{ +// std::cout << "reading datum " << DatumOffset << std::endl; + int OffsetInPage = DatumOffset - OffsetOfActualPage; + // there shouldn't be any need to check l + if( OffsetInPage >= 0 && OffsetInPage < (int)PageSize ) + return ActualPage[OffsetInPage]; + + // load the page + unsigned int PageIndex = DatumOffset / PageSize; + ensurePageLoaded( PageIndex ); + return ActualPage[DatumOffset-OffsetOfActualPage]; +} + + + + +int KBigBuffer::insert( int /*Pos*/, const char*, int /*Length*/ ) +{ + return 0; +} + +int KBigBuffer::remove( KSection /*Section*/ ) +{ + return 0; +} + +unsigned int KBigBuffer::replace( KSection /*Section*/, const char*, unsigned int /*Length*/ ) +{ + return 0; +} + +int KBigBuffer::fill( char /*FillChar*/, int /*Length*/, unsigned int /*Pos*/ ) +{ + return 0; +} + + +int KBigBuffer::move( int /*DestPos*/, KSection /*SourceSection*/ ) { return 0; } +//int KBigBuffer::find( const char*, int /*Length*/, int /*Pos*/ ) const { return 0; } +int KBigBuffer::find( const char*/*KeyData*/, int /*Length*/, KSection /*Section*/ ) const { return 0; } + +int KBigBuffer::rfind( const char*, int /*Length*/, int /*Pos*/ ) const { return 0; } + + + +bool KBigBuffer::open( const QString& FileName ) +{ + // clear old data + if( isOpen() && !close() ) // only occurs if close somehow fails. + return false; + + File.setName( FileName ); + if( !File.open(IO_ReadOnly|IO_Raw) ) + return false; + +// std::cout << "loading file " << FileName << std::endl; + + int FileSize = File.size(); + Size = FileSize; + + // calculate necessary number of pages + int NoOfPages = FileSize/PageSize + 1; + + // initialize Page pointers + Data.resize( NoOfPages ); + for( KPageOfChar::iterator D=Data.begin(); D!=Data.end(); ++D ) + *D = 0; + + FirstPage = LastPage = 0; + + return ensurePageLoaded( 0 ); +} + + +bool KBigBuffer::close() +{ + if( !isOpen() ) + return false; + + File.close(); + + if( File.status() == IO_UnspecifiedError ) + return false; + +// std::cout << "closing file " << std::endl; + + // free pages + for( KPageOfChar::iterator D=Data.begin(); D!=Data.end(); ++D ) + delete [] *D; + + FirstPage = LastPage = -1; + NoOfFreePages = NoOfUsedPages; + + return true; +} + + +bool KBigBuffer::ensurePageLoaded( unsigned int PageIndex ) const +{ + if( !isOpen() ) + return false; + // page loaded? + if( Data[PageIndex] != 0 ) + { + ActualPage = Data[PageIndex]; + OffsetOfActualPage = PageIndex * PageSize; + return true; + } + + // no page available? + if( NoOfFreePages < 1 ) + { + // free the page which is the furthest away from the page we are loading + if( abs(FirstPage-PageIndex) > abs(LastPage-PageIndex) ) + while( !freePage(FirstPage++) ); + else + while( !freePage(LastPage--) ); + } + +// std::cout << "loading page " << PageIndex << std::endl; + // create Page + Data[PageIndex] = new char[PageSize]; + --NoOfFreePages; + + // jump to position and read the page's data in + bool Success = File.at( (unsigned long)(PageIndex*PageSize) ); + if( Success ) + Success = File.readBlock( Data[PageIndex], PageSize ) > 0; + + if( Success ) + { + // correct bounds + if( (int)PageIndex < FirstPage ) + FirstPage = PageIndex; + + if( (int)PageIndex > LastPage ) + LastPage = PageIndex; + + ActualPage = Data[PageIndex]; + OffsetOfActualPage = PageIndex * PageSize; + } + + return Success; +} + + +bool KBigBuffer::freePage( unsigned int PageIndex ) const +{ + // check range and if is loaded at all + if( (unsigned int)PageIndex >= Data.size() || !Data[PageIndex] ) + return false; +// std::cout << "freeing page " << PageIndex << std::endl; + delete [] Data[PageIndex]; + Data[PageIndex] = 0; + ++NoOfFreePages; + return true; +} diff --git a/khexedit/lib/kbigbuffer.h b/khexedit/lib/kbigbuffer.h new file mode 100644 index 0000000..138e64b --- /dev/null +++ b/khexedit/lib/kbigbuffer.h @@ -0,0 +1,119 @@ +/*************************************************************************** + kbigbuffer.h - description + ------------------- + begin : Mit Jun 02 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBIGBUFFER_H +#define KHE_KBIGBUFFER_H + +// qt specific +#include <qvaluevector.h> +#include <qfile.h> +// lib specific +#include "kdatabuffer.h" +#include "khexedit_export.h" + +namespace KHE { + +/** base class for all Data buffers that are used to display + * TODO: think about a way to inform KHexEdit that there has been + * a change in the buffer outside. what kind of changes are possible? + *@author Friedrich W. H. Kossebau + */ + +class KHEXEDIT_EXPORT KBigBuffer : public KDataBuffer +{ + typedef QValueVector<char *> KPageOfChar; + + public: + /** default is only 50*4k = 200k memory image */ + KBigBuffer( int NP = 50, int PS = 4096 ); + virtual ~KBigBuffer(); + + public: // KDataBuffer API + virtual bool prepareRange( KSection Range ) const; + virtual const char *dataSet( KSection S ) const; + virtual char datum( unsigned int Offset ) const; + virtual int size() const; + virtual bool isReadOnly() const; + virtual bool isModified() const; + + virtual int insert( int Pos, const char*, int Length ); + virtual int remove( KSection S ); + virtual unsigned int replace( KSection S, const char*, unsigned int InputLength ); + virtual int move( int DestPos, KSection SourceSection ); + virtual int fill( char FillChar, int Length = -1, unsigned int Pos = 0 ); + virtual void setDatum( unsigned int Offset, const char Char ); + + virtual void setModified( bool M = true ); + + //virtual int find( const char*, int Length, int Pos = 0 ) const; + virtual int find( const char*KeyData, int Length, KSection Section ) const; + virtual int rfind( const char*, int Length, int Pos = -1 ) const; + +/* virtual int find( const QString &expr, bool cs, bool wo, bool forward = true, int *index = 0 ); */ + + public: + void setReadOnly( bool RO = true ); + bool isOpen() const; + bool open (const QString& filename ); + bool close(); + + protected: + bool ensurePageLoaded( unsigned int PageIndex ) const; + bool freePage( unsigned int PageIndex ) const; + + + protected: + /** */ + mutable QFile File; + /** */ + bool ReadOnly:1; + bool IsOpen:1; + bool AtEOF:1; + /** maximum number of pages which could be currently loaded */ + unsigned int NoOfUsedPages; + /** number of actually not used pages (in terms of NoOfUsedPages) */ + mutable int NoOfFreePages; + /** number of bytes in a page */ + unsigned int PageSize; + /** first currently loaded page */ + mutable int FirstPage; + /** last currently loaded page */ + mutable int LastPage; + /** */ + mutable KPageOfChar Data; + /** */ + unsigned int Size; + + /** current offset */ + mutable unsigned int OffsetOfActualPage; + /** points to the actual page */ + mutable char* ActualPage; +}; + +inline int KBigBuffer::size() const { return Size; } +inline bool KBigBuffer::isReadOnly() const { return ReadOnly; } +inline bool KBigBuffer::isModified() const { return false; } +inline void KBigBuffer::setReadOnly( bool RO ) { ReadOnly = RO; } +inline void KBigBuffer::setModified( bool ) {} + +inline void KBigBuffer::setDatum( unsigned int, const char ) {} + +inline bool KBigBuffer::isOpen() const { return File.isOpen(); } + +} + +#endif diff --git a/khexedit/lib/kbordercoltextexport.cpp b/khexedit/lib/kbordercoltextexport.cpp new file mode 100644 index 0000000..d46490f --- /dev/null +++ b/khexedit/lib/kbordercoltextexport.cpp @@ -0,0 +1,47 @@ +/*************************************************************************** + kbordercoltextexport.cpp - description + ------------------- + begin : Sam Aug 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qstring.h> +// lib specific +#include "kbordercoltextexport.h" + + +using namespace KHE; + +static const uint BorderColumnTEWidth = 3; + + +int KBorderColTextExport::charsPerLine() const +{ + return BorderColumnTEWidth; +} + +void KBorderColTextExport::printFirstLine( QString &T, int /*Line*/ ) const +{ + print( T ); +} + +void KBorderColTextExport::printNextLine( QString &T ) const +{ + print( T ); +} + +void KBorderColTextExport::print( QString &T ) const +{ + T.append( " | " ); +} diff --git a/khexedit/lib/kbordercoltextexport.h b/khexedit/lib/kbordercoltextexport.h new file mode 100644 index 0000000..4103f0b --- /dev/null +++ b/khexedit/lib/kbordercoltextexport.h @@ -0,0 +1,40 @@ +/*************************************************************************** + kbordercoltextexport.h - description + ------------------- + begin : Sam Aug 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBORDERCOLTEXTEXPORT_H +#define KHE_KBORDERCOLTEXTEXPORT_H + +#include "kcoltextexport.h" + +namespace KHE +{ + +class KBorderColTextExport : public KColTextExport +{ + public: // API + void printFirstLine( QString &T, int Line ) const; + void printNextLine( QString &T) const; + /** tells how much chars per line are needed */ + int charsPerLine() const ; + + protected: + void print( QString &T ) const; +}; + +} + +#endif diff --git a/khexedit/lib/kbordercolumn.cpp b/khexedit/lib/kbordercolumn.cpp new file mode 100644 index 0000000..c590246 --- /dev/null +++ b/khexedit/lib/kbordercolumn.cpp @@ -0,0 +1,82 @@ +/*************************************************************************** + kbordercolumn.cpp - description + ------------------- + begin : Mit Mai 21 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qpainter.h> +#include <qstyle.h> +// lib specific +#include "kcolumnsview.h" +#include "kbordercolumn.h" + + +using namespace KHE; + +static const KPixelX DefaultWidth = 9; +static const KPixelX LineX = DefaultWidth / 2; + + +KBorderColumn::KBorderColumn( KColumnsView *V, bool M ) + : KColumn( V ), + Middle( M ) +{ + setWidth( M?DefaultWidth:LineX-1 ); +} + +KBorderColumn::~KBorderColumn() +{ +} + + +void KBorderColumn::paintLine( QPainter *P ) +{ + if( LineHeight > 0 ) + { + KColumn::paintBlankLine( P ); + + if( Middle ) + { + int GridColor = View->style().styleHint( QStyle::SH_Table_GridLineColor, View ); + P->setPen( GridColor != -1 ? (QRgb)GridColor : View->colorGroup().mid() ); + P->drawLine( LineX, 0, LineX, LineHeight-1 ) ; + } + } +} + + +void KBorderColumn::paintFirstLine( QPainter *P, KPixelXs , int ) +{ + paintLine( P ); +} + + +void KBorderColumn::paintNextLine( QPainter *P ) +{ + paintLine( P ); +} + +void KBorderColumn::paintEmptyColumn( QPainter *P, KPixelXs Xs, KPixelYs Ys ) +{ + KColumn::paintEmptyColumn( P,Xs,Ys ); + + KPixelX LX = x() + LineX; + if( Middle && Xs.includes(LX) ) + { + int GridColor = View->style().styleHint( QStyle::SH_Table_GridLineColor, View ); + P->setPen( GridColor != -1 ? (QRgb)GridColor : View->colorGroup().mid() ); + P->drawLine( LX, Ys.start(), LX, Ys.end() ) ; + } +} diff --git a/khexedit/lib/kbordercolumn.h b/khexedit/lib/kbordercolumn.h new file mode 100644 index 0000000..0a72c05 --- /dev/null +++ b/khexedit/lib/kbordercolumn.h @@ -0,0 +1,52 @@ +/*************************************************************************** + kbordercolumn.h - description + ------------------- + begin : Mit Mai 21 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBORDERCOLUMN_H +#define KHE_KBORDERCOLUMN_H + +#include "kcolumn.h" + +namespace KHE +{ + +/** column that does nothing but draw a vertical line in the middle of the column + * + *@author Friedrich W. H. Kossebau + */ + +class KBorderColumn : public KColumn +{ + public: + KBorderColumn( KColumnsView *V, bool M ); + ~KBorderColumn(); + + public: // KColumn-API + virtual void paintFirstLine( QPainter *P, KPixelXs Xs, int FirstLine ); + virtual void paintNextLine( QPainter *P ); + virtual void paintEmptyColumn( QPainter *P, KPixelXs Xs, KPixelYs Ys ); + + protected: + virtual void paintLine( QPainter *P ); + + protected: + /** true if we are between two columns and should show a line */ + bool Middle; +}; + +} + +#endif diff --git a/khexedit/lib/kbuffercoltextexport.cpp b/khexedit/lib/kbuffercoltextexport.cpp new file mode 100644 index 0000000..a4ee91f --- /dev/null +++ b/khexedit/lib/kbuffercoltextexport.cpp @@ -0,0 +1,108 @@ +/*************************************************************************** + kbuffercoltextexport.cpp - description + ------------------- + begin : Sam Aug 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// c specific +#include <string.h> +// lib specific +#include "kbuffercolumn.h" +#include "kbufferlayout.h" +#include "kbuffercoltextexport.h" + + +using namespace KHE; + +static const int DefaultTEByteSpacingWidth = 1; +static const int TEGroupSpacingWidth = 3; + +QString KBufferColTextExport::whiteSpace( uint s ) +{ + return QString().fill( ' ', s ); +} + +KBufferColTextExport::KBufferColTextExport( const KBufferColumn* BufferColumn, const char *D, + KCoordRange CR, int ByteWidth ) + : Data( D ), + CoordRange( CR ) +{ + NoOfBytesPerLine = BufferColumn->layout()->noOfBytesPerLine(); + Pos = new int[NoOfBytesPerLine]; + + // TODO: remove this hack and make it more general + int ByteSpacingWidth = BufferColumn->byteSpacingWidth(); + if( ByteSpacingWidth > 0 ) + ByteSpacingWidth = DefaultTEByteSpacingWidth; + + int SpacingTrigger = BufferColumn->noOfGroupedBytes()-1; + if( SpacingTrigger < 0 ) + SpacingTrigger = NoOfBytesPerLine; // ensures to never trigger the group spacing + + int N = 0; + int p = 0; + int gs = 0; + int *P = Pos; + for( ; P<&Pos[NoOfBytesPerLine]; ++P, ++p, ++gs ) + { + *P = N; + N += ByteWidth; + + // is there a space behind the actual byte (if it is not the last)? + if( gs == SpacingTrigger ) + { + N += TEGroupSpacingWidth; + gs = -1; + } + else + N += ByteSpacingWidth; + } + N -= (gs==0)?TEGroupSpacingWidth:ByteSpacingWidth; + + NoOfCharsPerLine = N; +} + + +KBufferColTextExport::~KBufferColTextExport() +{ + delete [] Pos; +} + + +int KBufferColTextExport::charsPerLine() const +{ + return NoOfCharsPerLine; +} + + +void KBufferColTextExport::printFirstLine( QString &T, int Line ) const +{ + PrintLine = Line; + PrintData = Data; + print( T ); +} + + +void KBufferColTextExport::printNextLine( QString &T ) const +{ + print( T ); +} + + +void KBufferColTextExport::print( QString &T ) const +{ + T.append( whiteSpace(NoOfCharsPerLine) ); + ++PrintLine; +} + diff --git a/khexedit/lib/kbuffercoltextexport.h b/khexedit/lib/kbuffercoltextexport.h new file mode 100644 index 0000000..6cb161d --- /dev/null +++ b/khexedit/lib/kbuffercoltextexport.h @@ -0,0 +1,73 @@ +/*************************************************************************** + kbuffercoltextexport.h - description + ------------------- + begin : Sam Aug 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBUFFERCOLTEXTEXPORT_H +#define KHE_KBUFFERCOLTEXTEXPORT_H + +// qt specific +#include <qstring.h> +// lib specific +#include "kcoltextexport.h" +#include "kcoordrange.h" + + +namespace KHE +{ + +class KBufferColumn; + + +class KBufferColTextExport : public KColTextExport +{ + public: + KBufferColTextExport( const KBufferColumn* BF, const char *D, KCoordRange CR, int BytesWidth ); + virtual ~KBufferColTextExport(); + + public: // API + void printFirstLine( QString &T, int Line ) const; + void printNextLine( QString &T ) const; + /** tells how much chars per line are needed */ + int charsPerLine() const; + + + protected: // API to be reimplemented by subclasses + virtual void print( QString &T ) const; + + + protected: + static QString whiteSpace( uint s ); + + protected: + const char *Data; + KCoordRange CoordRange; + + int NoOfBytesPerLine; + + /** Line to print */ + mutable int PrintLine; + /** Data to print */ + mutable const char *PrintData; + + /** buffered value of how many chars a line needs */ + int NoOfCharsPerLine; + // positions where to paint the + int *Pos; +}; + +} + +#endif diff --git a/khexedit/lib/kbuffercolumn.cpp b/khexedit/lib/kbuffercolumn.cpp new file mode 100644 index 0000000..4291e00 --- /dev/null +++ b/khexedit/lib/kbuffercolumn.cpp @@ -0,0 +1,700 @@ +/*************************************************************************** + kbuffercolumn.cpp - description + ------------------- + begin : Mit Mai 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +//#include <kdebug.h> + +// qt specific +#include <qpainter.h> +// lib specific +#include "kcolumnsview.h" +#include "kbuffercursor.h" +#include "kbuffercolumn.h" +#include "kbufferlayout.h" +#include "kbufferranges.h" +#include "helper.h" +#include "kcharcodec.h" + +using namespace KHE; + +static const unsigned int StartsBefore = 1; +static const unsigned int EndsLater = 2; +static const char EmptyByte = ' '; + +static const KPixelX DefaultCursorWidth = 2; +static const KPixelX DefaultByteSpacingWidth = 3; +static const KPixelX DefaultGroupSpacingWidth = 9; +static const int DefaultNoOfGroupedBytes = 4; + +KBufferColumn::KBufferColumn( KColumnsView *CV, KDataBuffer *B, KBufferLayout *L, KBufferRanges *R ) + : KColumn( CV ), + Buffer( B ), + Layout( L ), + Ranges( R ), + DigitWidth( 0 ), + DigitBaseLine( 0 ), + VerticalGrid( false ), + ByteWidth( 0 ), + ByteSpacingWidth( DefaultByteSpacingWidth ), + GroupSpacingWidth( DefaultGroupSpacingWidth ), + NoOfGroupedBytes( DefaultNoOfGroupedBytes ), + PosX( 0L ), + PosRightX( 0L ), + LastPos( 0 ) +{ +} + + +KBufferColumn::~KBufferColumn() +{ + delete [] PosX; + delete [] PosRightX; +} + + + +void KBufferColumn::set( KDataBuffer *B ) +{ + Buffer= B; +} + + +void KBufferColumn::resetXBuffer() +{ + delete [] PosX; + delete [] PosRightX; + + LastPos = Layout->noOfBytesPerLine()-1; + PosX = new KPixelX[LastPos+1]; + PosRightX = new KPixelX[LastPos+1]; + + if( PosX ) + recalcX(); +} + + +void KBufferColumn::setMetrics( KPixelX DW, KPixelY DBL ) +{ + DigitBaseLine = DBL; + setDigitWidth( DW ); +} + + +bool KBufferColumn::setDigitWidth( KPixelX DW ) +{ + // no changes? + if( DigitWidth == DW ) + return false; + + DigitWidth = DW; + // recalculate depend sizes + recalcByteWidth(); + + if( PosX ) + recalcX(); + return true; +} + + +bool KBufferColumn::setSpacing( KPixelX BSW, int NoGB, KPixelX GSW ) +{ + // no changes? + if( ByteSpacingWidth == BSW && NoOfGroupedBytes == NoGB && GroupSpacingWidth == GSW ) + return false; + + ByteSpacingWidth = BSW; + NoOfGroupedBytes = NoGB; + GroupSpacingWidth = GSW; + + // recalculate depend sizes + recalcVerticalGridX(); + + if( PosX ) + recalcX(); + return true; +} + + +bool KBufferColumn::setByteSpacingWidth( KPixelX BSW ) +{ + // no changes? + if( ByteSpacingWidth == BSW ) + return false; + + ByteSpacingWidth = BSW; + + // recalculate depend sizes + recalcVerticalGridX(); + + if( PosX ) + recalcX(); + return true; +} + + +bool KBufferColumn::setNoOfGroupedBytes( int NoGB ) +{ + // no changes? + if( NoOfGroupedBytes == NoGB ) + return false; + + NoOfGroupedBytes = NoGB; + + if( PosX ) + recalcX(); + return true; +} + + +bool KBufferColumn::setGroupSpacingWidth( KPixelX GSW ) +{ + // no changes? + if( GroupSpacingWidth == GSW ) + return false; + + GroupSpacingWidth = GSW; + + // recalculate depend sizes + recalcVerticalGridX(); + + if( PosX ) + recalcX(); + return true; +} + + +void KBufferColumn::recalcByteWidth() +{ + ByteWidth = DigitWidth; + recalcVerticalGridX(); +} + + +void KBufferColumn::recalcVerticalGridX() +{ + VerticalGridX = ByteWidth-1 + GroupSpacingWidth/2; +} + + +void KBufferColumn::recalcX() +{ + SpacingTrigger = noOfGroupedBytes() > 0 ? noOfGroupedBytes()-1 : LastPos+1; // last ensures to never trigger the spacing + + KPixelX NewWidth = 0; + int p = 0; + int gs = 0; + KPixelX *PX = PosX; + KPixelX *PRX = PosRightX; + for( ; PX<&PosX[LastPos+1]; ++PX, ++PRX, ++p, ++gs ) + { + *PX = NewWidth; + NewWidth += ByteWidth; + *PRX = NewWidth-1; + + // is there a space behind the actual byte (if it is not the last)? + if( gs == SpacingTrigger ) + { + NewWidth += GroupSpacingWidth; + gs = -1; + } + else + NewWidth += ByteSpacingWidth; + } + setWidth( PosRightX[LastPos]+1 ); +} + + +// TODO: why are inlined functions not available as symbols when defined before their use +//TODO: works not precisly for the byte rects but includes spacing and left and right +/*inline*/ int KBufferColumn::posOfX( KPixelX PX ) const +{ + if( !PosX ) + return NoByteFound; + + // translate + PX -= x(); + // search backwards for the first byte that is equalleft to x + for( int p=LastPos; p>=0; --p ) + if( PosX[p] <= PX ) + return p; + + return 0; //NoByteFound; +} + + +int KBufferColumn::magPosOfX( KPixelX PX ) const +{ + if( !PosX ) + return NoByteFound; + + // translate + PX -= x(); + // search backwards for the first byte that is equalleft to x + for( int p=LastPos; p>=0; --p ) + if( PosX[p] <= PX ) + { + // are we close to the right? + if( PosRightX[p]-PX < DigitWidth/2 ) // TODO: perhaps cache also the middle xpos's + ++p; + return p; + } + + return 0; //NoByteFound; +} + + +KSection KBufferColumn::posOfX( KPixelX PX, KPixelX PW ) const +{ + if( !PosX ) + return KSection(); + + // translate + PX -= x(); + int PRX = PX + PW - 1; + + KSection P; + // search backwards for the first byte that is equalleft to x + for( int p=LastPos; p>=0; --p ) + if( PosX[p] <= PRX ) + { + P.setEnd( p ); + for( ; p>=0; --p ) + if( PosX[p] <= PX ) + { + P.setStart( p ); + break; + } + break; + } + + return P; +} + + +KPixelX KBufferColumn::xOfPos( int Pos ) const { return x() + (PosX?PosX[Pos]:0); } +KPixelX KBufferColumn::rightXOfPos( int Pos ) const { return x() + (PosRightX?PosRightX[Pos]:0); } + + +int KBufferColumn::posOfRelX( KPixelX PX ) const +{ + if( !PosX ) + return NoByteFound; + + // search backwards for the first byte that is equalleft to x + for( int p=LastPos; p>=0; --p ) + if( PosX[p] <= PX ) + return p; + + return 0; //NoByteFound; +} + + +KSection KBufferColumn::posOfRelX( KPixelX PX, KPixelX PW ) const +{ + if( !PosX ) + return KSection(); + + int PRX = PX + PW - 1; + + KSection P; + // search backwards for the first byte that is equalleft to x + for( int p=LastPos; p>=0; --p ) + if( PosX[p] <= PRX ) + { + P.setEnd( p ); + for( ; p>=0; --p ) + if( PosX[p] <= PX ) + { + P.setStart( p ); + break; + } + break; + } + + return P; +} + + +KPixelX KBufferColumn::relXOfPos( int Pos ) const { return PosX ? PosX[Pos] : 0; } +KPixelX KBufferColumn::relRightXOfPos( int Pos ) const { return PosRightX ? PosRightX[Pos] : 0; } + + +KPixelXs KBufferColumn::wideXPixelsOfPos( KSection Positions ) const +{ + return KPixelXs( Positions.start()>0?rightXOfPos(Positions.start()-1)+1:xOfPos(Positions.start()), + Positions.end()<LastPos?xOfPos(Positions.end()+1)-1:rightXOfPos(Positions.end()) ); +} + + +KPixelXs KBufferColumn::relWideXPixelsOfPos( KSection Positions ) const +{ + return KPixelXs( Positions.start()>0?relRightXOfPos(Positions.start()-1)+1:relXOfPos(Positions.start()), + Positions.end()<LastPos?relXOfPos(Positions.end()+1)-1:relRightXOfPos(Positions.end()) ); +} + + +void KBufferColumn::preparePainting( KPixelXs Xs ) +{ + Xs.restrictTo( XSpan ); + // translate + Xs.moveBy( -x() ); + + + // store the values + PaintX = Xs.start(); + PaintW = Xs.width(); + + // get line positions to paint + PaintPositions = posOfRelX( PaintX, PaintW ); +} + + +void KBufferColumn::paintFirstLine( QPainter *P, KPixelXs Xs, int FirstLine ) +{ + preparePainting( Xs ); + + PaintLine = FirstLine; + +// kdDebug(1501) << "paintFirstLine:"<<cx<<","<<cw<<"|" <<PaintX<<","<<PaintW << ")\n"; + +// paintPositions( P, PaintLine++, PaintPositions ); + paintLine( P, PaintLine++ ); +} + + +void KBufferColumn::paintNextLine( QPainter *P ) +{ +// paintPositions( P, PaintLine++, PaintPositions ); + paintLine( P, PaintLine++ ); +} + + +void KBufferColumn::paintLine( QPainter *P, int Line ) // TODO: could be removed??? +{ +// kdDebug(1501) << "paintLine line: "<<Line<<" Start: "<<PaintPositions.start()<<" End: "<<PaintPositions.end() << "\n"; + // no bytes to paint? +// if( !Layout->hasContent(Line) ) +// return; + + paintPositions( P, Line, PaintPositions ); +} + + +void KBufferColumn::paintPositions( QPainter *P, int Line, KSection Pos ) +{ + const QColorGroup &CG = View->colorGroup(); + + // clear background + unsigned int BlankFlag = (Pos.start()!=0?StartsBefore:0) | (Pos.end()!=LastPos?EndsLater:0); + paintRange( P, CG.base(), Pos, BlankFlag ); + + // Go through the lines TODO: handle first and last line more effeciently + // check for leading and trailing spaces + KSection Positions( Layout->firstPos(KBufferCoord( Pos.start(), Line )), + Layout->lastPos( KBufferCoord( Pos.end(), Line )) ); + + // no bytes to paint? + if( !Layout->hasContent(Line) ) + return; + + // check for leading and trailing spaces + KSection Indizes( Layout->indexAtCoord(KBufferCoord( Positions.start(), Line )), Positions.width(), false ); + + unsigned int SelectionFlag; + unsigned int MarkingFlag; + KSection Selection; + KSection Marking; + bool HasMarking = Ranges->hasMarking(); + bool HasSelection = Ranges->hasSelection(); + + while( Positions.isValid() ) + { + KSection PositionsPart( Positions ); // set of positions to paint next + KSection IndizesPart( Indizes ); // set of indizes to paint next + // falls Marking nicht mehr gebuffert und noch zu erwarten + if( HasMarking && Marking.endsBefore(IndizesPart.start()) ) + { + // erhebe nächste Markierung im Bereich + HasMarking = isMarked( IndizesPart, &Marking, &MarkingFlag ); + } + // falls Selection nicht mehr gebuffert und noch zu erwarten + if( HasSelection && Selection.endsBefore(IndizesPart.start()) ) + { + // erhebe nächste Selection im Bereich + HasSelection = isSelected( IndizesPart, &Selection, &SelectionFlag ); + } + + if( Marking.start() == IndizesPart.start() ) + { + IndizesPart.setEnd( Marking.end() ); + PositionsPart.setEndByWidth( Marking.width() ); + if( PositionsPart.end() == Layout->lastPos(Line) ) MarkingFlag &= ~EndsLater; + if( PositionsPart.start() == Layout->firstPos(Line)) MarkingFlag &= ~StartsBefore; + paintMarking( P, PositionsPart, IndizesPart.start(), MarkingFlag ); + + } + else if( Selection.includes(IndizesPart.start()) ) + { + if( Selection.startsBehind(IndizesPart.start()) ) + SelectionFlag |= StartsBefore; + bool MarkingBeforeEnd = HasMarking && Marking.start() <= Selection.end(); + + IndizesPart.setEnd( MarkingBeforeEnd ? Marking.start()-1 : Selection.end() ); + PositionsPart.setEndByWidth( IndizesPart.width() ); + + if( MarkingBeforeEnd ) + SelectionFlag |= EndsLater; + if( PositionsPart.end() == Layout->lastPos(Line) ) SelectionFlag &= ~EndsLater; + if( PositionsPart.start() == Layout->firstPos(Line) ) SelectionFlag &= ~StartsBefore; + + paintSelection( P, PositionsPart, IndizesPart.start(), SelectionFlag ); + } + else + { + // calc end of plain text + if( HasMarking ) + IndizesPart.setEnd( Marking.start()-1 ); + if( HasSelection ) + IndizesPart.restrictEndTo( Selection.start()-1 ); + + PositionsPart.setEndByWidth( IndizesPart.width() ); + paintPlain( P, PositionsPart, IndizesPart.start() ); + } + Indizes.setStartBehind( IndizesPart ); + Positions.setStartBehind( PositionsPart ); + } + // we don't paint grids as default, perhaps we never will though it works + // paintGrid( P, Positions ); // TODO: get some unmodified Positions (see three lines before) +} + + +void KBufferColumn::paintPlain( QPainter *P, KSection Positions, int Index ) +{ + // paint all the bytes affected + for( int p=Positions.start(); p<=Positions.end(); ++p,++Index ) + { + KPixelX x = relXOfPos( p ); + + // draw the byte + P->translate( x, 0 ); + char Byte = Buffer->datum( Index ); + KHEChar B = Codec->decode( Byte ); + drawByte( P, Byte, B, colorForChar(B) ); + + P->translate( -x, 0 ); + } +} + + +void KBufferColumn::paintSelection( QPainter *P, KSection Positions, int Index, int Flag ) +{ + const QColorGroup &CG = View->colorGroup(); + + paintRange( P, CG.highlight(), Positions, Flag ); + + const QColor &HTC = CG.highlightedText(); + // paint all the bytes affected + for( int p=Positions.start(); p<=Positions.end(); ++p,++Index ) + { + KPixelX x = relXOfPos( p ); + + // draw the byte + P->translate( x, 0 ); + char Byte = Buffer->datum( Index ); + KHEChar B = Codec->decode( Byte ); + drawByte( P, Byte, B, HTC ); + + P->translate( -x, 0 ); + } +} + + +void KBufferColumn::paintMarking( QPainter *P, KSection Positions, int Index, int Flag ) +{ + const QColorGroup &CG = View->colorGroup(); + + paintRange( P, CG.text(), Positions, Flag ); + + const QColor &BC = CG.base(); + // paint all the bytes affected + for( int p=Positions.start(); p<=Positions.end(); ++p,++Index ) + { + KPixelX x = relXOfPos( p ); + + // draw the byte + P->translate( x, 0 ); + char Byte = Buffer->datum( Index ); + KHEChar B = Codec->decode( Byte ); + drawByte( P, Byte, B, BC ); + + P->translate( -x, 0 ); + } +} + + +// TODO: smarter calculation +void KBufferColumn::paintGrid( QPainter *P, KSection Range ) +{ + int st = 0; // counter for spacing triggering + P->setPen( Qt::black ); + // paint all the bytes affected + for( int p=Range.start(); p<=Range.end(); ++p,++st ) + { + KPixelX x = relXOfPos( p ); + + // draw the byte + P->translate( x, 0 ); + + // spacing behind byte and vertical grid enabled? + if( st == SpacingTrigger && p != LastPos ) + P->drawLine( VerticalGridX, 0, VerticalGridX, LineHeight-1 ) ; + + P->translate( -x, 0 ); + } +} + + +void KBufferColumn::paintRange( QPainter *P, const QColor &Color, KSection Positions, int Flag ) +{ + KPixelX RangeX = Flag & StartsBefore ? relRightXOfPos( Positions.start()-1 ) + 1 : relXOfPos( Positions.start() ); + KPixelX RangeW = (Flag & EndsLater ? relXOfPos( Positions.end()+1 ): relRightXOfPos( Positions.end() ) + 1) - RangeX; + + P->fillRect( RangeX,0,RangeW,LineHeight, QBrush(Color,Qt::SolidPattern) ); +} + + +void KBufferColumn::paintByte( QPainter *P, int Index ) +{ + char Byte = ( Index > -1 ) ? Buffer->datum( Index ) : EmptyByte; + KHEChar B = Codec->decode( Byte ); + + const QColorGroup &CG = View->colorGroup(); + QColor Color = CG.text(); + QBrush Brush( CG.base(), Qt::SolidPattern ); + + if( Index > -1 ) + { + if( Ranges->markingIncludes(Index) ) + { + Brush.setColor( CG.text() ); + Color = CG.base(); + } + else if( Ranges->selectionIncludes(Index) ) + { + Brush.setColor( CG.highlight() ); + Color = CG.highlightedText(); + } + else + { + Brush.setColor( CG.base() ); + Color = colorForChar( B ); + } + } + + P->fillRect( 0,0,ByteWidth,LineHeight, Brush ); + + if( Index > -1 ) + drawByte( P, Byte, B, Color ); +} + + +void KBufferColumn::paintFramedByte( QPainter *P, int Index, KFrameStyle FrameStyle ) +{ + paintByte( P, Index ); + char Byte = ( Index > -1 ) ? Buffer->datum( Index ) : EmptyByte; + KHEChar B = Codec->decode( Byte ); + + P->setPen( colorForChar(B) ); + if( FrameStyle == Frame ) + P->drawRect( 0, 0, ByteWidth, LineHeight ); + else if( FrameStyle == Left ) + P->drawLine( 0, 0, 0, LineHeight-1 ); + else + P->drawLine( ByteWidth-1,0,ByteWidth-1,LineHeight-1 ); +} + + +void KBufferColumn::paintCursor( QPainter *P, int Index ) +{ + char Byte = ( Index > -1 ) ? Buffer->datum( Index ) : EmptyByte; + KHEChar B = Codec->decode( Byte ); + P->fillRect( 0, 0, ByteWidth, LineHeight, QBrush(colorForChar(B),Qt::SolidPattern) ); +} + + +void KBufferColumn::drawByte( QPainter *P, char /*Byte*/, KHEChar B, const QColor &Color ) const +{ + P->setPen( Color ); + P->drawText( 0, DigitBaseLine, B ); +} + + +bool KBufferColumn::isSelected( KSection Range, KSection *Selection, unsigned int *Flag ) const +{ + KSection S; + unsigned int F = 0; + const KSection *OS = Ranges->firstOverlappingSelection( Range ); + if( !OS ) + return false; + S = *OS; + + // does selection start before asked range? + if( Range.start() > S.start() ) + { + S.setStart( Range.start() ); + F |= StartsBefore; + } + + // does selection go on behind asked range? + if( Range.end() < S.end() ) + { + S.setEnd( Range.end() ); + F |= EndsLater; + } + + *Selection = S; + *Flag = F; + return true; +} + + +bool KBufferColumn::isMarked( KSection Range, KSection *Marking, unsigned int *Flag ) const +{ + KSection M; + unsigned int F = 0; + const KSection *OM = Ranges->overlappingMarking( Range ); + if( !OM ) + return false; + M = *OM; + + // does selection start before asked range? + if( Range.start() > M.start() ) + { + M.setStart( Range.start() ); + F |= StartsBefore; + } + + // does selection go on behind asked range? + if( Range.end() < M.end() ) + { + M.setEnd( Range.end() ); + F |= EndsLater; + } + + *Marking = M; + *Flag = F; + return true; +} diff --git a/khexedit/lib/kbuffercolumn.h b/khexedit/lib/kbuffercolumn.h new file mode 100644 index 0000000..76ed8bc --- /dev/null +++ b/khexedit/lib/kbuffercolumn.h @@ -0,0 +1,253 @@ +/*************************************************************************** + kbuffercolumn.h - description + ------------------- + begin : Mit Mai 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBUFFERCOLUMN_H +#define KHE_KBUFFERCOLUMN_H + +// lib specific +#include "khe.h" +#include "kdatabuffer.h" +#include "khechar.h" +#include "kcolumn.h" +#include "kbufferlayout.h" +#include "ksection.h" + +class QPainter; +class QColor; + +namespace KHE +{ + +// class KHexEdit; +class KBufferRanges; +class KCharCodec; + +const int NoByteFound = -1; + +/** base class of all buffer column displayers + * holds all information about the vertical layout of a buffer column + * knows how to paint the data and the editing things (focus, cursor, selection) + * but does not offer + * + *@author Friedrich W. H. Kossebauint KBufferColumn::posOfX( KPixelX PX, bool *ToTheRightFlag ) const + */ +class KBufferColumn : public KColumn +{ + public: + enum KFrameStyle { Frame, Left, Right }; + public: + KBufferColumn( KColumnsView/*KHexEdit*/ *HE, KDataBuffer *B, KBufferLayout *L, KBufferRanges *R ); + virtual ~KBufferColumn(); + + + public: // KColumn-API + virtual void paintFirstLine( QPainter *P, KPixelXs Xs, int FirstLine ); + virtual void paintNextLine( QPainter *P ); + + public: + void preparePainting( KPixelXs Xs ); + + public: + void paintLine( QPainter *P, int Line ); + void paintPositions( QPainter *P, int Line, KSection Positions ); + /** paints a cursor based on the type of the byte. + * @param Index Index of the byte to paint the cursor for. If -1 a space is used as char. + */ + void paintCursor( QPainter *P, int Index ); + /** paints the byte with background. + * @param Index Index of the byte to paint. If -1 only the background is painted. + */ + void paintByte( QPainter *P, int Index ); + /** paints the byte with background and a frame around. + * @param Index Index of the byte to paint the frame for. If -1 a space is used as char. + * @param Style the style of the framing + */ + void paintFramedByte( QPainter *P, int Index, KFrameStyle Style ); + + + public: // modification access + /** sets the spacing in the hex column + * @param ByteSpacingW spacing between the bytes in pixels + * @param NewNoOfGroupedBytes numbers of grouped bytes, 0 means no grouping + * @param GroupSpacingW spacing between the groups in pixels + * returns true if there was a change + */ + bool setSpacing( KPixelX ByteSpacingW, int NewNoOfGroupedBytes = 0, KPixelX GroupSpacingW = 0 ); + /** sets the spacing between the bytes in the hex column + * @param ByteSpacingW spacing between the bytes in pixels + * returns true if there was a change + */ + bool setByteSpacingWidth( KPixelX ByteSpacingW ); + /** sets the number of grouped bytes in the hex column + * @param NewNoOfGroupedBytes numbers of grouped bytes, 0 means no grouping + * returns true if there was a change + */ + bool setNoOfGroupedBytes( int NewNoOfGroupedBytes ); + /** sets the spacing between the groups of bytes in the hex column + * @param GroupSpacingW spacing between the groups in pixels + * returns true if there was a change + */ + bool setGroupSpacingWidth( KPixelX GroupSpacingW ); + /** sets width of digits and recalculates depend sizes + * returns true if there was a change + */ + bool setDigitWidth( KPixelX DW ); + /** sets the metrics of the used font + * @param NewDigitWidth the new width of a digit + * @param NewDigitBaseLine the new baseline of the digits + */ + void setMetrics( KPixelX NewDigitWidth, KPixelY NewDigitBaseLine ); + /** */ + void set( KDataBuffer *B ); + /** creates new buffer for x-values; to be called on any change of NoOfBytesPerLine or metrics */ + void resetXBuffer(); + /** sets the codec to be used by the char column. */ + void setCodec( KCharCodec *C ); + + public: // functional logic + /** returns byte positions covered by pixels with absolute x-coord x */ + KSection posOfX( KPixelX x, KPixelX w ) const; + /** returns byte pos at pixel with absolute x-coord x */ + int posOfX( KPixelX x ) const; + /** returns byte pos at pixel with absolute x-coord x, and sets the flag to true if we are closer to the right */ + int magPosOfX( KPixelX PX ) const; + /** returns absolute x-coord of byte at position Pos */ + KPixelX xOfPos( int Pos ) const; + /** returns right absolute x-coord of byte at position Pos */ + KPixelX rightXOfPos( int Pos ) const; + /** returns byte pos at pixel with relative x-coord x */ + int posOfRelX( KPixelX x ) const; + /** returns byte positions covered by pixels with relative x-coord x */ + KSection posOfRelX( KPixelX x, KPixelX w ) const; + /** returns relative x-coord of byte at position Pos */ + KPixelX relXOfPos( int Pos ) const; + /** returns right relative x-coord of byte at position Pos */ + KPixelX relRightXOfPos( int Pos ) const; + /** returns the positions that overlap with the absolute x-coords */ + KSection visiblePositions( KPixelX x, KPixelX w ) const; + /** returns the */ + KPixelXs wideXPixelsOfPos( KSection Positions ) const; + /** */ + KPixelXs relWideXPixelsOfPos( KSection Positions ) const; + + public: // value access + KPixelX byteWidth() const; + KPixelX digitWidth() const; + KPixelX groupSpacingWidth() const; + KPixelX byteSpacingWidth() const; + int noOfGroupedBytes() const; + + int firstPos() const; + int lastPos() const; + KSection visiblePositions() const; + const KBufferLayout *layout() const; + KCharCodec* codec() const; + + protected: + /** */ + void recalcX(); + void recalcVerticalGridX(); + + + protected: // API to be refined + /** default implementation simply prints the byte as ASCII */ + virtual void drawByte( QPainter *P, char Byte, KHEChar B, const QColor &Color ) const; + /** default implementation sets byte width to one digit width */ + virtual void recalcByteWidth(); + + + protected: + void paintGrid( QPainter *P, KSection Range ); + void paintPlain( QPainter *P, KSection Positions, int Index ); + void paintSelection( QPainter *P, KSection Positions, int Index, int Flag ); + void paintMarking( QPainter *P, KSection Positions, int Index, int Flag ); + void paintRange( QPainter *P, const QColor &Color, KSection Positions, int Flag ); + + bool isSelected( KSection Range, KSection *Selection, unsigned int *Flag ) const; + bool isMarked( KSection Range, KSection *Marking, unsigned int *Flag ) const; + + + protected: + /** pointer to the buffer */ + KDataBuffer *Buffer; + /** pointer to the layout */ + const KBufferLayout *Layout; + /** pointer to the ranges */ + KBufferRanges *Ranges; + /** */ + KCharCodec *Codec; + + /** */ + KPixelX DigitWidth; + /** */ + KPixelY DigitBaseLine; + /** */ + KPixelX VerticalGridX; + /** */ + bool VerticalGrid; + + protected: // individual data + /** total width of byte display in pixel */ + KPixelX ByteWidth; + /** width of inserting cursor in pixel */ + KPixelX CursorWidth; + /** size of the line margin */ + KPixelX ByteSpacingWidth; + /** width of spacing in pixel */ + KPixelX GroupSpacingWidth; + + /** number of grouped bytes */ + int NoOfGroupedBytes; + + /** pointer to array with buffered positions (relative to column position) + * a spacing gets assigned to the left byte -> ...c|c|c |c|c... + */ + KPixelX *PosX; + KPixelX *PosRightX; + /** index of right position */ + int LastPos; + + + protected: // buffering drawing data + KSection PaintPositions; + int PaintLine; + KPixelX PaintX; + KPixelX PaintW; + int SpacingTrigger; +}; + + +inline KPixelX KBufferColumn::byteWidth() const { return ByteWidth; } +inline KPixelX KBufferColumn::digitWidth() const { return DigitWidth; } +inline KPixelX KBufferColumn::byteSpacingWidth() const { return ByteSpacingWidth; } +inline KPixelX KBufferColumn::groupSpacingWidth() const { return GroupSpacingWidth; } + +inline int KBufferColumn::noOfGroupedBytes() const { return NoOfGroupedBytes; } + +inline int KBufferColumn::firstPos() const { return PaintPositions.start(); } +inline int KBufferColumn::lastPos() const { return PaintPositions.end(); } +inline KSection KBufferColumn::visiblePositions() const { return PaintPositions; } + +inline const KBufferLayout *KBufferColumn::layout() const { return Layout; } + + +inline void KBufferColumn::setCodec( KCharCodec *C ) { Codec = C; } +inline KCharCodec* KBufferColumn::codec() const { return Codec; } + +} + +#endif diff --git a/khexedit/lib/kbuffercoord.h b/khexedit/lib/kbuffercoord.h new file mode 100644 index 0000000..997551a --- /dev/null +++ b/khexedit/lib/kbuffercoord.h @@ -0,0 +1,293 @@ +/*************************************************************************** + kbuffercoord.h - description + ------------------- + begin : Don Mai 29 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBUFFERCOORD_H +#define KHE_KBUFFERCOORD_H + + +namespace KHE +{ + +/** + * a class which represents a coord in a 2-dim. system + * + * It consists of a line number and a position in the line. + * The coord starts at (0,0). Line numbers increase downwards, positions to the right. + * With any of both at a negative number the coord is invalid. + * TODO: change as much as possible params to unsigned integer + * + * @author Friedrich W. H. Kossebau + */ +class KBufferCoord +{ + public: + /** creates a coord with 0,0 */ + KBufferCoord(); + KBufferCoord( int P, int L ); + KBufferCoord( int Index, int LineWidth, bool /*dummy*/ ); + KBufferCoord( const KBufferCoord &C ); + KBufferCoord &operator=( const KBufferCoord &c ); + ~KBufferCoord(); + + + public: // logic + bool operator==( const KBufferCoord &c ) const; + bool operator!=( const KBufferCoord &c ) const; + bool operator<( const KBufferCoord &c ) const; + bool operator<=( const KBufferCoord &c ) const; + bool operator>( const KBufferCoord &c ) const; + bool operator>=( const KBufferCoord &c ) const; + + /** tests if the coord is prior in the same line than the given coord. + * If at least one of both is invalid the result is undefined. + * @return true if the pos is left to the pos of C and both are in the same line, otherwise false. + */ + bool isPriorInLineThan( const KBufferCoord &C ) const; + /** tests if the coord is later in the same line than the given coord. + * If at least one of both is invalid the result is undefined. + * @return true if the pos is right to the pos of C and both are in the same line, otherwise false + */ + bool isLaterInLineThan( const KBufferCoord &C ) const; + /** @return true if the line is below L, otherwise false */ + bool isBelow( int L ) const; + /** @return true if the line is above L, otherwise false */ + bool isAbove( int L ) const; + /** @return true if the coord is at (0,0) */ + bool isAtStart() const; + /** @return true if the pos is greater than 0, otherwise false */ + bool isBehindLineStart() const; + /** @return true if the pos is smaller than MaxPos, otherwise false */ + bool isBeforeLineEnd( int MaxPos ) const; + + /** calculates the index the coord is at with a given line width + * If the coord is invalid the result is undefined. + * @param LineWidth given width of line + * @return index the coord is at + */ + int indexByLineWidth( int LineWidth ) const; + + public: + /** set the coord by calculating it for an index with a given line width + * @param Index index in the buffer + * @param LineWidth given line width + */ + void setByIndexNWidth( int Index, int LineWidth ); + /** sets both position and line */ + void set( int P, int L ); + /** sets the position */ + void setPos( int P ); + /** sets the line */ + void setLine( int L ); + + /** moves the coord one position to the left. If the coord is invalid the result is undefined. */ + void goLeft(); + /** moves the coord a given number of positions to the left. + * If the coord is invalid the result is undefined or the position smaller then the given number + * the behaviour is undefined. + * @param P number of positions + */ + void goLeft( unsigned int P ); + /** moves the coord one position to the left, or if the position is already at the line start + * to the given position in the previous line. If the coord is invalid the result is undefined. + * @param MaxPos maximal allowed position + */ + void goCLeft( int MaxPos ); + /** moves the coord one position to the right. If the coord is invalid the result is undefined. */ + void goRight(); + /** moves the coord a given number of positions to the right. If the coord is invalid the result is undefined. + * @param P number of positions + */ + void goRight( unsigned int P ); + /** moves the coord one position to the right, or if the position has already reached or passed MaxPos + * to the first position in the next line. If the coord is invalid the result is undefined. + * @param MaxPos maximal allowed position + */ + void goCRight( int MaxPos ); + /** sets coord to (0,0) */ + void gotoStart(); + void gotoEndOfPreviousLine( int LastPos ); + /** sets the coord to the start of the next line. + * If the coord is invalid the behaviour is undefined. + */ + void gotoStartOfNextLine(); + /** sets the position to the start of the line or + * if the line is the same as that of the given coord to the position of it. + * If one or more of the coords is invalid the behaviour is undefined. + * @param C a possible line start coord + */ + void goLineStart( const KBufferCoord &C ); + /** sets the position to the given pos or + * if the line is the same as that of the given coord to the position of that. + * If one or more of the coords is invalid the behaviour is undefined. + * @param L last position in normal line + * @param C a possible line end coord + */ + void goLineEnd( int L, const KBufferCoord &C ); + /** moves the coord 1 lines upwards. There is no check whether the first line is overstepped. */ + void goUp(); + /** moves the coord L lines downwards. */ + void goDown(); + /** moves the coord L lines upwards. There is no check whether the first line is overstepped. + * @param L number of lines + */ + void goUp( unsigned int L ); + /** moves the coord L lines downwards. + * @param L number of lines + */ + void goDown( unsigned int L ); + + public: // state value access + /** @return the pos in the line */ + int pos() const; + /** @return the line number */ + int line() const; + /** @return true if the coord is valid */ + bool isValid() const; + + private: // member variables + /** Position in Line */ + int Pos; + /** Line */ + int Line; +}; + + +inline KBufferCoord::KBufferCoord() : Pos( 0 ), Line( 0 ) {} +inline KBufferCoord::KBufferCoord( int P, int L ) : Pos( P ), Line( L ) {} +inline KBufferCoord::KBufferCoord( int Index, int LineWidth, bool ) +{ + Line = Index / LineWidth; + Pos = Index - Line*LineWidth; +} + +inline KBufferCoord::KBufferCoord( const KBufferCoord &C ) : Pos( C.Pos ), Line( C.Line ) {} +inline KBufferCoord &KBufferCoord::operator=( const KBufferCoord &C ) { Pos = C.Pos; Line = C.Line; return *this; } +inline KBufferCoord::~KBufferCoord() {} + +inline bool KBufferCoord::operator==( const KBufferCoord &C ) const { return Pos == C.Pos && Line == C.Line; } +inline bool KBufferCoord::operator!=( const KBufferCoord &C ) const { return !(*this == C); } + +inline bool KBufferCoord::operator<( const KBufferCoord &C ) const +{ return Line < C.Line || (Line == C.Line && Pos<C.Pos); } +inline bool KBufferCoord::operator<=( const KBufferCoord &C ) const +{ return Line < C.Line || (Line == C.Line && Pos<=C.Pos); } +inline bool KBufferCoord::operator>( const KBufferCoord &C ) const +{ return Line > C.Line || (Line == C.Line && Pos>C.Pos); } +inline bool KBufferCoord::operator>=( const KBufferCoord &C ) const +{ return Line > C.Line || (Line == C.Line && Pos>=C.Pos); } + +inline int KBufferCoord::pos() const { return Pos; } +inline int KBufferCoord::line() const { return Line; } +inline bool KBufferCoord::isValid() const { return Line >= 0 && Pos >= 0; } + +inline void KBufferCoord::setByIndexNWidth( int Index, int LineWidth ) +{ + Line = Index / LineWidth; + Pos = Index - Line*LineWidth; +} + +inline void KBufferCoord::set( int P, int L ) +{ + Pos = P; + Line = L; +} +inline void KBufferCoord::setPos( int P ) { Pos = P; } +inline void KBufferCoord::setLine( int L ) { Line = L; } + +inline void KBufferCoord::goCRight( int MaxPos ) +{ + if( isBeforeLineEnd(MaxPos) ) + goRight(); + else + gotoStartOfNextLine(); +} +inline void KBufferCoord::goCLeft( int MaxPos ) +{ + if( isBehindLineStart() ) + goLeft(); + else + gotoEndOfPreviousLine( MaxPos ); +} + +inline void KBufferCoord::goRight() { ++Pos; } +inline void KBufferCoord::goLeft() { --Pos; } +inline void KBufferCoord::goRight( unsigned int P ) { Pos += P; } +inline void KBufferCoord::goLeft( unsigned int P ) { Pos -= P; } + +inline void KBufferCoord::gotoStart() { Pos = Line = 0; } + +inline void KBufferCoord::gotoEndOfPreviousLine( int LastPos ) +{ + --Line; + Pos = LastPos; +} + +inline void KBufferCoord::gotoStartOfNextLine() +{ + ++Line; + Pos = 0; +} + + +inline void KBufferCoord::goLineStart( const KBufferCoord &C ) +{ + Pos = ( Line == C.Line ) ? C.Pos : 0; +} + +inline void KBufferCoord::goLineEnd( int L, const KBufferCoord &C ) +{ + Pos = ( Line == C.Line ) ? C.Pos : L; +} + +inline void KBufferCoord::goUp() { --Line; } +inline void KBufferCoord::goDown() { ++Line; } +inline void KBufferCoord::goUp( unsigned int L ) { Line -= L; } +inline void KBufferCoord::goDown( unsigned int L ) { Line += L; } + + +inline int KBufferCoord::indexByLineWidth( int LineWidth ) const +{ + return Line * LineWidth + Pos; +} + + +inline bool KBufferCoord::isPriorInLineThan( const KBufferCoord &C ) const +{ + return Line == C.Line && Pos < C.Pos; +} + +inline bool KBufferCoord::isLaterInLineThan( const KBufferCoord &C ) const +{ + return Line == C.Line && Pos > C.Pos; +} + +inline bool KBufferCoord::isBelow( int L ) const { return Line > L; } +inline bool KBufferCoord::isAbove( int L ) const { return Line < L; } + +inline bool KBufferCoord::isBehindLineStart() const { return Pos > 0; } +inline bool KBufferCoord::isBeforeLineEnd( int MaxPos ) const { return Pos < MaxPos; } + +inline bool KBufferCoord::isAtStart() const { return Pos == 0 && Line == 0; } + +inline KBufferCoord operator+( const KBufferCoord &C, int p ) +{ + return KBufferCoord( C.pos()+p, C.line() ); +} + +} + +#endif diff --git a/khexedit/lib/kbuffercursor.cpp b/khexedit/lib/kbuffercursor.cpp new file mode 100644 index 0000000..0255d2d --- /dev/null +++ b/khexedit/lib/kbuffercursor.cpp @@ -0,0 +1,365 @@ +/*************************************************************************** + kbuffercursor.cpp - description + ------------------- + begin : Don Mai 29 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +//#include <kdebug.h> + +// lib specific +#include "kbufferlayout.h" +#include "kbuffercursor.h" + +using namespace KHE; + +KBufferCursor::KBufferCursor( const KBufferLayout *L ) + : Layout( L ), + Index( 0 ), + Coord( 0, 0 ), + Behind( false ), + AppendPosEnabled( false ) +{ +} + +KBufferCursor::~KBufferCursor() +{ +} + + +bool KBufferCursor::operator==( const KBufferCursor &C ) const +{ + return Index == C.Index && Behind == C.Behind ; +} + + +void KBufferCursor::setAppendPosEnabled( bool APE ) +{ + if( AppendPosEnabled == APE ) + return; + + AppendPosEnabled = APE; + // reposition Cursor + int Length = Layout->length(); + // behind buffer end, not end of line and not empty? + if( realIndex() >= Length && Coord.pos() < Layout->noOfBytesPerLine()-1 && Length > 0 ) + { + if( AppendPosEnabled ) + { + ++Index; + Coord.goRight(); + Behind = false; + } + else + { + --Index; + Coord.goLeft(); + Behind = true; + } + } +} + + +void KBufferCursor::gotoPreviousByte() +{ + if( Behind ) + Behind = false; + else if( Index > 0 ) + { + --Index; + Coord.goCLeft( Layout->noOfBytesPerLine()-1 ); + } +} + + +void KBufferCursor::gotoPreviousByte( int D ) +{ + if( Behind ) + { + --D; + Behind = false; + } + if( D > Index ) + { + if( Index == 0 ) + return; + gotoStart(); + } + gotoIndex( Index - D ); +} + + +void KBufferCursor::gotoNextByte() +{ + int Length = Layout->length(); + + if( Index < Length ) + { + if( Index == Length-1 ) + stepToEnd(); + else + { + ++Index; + Coord.goCRight( Layout->noOfBytesPerLine()-1 ); + Behind = false; + } + } +} + + +void KBufferCursor::gotoNextByte( int D ) // TODO: think about consistency with gotoNextByte!!! +{ + if( Behind ) + { + ++D; + Behind = false; + } + // would we end behind the end? + if( Index+D >= Layout->length() ) + gotoEnd(); + else + gotoIndex( Index + D ); +} + + +void KBufferCursor::gotoNextByteInLine() +{ + int Length = Layout->length(); + + if( Index < Length ) + { + if( Index == Length-1 ) + stepToEnd(); + else + { + ++Index; + + if( Coord.pos() < Layout->noOfBytesPerLine()-1 ) + Coord.goRight(); + else + Behind = true; + } + } +} + + +void KBufferCursor::gotoUp() +{ + // can we even go up? + if( Coord.isBelow(Layout->startLine()) ) + { + Coord.goUp(); + if( Coord.isPriorInLineThan(Layout->start()) ) + { + Index = 0; + Coord.setPos( Layout->startPos() ); + Behind = false; + } + else + { + Index -= Layout->noOfBytesPerLine(); + if( Behind && !atLineEnd() ) + { + ++Index; + Coord.goRight(); + Behind = false; + } + } + } +} + + +void KBufferCursor::gotoDown() +{ + if( Coord.isAbove(Layout->finalLine()) ) + { + Coord.goDown(); + // behind End? + if( Coord.isLaterInLineThan(Layout->final()) ) + gotoEnd(); + else + Index += Layout->noOfBytesPerLine(); + } +} + + +void KBufferCursor::gotoLineStart() +{ + int OldIndex = Index; + Index = Layout->indexAtLineStart( Coord.line() ); + Coord.goLeft( OldIndex-Index ); + Behind = false; +} + + +void KBufferCursor::gotoLineEnd() +{ + if( Index < Layout->length() ) + { + int OldIndex = Index; + Index = Layout->indexAtLineEnd( Coord.line() ); + Coord.goRight( Index-OldIndex ); + + stepToEnd(); + } +} + + +void KBufferCursor::gotoStart() +{ + Index = 0; + Coord = Layout->start(); + Behind = false; +} + + +void KBufferCursor::gotoEnd() +{ + int Length = Layout->length(); + if( Length > 0 ) + { + Index = Length-1; + Coord = Layout->final(); + + stepToEnd(); + } + else + gotoStart(); +} + + +void KBufferCursor::gotoCIndex( int i ) +{ + if( Layout->length() > 0 ) + { + Index = Layout->correctIndex( i ); + Coord = Layout->coordOfIndex( Index ); + if( i > Index ) + stepToEnd(); + else + Behind = false; + } + else + gotoStart(); +} + + +void KBufferCursor::gotoCCoord( const KBufferCoord &C ) +{ + if( Layout->length() > 0 ) + { + Coord = Layout->correctCoord( C ); + Index = Layout->indexAtCoord( Coord ); + if( C > Coord ) + stepToEnd(); + else + Behind = false; + } + else + gotoStart(); +} + + +void KBufferCursor::stepToEnd() +{ + if( AppendPosEnabled && (Coord.pos() < Layout->noOfBytesPerLine()-1) ) + { + ++Index; + Coord.goRight(); + Behind = false; + } + else + Behind = true; +} + + +void KBufferCursor::gotoIndex( int i ) +{ + Index = i; + Coord = Layout->coordOfIndex( Index ); + Behind = false; +} + + +void KBufferCursor::gotoRealIndex() +{ + if( Behind ) + { + ++Index; + Coord = Layout->coordOfIndex( Index ); + Behind = false; + } +} + + +void KBufferCursor::gotoCoord( const KBufferCoord &C ) +{ + Index = Layout->indexAtCoord( C ); + Coord = C; + Behind = false; +} + + +void KBufferCursor::updateCoord() +{ + Coord = Layout->coordOfIndex( Index ); +} + +// page down should be: one page minus one line +// -> if in the very first line page down will put the cursor on the same page into the last line +void KBufferCursor::gotoPageUp() +{ + int NoOfLinesPerPage = Layout->noOfLinesPerPage(); + int NewIndex = Index - NoOfLinesPerPage * Layout->noOfBytesPerLine(); + if( NewIndex < 0 ) + gotoStart(); + else + { + Index = NewIndex; + Coord.goUp( NoOfLinesPerPage ); + if( Behind && !atLineEnd() ) + { + ++Index; + Coord.goRight(); + Behind = false; + } + } +} + + +void KBufferCursor::gotoPageDown() +{ + int NoOfLinesPerPage = Layout->noOfLinesPerPage(); + int NewIndex = Index + NoOfLinesPerPage * Layout->noOfBytesPerLine(); + if( NewIndex >= Layout->length() ) + gotoEnd(); + else + { + Index = NewIndex; + Coord.goDown( NoOfLinesPerPage ); + } +} + + +int KBufferCursor::validIndex() const { return Index < Layout->length() ? Index : -1; } +int KBufferCursor::indexAtLineStart() const { return Layout->indexAtLineStart( Coord.line() ); } +int KBufferCursor::indexAtLineEnd() const { return Layout->indexAtLineEnd( Coord.line() ); } + + +bool KBufferCursor::atStart() const { return Index == 0; } +bool KBufferCursor::atEnd() const { return Index == Layout->length() - 1; } +bool KBufferCursor::atAppendPos() const { return realIndex() >= Layout->length(); } + + +bool KBufferCursor::atLineStart() const { return Layout->atLineStart( Coord ); } +bool KBufferCursor::atLineEnd() const { return Layout->atLineEnd( Coord ); } diff --git a/khexedit/lib/kbuffercursor.h b/khexedit/lib/kbuffercursor.h new file mode 100644 index 0000000..855b3e8 --- /dev/null +++ b/khexedit/lib/kbuffercursor.h @@ -0,0 +1,172 @@ +/*************************************************************************** + kbuffercursor.h - description + ------------------- + begin : Don Mai 29 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBUFFERCURSOR_H +#define KHE_KBUFFERCURSOR_H + +#include "kbuffercoord.h" + + +namespace KHE +{ + +class KBufferLayout; + + +/**@short navigates through the buffer in an abstract way, based on the layout + * + * The cursor is allowed to access every coord that has content as + * described in the layout. It holds the coord of the actual position + * and the according index in the data array. + * + * To enable the cursor to be placed behind the last position in a line + * (e.g, to mark all data in the line without placing the cursor to the + * beginning of the next line) there is a flag Behind that should be read + * as that the real index the cursor is at is the current one + 1 + * (as returned by realIndex()) + * + * For appending new data to the buffer there is also the need to be able + * to place the cursor at a position behind the last byte. This can be + * enabled by calling setAppendPosEnabled(true). If the cursor is placed to + * this position it gets the (real) index of the last byte + 1. As this + * index does not point to an existing byte validIndex() returns -1. + * Check for atAppendPos() to see whether cursor is at this position. + * + * If the buffer is empty there is no navigation possible, of course. + * The cursor will be placed to coord 0/0 with index 1, Behind=false. + * + *@author Friedrich W. H. Kossebau + */ +class KBufferCursor +{ + public: + KBufferCursor( const KBufferLayout *L ); + ~KBufferCursor(); + + + public: + bool operator==( const KBufferCursor &c ) const; + bool operator!=( const KBufferCursor &c ) const { return !(*this == c); } + + public: // modificator + void setAppendPosEnabled( bool APE=true ); + + public: // state value access + /** the index that is drawn at the actual coord */ + int index() const; + /** the pos of the actual coord */ + int pos() const; + /** the line of the actual coord */ + int line() const; + /** the actual coord */ + KBufferCoord coord() const; + /** true if the cursor is located to the right of the actual coord but still shown at the coord */ + bool isBehind() const; + /** returns the real index. That is if the cursor is tagged as "behind" the current index + * it's real index is the next one. + * Attention: this could be outside the data's range if the cursor is behind the last byte! + */ + int realIndex() const; + /** returns the true index if it is valid index that is it is inside the data's range. + * Otherwise -1 is returned + */ + int validIndex() const; + + //bool isValid() const; + bool appendPosEnabled() const; + + public: // index calculation service + /** returns the index at the start of the cursor's line */ + int indexAtLineStart() const; + /** returns the index at the end of the cursor's line */ + int indexAtLineEnd() const; + + public: // navigation commands + void gotoIndex( int I ); + void gotoCoord( const KBufferCoord &C ); + void gotoCIndex( int I ); + void gotoCCoord( const KBufferCoord &C ); + void gotoRealIndex(); + + void gotoPreviousByte(); + void gotoNextByte(); + void gotoPreviousByte( int D ); + void gotoNextByte( int D ); + void gotoNextByteInLine(); + void gotoUp(); + void gotoDown(); + void gotoLineStart(); + void gotoLineEnd(); + void gotoStart(); + void gotoEnd(); + void gotoPageUp(); + void gotoPageDown(); + + /** puts the cursor behind the actual position if it isn't already*/ + void stepBehind(); + void updateCoord(); + + + public: // logical state access + bool atStart() const; + bool atEnd() const; + /** could only be true in InsertMode: Cursor is behind the last byte */ + bool atAppendPos() const; + bool atLineStart() const; + bool atLineEnd() const; + + + protected: + /** if newpos allowed steps at a coord behind the last existing + * or, if that is at a line end, behind the line + * does not check for empty content! + */ + void stepToEnd(); + + private: + /** layout, tells how the column is organized */ + const KBufferLayout *Layout; + + /** Position in buffer */ + int Index; + /** Position and Line */ + KBufferCoord Coord; + + /** tells whether the cursor is actually behind the actual position. + * This is used for selection to the end of a line or of the whole buffer. + */ + bool Behind : 1; + + /** tells whether there could be a position behind the end of the layout */ + bool AppendPosEnabled : 1; +}; + + +inline int KBufferCursor::index() const { return Index; } +inline int KBufferCursor::pos() const { return Coord.pos(); } +inline int KBufferCursor::line() const { return Coord.line(); } +inline KBufferCoord KBufferCursor::coord() const { return Coord; } +inline bool KBufferCursor::isBehind() const { return Behind; } +inline int KBufferCursor::realIndex() const { return Behind ? Index + 1 : Index; } + +inline void KBufferCursor::stepBehind() { Behind = true; } + +//inline bool KBufferCursor::isValid() const { return Index != -1; } + +} + +#endif diff --git a/khexedit/lib/kbufferdrag.cpp b/khexedit/lib/kbufferdrag.cpp new file mode 100644 index 0000000..199982c --- /dev/null +++ b/khexedit/lib/kbufferdrag.cpp @@ -0,0 +1,237 @@ +/*************************************************************************** + kbufferdrag.cpp - description + ------------------- + begin : Mon Jul 07 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qcstring.h> +#include <qtextcodec.h> +// kde specific +#include <kglobal.h> +#include <klocale.h> +// lib specific +#include "kbordercoltextexport.h" +#include "koffsetcoltextexport.h" +#include "kvaluecoltextexport.h" +#include "kcharcoltextexport.h" +#include "kcharcodec.h" +#include "kbufferdrag.h" + + +using namespace std; +using namespace KHE; + +static const char OctetStream[] = "application/octet-stream"; +static const char TextPlainUTF8[] = "text/plain;charset=UTF-8"; +static const char TextPlain[] = "text/plain"; +static const char TextPlainLocalStub[] = "text/plain;charset="; + +//static const char *BaseTypes[3] = { OctetStream, TextPlainUTF8, TextPlain }; + +// creates the name for the local text/plain +static const char *localTextPlain() +{ + static QCString TextPlainLocal; + + if( TextPlainLocal.isNull() ) + { + TextPlainLocal = QCString(KGlobal::locale()->encoding()).lower(); + // remove the whitespaces + int s; + while( (s=TextPlainLocal.find(' ')) >= 0 ) + TextPlainLocal.remove( s, 1 ); + + TextPlainLocal.prepend( TextPlainLocalStub ); + } + + return TextPlainLocal; +} + +// tries to create a codec by the given charset description +static QTextCodec* codecForCharset( const QCString& Desc ) +{ + int i = Desc.find( "charset=" ); + if( i >= 0 ) + { + QCString CharSetName = Desc.mid( i+8 ); + // remove any further attributes + if( (i=CharSetName.find( ';' )) >= 0 ) + CharSetName = CharSetName.left( i ); + + // try to find codec + return QTextCodec::codecForName( CharSetName ); + } + // no charset=, use locale + return KGlobal::locale()->codecForEncoding(); +} + + + +KBufferDrag::KBufferDrag( const QByteArray &D, KCoordRange Range, + const KOffsetColumn *OC, const KValueColumn *HC, const KCharColumn *TC, + QChar SC, QChar UC, const QString &CN, + QWidget *Source, const char *Name ) + :QDragObject( Source, Name ), + CoordRange( Range ), + NoOfCol( 0 ), + SubstituteChar( SC ), + UndefinedChar( UC ), + CodecName( CN ) +{ + setData( D ); + + // print column wise? + if( HC || TC ) + { + if( OC ) + { + Columns[NoOfCol++] = new KOffsetColTextExport( OC ); + Columns[NoOfCol++] = new KBorderColTextExport(); + } + if( HC ) + Columns[NoOfCol++] = new KValueColTextExport( HC, Data.data(), CoordRange ); + if( TC ) + { + if( HC ) Columns[NoOfCol++] = new KBorderColTextExport(); + Columns[NoOfCol++] = new KCharColTextExport( TC, Data.data(), CoordRange, CodecName ); + } + } +} + + +KBufferDrag::~KBufferDrag() +{ + for( uint i=0; i<NoOfCol; ++i ) + delete Columns[i]; +} + + + +void KBufferDrag::setData( const QByteArray &D ) +{ + Data = D; +} + + +const char *KBufferDrag::format( int i ) const +{ + return( i == 0 ? OctetStream : + i == 1 ? TextPlainUTF8 : + i == 2 ? TextPlain : + i == 3 ? localTextPlain() : + 0 ); +} + + +QByteArray KBufferDrag::encodedData( const char *Format ) const +{ + if( Format != 0 ) + { + // octet stream wanted? + if( qstrcmp(Format,OctetStream) == 0 ) + return( Data ); + + // plain text wanted? + if( qstrncmp(Format,TextPlain,10) == 0 ) + { + QCString Output; + QTextCodec *TextCodec = codecForCharset( QCString(Format).lower() ); + if( TextCodec == 0 ) + return Output; + + QString Text; + // plain copy? + if( NoOfCol == 0 ) + { + // duplicate the data and substitute all non-printable items with a space + KCharCodec *CharCodec = KCharCodec::createCodec( CodecName ); + static const QChar Tab('\t'); + static const QChar Return('\n'); + uint Size = Data.size(); + Text.setLength( Size ); + + for( uint i=0; i<Size; ++i ) + { + KHEChar B = CharCodec->decode( Data[i] ); + + Text.at(i) = B.isUndefined() ? KHEChar(UndefinedChar) : + (!B.isPrint() && B != Tab && B != Return ) ? KHEChar(SubstituteChar) : B; + } + // clean up + delete CharCodec; + } + // formatted copy + else + { + // initialize: one for the line's newline \n + uint NeededChars = 1; + for( uint i=0; i<NoOfCol; ++i ) + NeededChars += Columns[i]->charsPerLine(); + // scale with the number of lines + NeededChars *= CoordRange.lines(); + // find out needed size + Text.reserve( NeededChars ); + + // now fill + int l = CoordRange.start().line(); + for( uint i=0; i<NoOfCol; ++i ) + Columns[i]->printFirstLine( Text, l ); + Text.append('\n'); + for( ++l; l<=CoordRange.end().line(); ++l ) + { + for( uint i=0; i<NoOfCol; ++i ) + Columns[i]->printNextLine( Text ); + Text.append('\n'); + } + } + // generate the ouput + Output = TextCodec->fromUnicode( Text ); + // fix end + //if( TextCodec->mibEnum() != 1000 ) + //{ + // Don't include NUL in size (QCString::resize() adds NUL) + // ((QByteArray&)Output).resize( Output.length() ); + //} + return Output; + } + } + + // return empty dummy + return QByteArray(); +} + + + +bool KBufferDrag::canDecode( const QMimeSource* Source ) +{ + bool c =( Source->provides(OctetStream) /*|| Source->provides(TextPlain)*/ ); + return c; +// return( Source->provides(OctetStream) /*|| Source->provides(TextPlain)*/ ); +} + + +bool KBufferDrag::decode( const QMimeSource* Source, QByteArray &Dest ) +{ +// Dest = Source->encodedData( MediaString ); +// return Dest.size() != 0; + + bool CanDecode = Source->provides( OctetStream ); + if( CanDecode ) + Dest = Source->encodedData( OctetStream ); + + return CanDecode; +} + +#include "kbufferdrag.moc" diff --git a/khexedit/lib/kbufferdrag.h b/khexedit/lib/kbufferdrag.h new file mode 100644 index 0000000..86c498f --- /dev/null +++ b/khexedit/lib/kbufferdrag.h @@ -0,0 +1,76 @@ +/*************************************************************************** + kbufferdrag.h - description + ------------------- + begin : Mon Jul 07 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBUFFERDRAG_H +#define KHE_KBUFFERDRAG_H + +// qt specific +#include <qdragobject.h> +// lib specific +#include "khe.h" +#include "kcoordrange.h" +#include "kcoltextexport.h" + +namespace KHE +{ + +// class KBorderColumn; +class KOffsetColumn; +class KValueColumn; +class KCharColumn; + +typedef KColTextExport* KColTextExportPtr; +/** + *@author Friedrich W. H. Kossebau + */ +class KBufferDrag : public QDragObject +{ + Q_OBJECT + + public: + // TODO: make this call somewhat more generic + KBufferDrag( const QByteArray &, KCoordRange Range, + const KOffsetColumn *OC, const KValueColumn *HC, const KCharColumn *TC, + QChar SC, QChar UC, const QString &CN, + QWidget *Source = 0, const char *Name = 0 ); + ~KBufferDrag(); + + public: // QDragObject API + virtual const char *format( int i ) const; + virtual QByteArray encodedData( const char* ) const; + + public: + virtual void setData( const QByteArray &); + + public: + static bool canDecode( const QMimeSource* Source ); + static bool decode( const QMimeSource* Source, QByteArray &Dest ); + + protected: + QByteArray Data; + KCoordRange CoordRange; + /** collection of all the columns. All columns will be autodeleted. */ + KColTextExportPtr Columns[5]; + uint NoOfCol; + QChar SubstituteChar; + QChar UndefinedChar; + const QString &CodecName; +}; + +} + +#endif diff --git a/khexedit/lib/kbufferlayout.cpp b/khexedit/lib/kbufferlayout.cpp new file mode 100644 index 0000000..a2ea9a0 --- /dev/null +++ b/khexedit/lib/kbufferlayout.cpp @@ -0,0 +1,240 @@ +/*************************************************************************** + kbufferlayout.cpp - description + ------------------- + begin : Thu Jun 12 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#include "kbufferlayout.h" + +using namespace KHE; + + + +KBufferLayout::KBufferLayout( int NoBpL, int SO, int L ) + : NoOfBytesPerLine( NoBpL ), + StartOffset( SO ), + Length( L ) +{ + calcStart(); + calcEnd(); +} + + +KBufferLayout::~KBufferLayout() +{ +} + + +bool KBufferLayout::setStartOffset( int SO ) +{ + // rejecting <0 + if( SO < 0 ) + SO = 0; + + if( StartOffset == SO ) + return false; + + StartOffset = SO; + + calcStart(); + calcEnd(); + return true; +} + + +bool KBufferLayout::setNoOfBytesPerLine( int N ) +{ + // rejecting <1 + if( N < 1 ) + N = 1; + + // no changes? + if( NoOfBytesPerLine == N ) + return false; + + NoOfBytesPerLine = N; + + calcStart(); + calcEnd(); + return true; +} + + +bool KBufferLayout::setLength( int L ) +{ + // rejecting < 0 + if( L < 0 ) + L = 0; + + // no changes? + if( Length == L ) + return false; + + Length = L; + + calcEnd(); + return true; +} + + +void KBufferLayout::setNoOfLinesPerPage( int N ) +{ + NoOfLinesPerPage = N; +} + + +void KBufferLayout::calcStart() +{ + ContentCoords.setStart( KBufferCoord(StartOffset,NoOfBytesPerLine,false) ); +} + + +void KBufferLayout::calcEnd() +{ + ContentCoords.setEnd( (Length>0)?KBufferCoord(Length-1+StartOffset,NoOfBytesPerLine,false): + KBufferCoord(-1,ContentCoords.start().line()) ); +} + + +int KBufferLayout::indexAtCLineStart( int L ) const +{ + return ( L <= ContentCoords.start().line() ) ? 0: + ( L > ContentCoords.end().line() ) ? Length-1: + L * NoOfBytesPerLine - StartOffset; +} + + +int KBufferLayout::indexAtCLineEnd( int L ) const +{ + return ( L < ContentCoords.start().line() ) ? 0: + ( L >= ContentCoords.end().line() ) ? Length-1: + (L+1)*NoOfBytesPerLine-StartOffset-1; +} + + +int KBufferLayout::indexAtCCoord( const KBufferCoord &C ) const +{ + int Index = indexAtCoord( C ); + + return ( Index <= 0 ) ? 0: + ( Index >= Length ) ? Length-1: + Index; +} + + +int KBufferLayout::lineAtCIndex( int Index ) const +{ + return ( Index <= 0 ) ? ContentCoords.start().line(): + ( Index >= Length ) ? ContentCoords.end().line(): + lineAtIndex(Index); +} + + +KBufferCoord KBufferLayout::coordOfCIndex( int Index ) const +{ + return ( Index <= 0 ) ? ContentCoords.start(): + ( Index >= Length ) ? ContentCoords.end(): + coordOfIndex(Index); +} + + +int KBufferLayout::indexAtLineStart( int L ) const +{ + return ( L == ContentCoords.start().line() ) ? 0 : L*NoOfBytesPerLine-StartOffset; +} + + +int KBufferLayout::indexAtLineEnd( int L ) const +{ + return ( L == ContentCoords.end().line() ) ? Length-1 : (L+1)*NoOfBytesPerLine-StartOffset-1; +} + + +int KBufferLayout::indexAtCoord( const KBufferCoord &C ) const +{ + return C.indexByLineWidth( NoOfBytesPerLine ) - StartOffset; +} + +int KBufferLayout::lineAtIndex( int Index ) const +{ + return (Index+StartOffset)/NoOfBytesPerLine; +} + +KBufferCoord KBufferLayout::coordOfIndex( int Index ) const +{ + return KBufferCoord( Index+StartOffset, NoOfBytesPerLine, false ); +} + + + +int KBufferLayout::correctIndex( int I ) const +{ + return ( I <= 0 ) ? 0: + ( I >= Length ) ? Length-1: + I; +} + + +KBufferCoord KBufferLayout::correctCoord( const KBufferCoord &C ) const +{ + return ( C <= ContentCoords.start() ) ? ContentCoords.start(): + ( C >= ContentCoords.end() ) ? ContentCoords.end(): + ( C.pos() >= NoOfBytesPerLine ) ? KBufferCoord( NoOfBytesPerLine-1, C.line() ): + C; +} + + +bool KBufferLayout::atLineStart( const KBufferCoord &C ) const +{ + return ( C.line() == ContentCoords.start().line() ) ? C.pos() == ContentCoords.start().pos(): + C.pos() == 0; +} + +bool KBufferLayout::atLineEnd( const KBufferCoord &C ) const +{ + return ( C.line() == ContentCoords.end().line() ) ? C.pos() == ContentCoords.end().pos(): + C.pos() == NoOfBytesPerLine-1; +} + + +KSection KBufferLayout::positions( int Line ) const +{ + return KSection( firstPos(Line), lastPos(Line) ); +} + + +int KBufferLayout::firstPos( const KBufferCoord &C ) const +{ + return ( ContentCoords.start().isLaterInLineThan(C) ) ? ContentCoords.start().pos() : C.pos(); +} + +int KBufferLayout::lastPos( const KBufferCoord &C ) const +{ + return ( ContentCoords.end().isPriorInLineThan(C) ) ? ContentCoords.end().pos() : C.pos(); +} + +int KBufferLayout::firstPos( int Line ) const +{ + return Line == ContentCoords.start().line() ? ContentCoords.start().pos() : 0; +} + +int KBufferLayout::lastPos( int Line ) const +{ + return ( Line == ContentCoords.end().line() ) ? ContentCoords.end().pos() : NoOfBytesPerLine-1; +} + +bool KBufferLayout::hasContent( int Line ) const +{ + return ContentCoords.includesLine( Line ); +} diff --git a/khexedit/lib/kbufferlayout.h b/khexedit/lib/kbufferlayout.h new file mode 100644 index 0000000..c243225 --- /dev/null +++ b/khexedit/lib/kbufferlayout.h @@ -0,0 +1,196 @@ +/*************************************************************************** + kbufferlayout.h - description + ------------------- + begin : Thu Jun 12 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBUFFERLAYOUT_H +#define KHE_KBUFFERLAYOUT_H + +// lib specific +#include "kcoordrange.h" +#include "ksection.h" + +namespace KHE { + +/**@short the logical layout of a plain buffer view + * + * Given the values for + * * length of the buffer, + * * number of bytes per line, + * * a possible (relative) offset in the display, and + * * the number of lines per page jump + * the following values are calculated: + * * starting line of display, + * * starting position in this line, + * * final line of display, + * * final position in this line, and + * * the total number of lines (is final line +1 or 0) + * + * This layout sees the buffer as a continous stream of byte, + * thus uses each line after the start from the begin to the end. + * + * If the buffer is empty the end coord will be set one pos left to the start coord + * to easen the cursor handling. + * + *@author Friedrich W. H. Kossebau + */ +class KBufferLayout +{ + public: + KBufferLayout( int NoBpL, int SO, int L ); + //KBufferLayout(); + ~KBufferLayout(); + + + public: // given values + /** */ + int startOffset() const; + /** returns number of bytes per line */ + int noOfBytesPerLine() const; + /** returns the length of the displayed data (equals Buffer->size()) */ + int length() const; + /** returns number of lines per visual page */ + int noOfLinesPerPage() const; + + public: // calculated values + int startLine() const; + int startPos() const; + /** returns the coord of the start */ + KBufferCoord start() const; + + int finalLine() const; + int finalPos() const; + /** returns the coord of the end */ + KBufferCoord final() const; + + /** tells how much lines this layout needs (incl. blank leading lines due to StartOffset) */ + int noOfLines() const; + + + public: // value calculation service + /** calculates the index of the coord + * If the coord is before the first coord the first index is returned, + * if the coord is behind the last coord the last index is returned + */ + int indexAtCCoord( const KBufferCoord &C ) const; + /** calculates the index of the first pos in line. + * If the line is below the first line the first index is returned, + * if the line is above the last line the last index is returned + */ + int indexAtCLineStart( int L ) const; + /** calculates the index of last pos in line + * If the line is below the first line the first index is returned, + * if the line is above the last line the last index is returned + */ + int indexAtCLineEnd( int L ) const; + /** calculates the line in which index is found + * If the index is below the first index the first line is returned, + * if the index is above the last index the last line is returned + */ + int lineAtCIndex( int Index ) const; + /** calculates the coord in which index is found + * If the index is below the first index the first coord is returned, + * if the index is above the last index the last coord is returned + */ + KBufferCoord coordOfCIndex( int Index ) const; + + /** calculates the index of coord. if coord is invalid the behaviour is undefinded */ + int indexAtCoord( const KBufferCoord &C ) const; + /** calculates the index of the first pos in line. if line is invalid the behaviour is undefinded */ + int indexAtLineStart( int L ) const; + /** calculates the index of last pos in line. if line is invalid the behaviour is undefinded */ + int indexAtLineEnd( int L ) const; + /** calculates the line in which index is found. if index is invalid the behaviour is undefinded */ + int lineAtIndex( int Index ) const; + /** calculates the coord in which index is found. if index is invalid the behaviour is undefinded */ + KBufferCoord coordOfIndex( int Index ) const; + + /** returns the used positions in line */ + KSection positions( int Line ) const; + /** returns the first Pos in line. if line is invalid the behaviour is undefinded */ + int firstPos( int Line ) const; + /** returns the last Pos in line. if line is invalid the behaviour is undefinded */ + int lastPos( int Line ) const; + /** returns the valid Pos or the first Pos in line. if coord is invalid the behaviour is undefinded */ + int firstPos( const KBufferCoord &C ) const; + /** returns the valid Pos or the last Pos in line. if coord is invalid the behaviour is undefinded */ + int lastPos( const KBufferCoord &C ) const; + /** returns true if the line has content */ + bool hasContent( int Line ) const; + /** returns true if the coord is the first in it's line. if coord is invalid the behaviour is undefinded */ + bool atLineStart( const KBufferCoord &C ) const; + /** returns true if the coord is the last in it's line. if coord is invalid the behaviour is undefinded */ + bool atLineEnd( const KBufferCoord &C ) const; + + /** returns the index if valid or the nearest valid index */ + int correctIndex( int I ) const; + /** returns the coord if valid or the nearest valid coord */ + KBufferCoord correctCoord( const KBufferCoord &C ) const; + + + public: // modification access; return true if changes + /** sets StartOffset, returns true if changed */ + bool setStartOffset( int SO ); + /** sets number of bytes per line, returns true if changed */ + bool setNoOfBytesPerLine( int N ); + /** sets number of lines per page */ + void setNoOfLinesPerPage( int N ); + /** sets length of data to display, returns true if changed */ + bool setLength( int L ); + + + protected: + /** calculates the start coord by startoffset and number of bytes per line */ + void calcStart(); + /** calculates the final coord by startoffset, length, and number of bytes per line */ + void calcEnd(); + + + protected: + /** how many chars per line */ + int NoOfBytesPerLine; + /** starting offset of the displayed data */ + int StartOffset; + /** length of the displayed buffer */ + int Length; + /** number of lines that are moved by page up/down */ + int NoOfLinesPerPage; + + protected: // calculated values, buffered + /** coord in which the start offset is (starting with 0) */ +// KBufferCoord Start; + /** coord in which the last byte is (starting with 0) */ +// KBufferCoord Final; + /** */ + KCoordRange ContentCoords; +}; + + +inline int KBufferLayout::startOffset() const { return StartOffset; } +inline int KBufferLayout::noOfBytesPerLine() const { return NoOfBytesPerLine; } +inline int KBufferLayout::length() const { return Length; } + +inline KBufferCoord KBufferLayout::final() const { return ContentCoords.end(); } +inline KBufferCoord KBufferLayout::start() const { return ContentCoords.start(); } +inline int KBufferLayout::startPos() const { return start().pos(); } +inline int KBufferLayout::finalPos() const { return final().pos(); } +inline int KBufferLayout::startLine() const { return start().line(); } +inline int KBufferLayout::finalLine() const { return final().line(); } +inline int KBufferLayout::noOfLinesPerPage() const { return NoOfLinesPerPage; } +inline int KBufferLayout::noOfLines() const { return Length==0?0:final().line()+1; } + +} + +#endif diff --git a/khexedit/lib/kbufferranges.cpp b/khexedit/lib/kbufferranges.cpp new file mode 100644 index 0000000..57fb9c4 --- /dev/null +++ b/khexedit/lib/kbufferranges.cpp @@ -0,0 +1,307 @@ +/*************************************************************************** + kbufferranges.cpp - description + ------------------- + begin : Sun Jun 22 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +//#include <kdebug.h> + +// lib specific +#include "kbufferranges.h" + + +using namespace KHE; + +KBufferRanges::KBufferRanges( KBufferLayout *L ) + : Modified( false ), + Layout( L ) +{ +} + + +KBufferRanges::~KBufferRanges() +{ +} + + +void KBufferRanges::reset() +{ + Selection.cancel(); + FirstWordSelection.unset(); + Marking.unset(); + ChangedRanges.clear(); +} + + +void KBufferRanges::setMarking( KSection M ) +{ + if( Marking == M ) + return; + + Marking = M; + addChangedRange( M ); +} + + +void KBufferRanges::removeFurtherSelections() +{ + for( int i = 1; i < noOfSelections(); ++i ) + removeSelection( i ); +} + + +void KBufferRanges::setSelection( KSection S ) +{ + bool Changed = Selection.isValid(); + if( Changed ) + addChangedRange( Selection ); + Selection = S; + addChangedRange( Selection ); +} + +void KBufferRanges::setSelectionStart( int StartIndex ) +{ + bool Changed = Selection.isValid(); + if( Changed ) + addChangedRange( Selection ); + + Selection.setStart( StartIndex ); +} + + +void KBufferRanges::setSelectionEnd( int EndIndex ) +{ + KSection OldSelection = Selection; + Selection.setEnd( EndIndex ); + + // TODO: think about rather building a diff of the sections + if( !OldSelection.isValid() ) + { + addChangedRange( Selection ); + return; + } + if( !Selection.isValid() ) + { + addChangedRange( OldSelection ); + return; + } + + if( OldSelection == Selection ) + return; + int CS_; + int CE_; + // changes at the end? + if( Selection.start() == OldSelection.start() ) + { + CS_ = OldSelection.end()+1; + CE_ = Selection.end(); + if( CE_ < CS_ ) + { + CS_ = Selection.end()+1; + CE_ = OldSelection.end(); + } + } + // changes at the start? + else if( Selection.end() == OldSelection.end() ) + { + CS_ = OldSelection.start(); + CE_ = Selection.start()-1; + if( CE_ < CS_ ) + { + CS_ = Selection.start(); + CE_ = OldSelection.start()-1; + } + } + // change over the anchor + else + { + CS_ = OldSelection.start(); + CE_ = Selection.end(); + if( CE_ < CS_ ) + { + CS_ = Selection.start(); + CE_ = OldSelection.end(); + } + } + KSection C( CS_, CE_ ); + + bool Changed = C.isValid(); + if( Changed ) + addChangedRange( C ); + return; +} + + +void KBufferRanges::removeSelection( int id ) +{ + if( id > 0 ) + return; + + bool Changed = Selection.isValid(); + if( Changed ) + addChangedRange( Selection ); + + Selection.cancel(); + FirstWordSelection.unset(); +} + + +bool KBufferRanges::overlapsSelection( int FirstIndex, int LastIndex, int *SI, int *EI ) const +{ + if( Selection.overlaps(KSection(FirstIndex,LastIndex)) ) + { + *SI = Selection.start(); + *EI = Selection.end(); + return true; + } + return false; +} + + +bool KBufferRanges::overlapsMarking( int FirstIndex, int LastIndex, int *SI, int *EI ) const +{ + if( Marking.overlaps(KSection(FirstIndex,LastIndex)) ) + { + *SI = Marking.start(); + *EI = Marking.end(); + return true; + } + return false; +} + + +const KSection *KBufferRanges::firstOverlappingSelection( KSection Range ) const +{ + if( Selection.overlaps(Range) ) + return &Selection; + + return 0L; +} + + +const KSection *KBufferRanges::overlappingMarking( KSection Range ) const +{ + if( Marking.overlaps(Range) ) + return &Marking; + + return 0L; +} + +/* +bool KBufferRanges::overlapsChanges( int FirstIndex, int LastIndex, int *SI, int *EI ) const +{ + for( KCoordRangeList::const_iterator S=ChangedRanges.begin(); S!=ChangedRanges.end(); ++S ) + { + if( (*S).overlaps(KBuff(FirstIndex,LastIndex)) ) + { + *SI = (*S).start(); + *EI = (*S).end(); + return true; + } + } + + return false; +} + +bool KBufferRanges::overlapsChanges( KSection Indizes, KSection *ChangedRange ) const +{ + for( KSectionList::const_iterator S=ChangedRanges.begin(); S!=ChangedRanges.end(); ++S ) + { + if( (*S).overlaps(Indizes) ) + { + *ChangedRange = *S; + return true; + } + } + + return false; +} +*/ +bool KBufferRanges::overlapsChanges( const KCoordRange &Range, KCoordRange *ChangedRange ) const +{ + // TODO: add a lastusedrange pointer for quicker access + for( KCoordRangeList::const_iterator R=ChangedRanges.begin(); R!=ChangedRanges.end(); ++R ) + { + if( (*R).overlaps(Range) ) + { + *ChangedRange = *R; + return true; + } + } + + return false; +} + + +void KBufferRanges::addChangedRange( int SI, int EI ) +{ + addChangedRange( KSection(SI,EI) ); +} + + +void KBufferRanges::addChangedRange( KSection S ) +{ + addChangedRange( KCoordRange(Layout->coordOfIndex(S.start()),Layout->coordOfIndex(S.end())) ); +} + + +void KBufferRanges::addChangedRange( const KCoordRange &NewRange ) +{ + ChangedRanges.addCoordRange( NewRange ); + + Modified = true; +} + + +void KBufferRanges::removeMarking() +{ + bool Changed = Marking.isValid(); + if( Changed ) + addChangedRange( Marking ); + + Marking.unset(); +} + + +void KBufferRanges::resetChangedRanges() +{ + ChangedRanges.clear(); + Modified = false; +} + + +void KBufferRanges::setFirstWordSelection( KSection Section ) +{ + FirstWordSelection = Section; + setSelection( FirstWordSelection ); +} + + void KBufferRanges::ensureWordSelectionForward( bool Forward ) + { + // in the anchor not on the right side? + if( Selection.isForward() != Forward ) + { + if( Forward ) + { + setSelectionEnd( FirstWordSelection.start() ); + Selection.setForward(); + } + else + { + setSelectionEnd( FirstWordSelection.end()+1 ); + Selection.setBackward(); + } + } + } + diff --git a/khexedit/lib/kbufferranges.h b/khexedit/lib/kbufferranges.h new file mode 100644 index 0000000..ed2cbce --- /dev/null +++ b/khexedit/lib/kbufferranges.h @@ -0,0 +1,130 @@ +/*************************************************************************** + kbufferranges.h - description + ------------------- + begin : Sun Jun 22 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBUFFERRANGES_H +#define KHE_KBUFFERRANGES_H + +// lib specific +#include "kbufferlayout.h" +#include "kselection.h" +#include "ksectionlist.h" +#include "kcoordrangelist.h" + +namespace KHE +{ + +/** a class to control all the ranges like marking and selections + * holds also all modified ranges and merges them so a repaint can take its info from here + * + * @author Friedrich W. H. Kossebau + */ +class KBufferRanges +{ + public: + KBufferRanges( KBufferLayout *L ); + ~KBufferRanges(); + + public: // modifcation access + void setMarking( KSection M ); + void setSelectionStart( int StartIndex ); + void setSelectionEnd( int StartIndex ); + void setSelection( KSection S ); + /** */ + void setFirstWordSelection( KSection S ); + /** */ + void ensureWordSelectionForward( bool Forward ); + + /** removes marking and returns true if something changed */ + void removeMarking(); + /** removes selection with id and returns true if something changed */ + void removeSelection( int id = 0 ); + /** removes all but the standard selection and returns true if something changed */ + void removeFurtherSelections(); + + void addChangedRange( KSection S ); + void addChangedRange( int SI, int EI ); + void addChangedRange( const KCoordRange &NewRange ); + void resetChangedRanges(); + + void setModified( bool M = true ); + /** removes all ranges */ + void reset(); + + public: // value access + int noOfSelections() const; + int selectionStart() const; + int selectionEnd() const; + KSection selection() const; + KSection firstWordSelection() const; + int selectionLength() const; + bool isModified() const; + + public: // calculated logic access + bool hasSelection() const; + bool hasMarking() const; + bool selectionStarted() const; + bool selectionJustStarted() const; + bool hasFirstWordSelection() const; + bool selectionIncludes( int Index ) const; + bool markingIncludes( int Index ) const; + // TODO: next three are deprecated + bool overlapsSelection( int FirstIndex, int LastIndex, int *SI, int *EI ) const; + bool overlapsMarking( int FirstIndex, int LastIndex, int *SI, int *EI ) const; +// bool overlapsChanges( int FirstIndex, int LastIndex, int *SI, int *EI ) const; +// bool overlapsChanges( KSection Indizes, KSection *ChangedRange ) const; + bool overlapsChanges( const KCoordRange &Range, KCoordRange *ChangedRange ) const; + const KSection *firstOverlappingSelection( KSection Range ) const; + const KSection *overlappingMarking( KSection Range ) const; + + + protected: + /** true if something changed */ + bool Modified; + + KSection Marking; + KSelection Selection; + /** memories first selected word on wordwise selection */ + KSection FirstWordSelection; + + KCoordRangeList ChangedRanges; + + KBufferLayout *Layout; +}; + + +inline int KBufferRanges::noOfSelections() const { return 1; } + +inline int KBufferRanges::selectionStart() const { return Selection.start(); } +inline int KBufferRanges::selectionEnd() const { return Selection.end(); } +inline KSection KBufferRanges::selection() const { return Selection; } +inline KSection KBufferRanges::firstWordSelection() const { return FirstWordSelection; } +inline int KBufferRanges::selectionLength() const { return Selection.width(); } +inline bool KBufferRanges::isModified() const { return Modified; } + +inline bool KBufferRanges::hasSelection() const { return Selection.isValid(); } +inline bool KBufferRanges::selectionStarted() const { return Selection.started(); } +inline bool KBufferRanges::selectionJustStarted() const { return Selection.justStarted(); } +inline bool KBufferRanges::hasFirstWordSelection() const { return FirstWordSelection.isValid(); } +inline bool KBufferRanges::hasMarking() const { return Marking.isValid(); } +inline bool KBufferRanges::selectionIncludes( int Index ) const { return Selection.includes( Index ); } +inline bool KBufferRanges::markingIncludes( int Index ) const { return Marking.includes( Index ); } + +inline void KBufferRanges::setModified( bool M ) { Modified = M; } + +} + +#endif diff --git a/khexedit/lib/kbytecodec.h b/khexedit/lib/kbytecodec.h new file mode 100644 index 0000000..fc4e1b3 --- /dev/null +++ b/khexedit/lib/kbytecodec.h @@ -0,0 +1,73 @@ +/*************************************************************************** + kbytecodec.h - description + ------------------- + begin : Sam Mai 17 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBYTECODEC_H +#define KHE_KBYTECODEC_H + +#include "khe.h" +#include <qstring.h> + +namespace KHE +{ + +/** class that is able to convert codings to and from + * hexadecimal, decimal, octal, and binary + * + * the buffer will be always filled up to CodingWidth, if not using shortCodingFunction + * a closing '\0' will be always added + * + *@author Friedrich W. H. Kossebau + */ + +class KByteCodec +{ + public: + static KByteCodec *createCodec( KCoding C ); + + + protected: // hiding, as this class should never be instanciated + KByteCodec() {} + + public: // API to be implemented + /** */ + virtual unsigned int encodingWidth() const = 0; + /** */ + virtual unsigned char digitsFilledLimit() const = 0; + + /** encodes the Char and writes the result to */ + virtual void encode( QString &Digits, unsigned int Pos, const unsigned char Char ) const = 0; + /** */ + virtual void encodeShort( QString &Digits, unsigned int Pos, const unsigned char Char ) const = 0; + + /** */ + virtual bool appendDigit( unsigned char *Byte, const unsigned char Digit ) const = 0; + /** */ + virtual void removeLastDigit( unsigned char *Byte ) const = 0; + /** */ + virtual bool isValidDigit( const unsigned char Digit ) const = 0; + /** */ + virtual bool turnToValue( unsigned char *Digit ) const = 0; + + + public: + /** */ + uint decode( unsigned char *Char, const QString &Digits, uint Pos ) const; +}; + +} + +#endif diff --git a/khexedit/lib/kbytesedit.cpp b/khexedit/lib/kbytesedit.cpp new file mode 100644 index 0000000..40b57a1 --- /dev/null +++ b/khexedit/lib/kbytesedit.cpp @@ -0,0 +1,162 @@ +/*************************************************************************** + kbytesedit.cpp - description + ------------------- + begin : Die Jul 9 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kplainbuffer.h" +#include "kbytesedit.h" +#include "kbufferranges.h" +#include "kbuffercursor.h" + +using namespace KHE; + + +KBytesEdit::KBytesEdit( char *D, int DS_, int RS_, bool KM, QWidget *Parent, const char *Name, WFlags F ) + : KHexEdit( 0L, Parent, Name, F ), + AutoDelete( false ) +{ + setData( D, DS_, RS_, KM ); +} + +KBytesEdit::KBytesEdit( char *D, int DS_, QWidget *Parent, const char *Name, WFlags F ) + : KHexEdit( 0L, Parent, Name, F ), + AutoDelete( false ) +{ + setData( D, DS_ ); +} + + +KBytesEdit::KBytesEdit( QWidget *Parent, const char *Name, WFlags F ) + : KHexEdit( 0L, Parent, Name, F ), + AutoDelete( false ) +{ + setDataBuffer( new KPlainBuffer() ); +} + +KBytesEdit::~KBytesEdit() +{ + clean(); +} + +void KBytesEdit::setReadOnly( bool RO ) +{ + KPlainBuffer *Buffer = dynamic_cast<KPlainBuffer *>(DataBuffer); + if( Buffer ) + Buffer->setReadOnly( RO ); + KHexEdit::setReadOnly( RO ); +} + + +void KBytesEdit::setAutoDelete( bool AD ) +{ + AutoDelete = AD; +} + + +char *KBytesEdit::data() const +{ + KPlainBuffer *Buffer = dynamic_cast<KPlainBuffer *>(DataBuffer); + return Buffer ? Buffer->data() : 0L; +} + + +void KBytesEdit::setData( char *D, int S, int RS_, bool KM ) +{ + KPlainBuffer *NewBuffer = new KPlainBuffer( D, S, RS_, KM ); + if( DataBuffer ) + { + // take the settings + NewBuffer->setReadOnly( DataBuffer->isReadOnly() ); + clean(); + } + else + NewBuffer->setReadOnly( isReadOnly() ); + + setDataBuffer( NewBuffer ); +} + + +int KBytesEdit::dataSize() const +{ + KPlainBuffer *Buffer = dynamic_cast<KPlainBuffer *>(DataBuffer); + return Buffer ? Buffer->size() : -1; +} + + +int KBytesEdit::maxDataSize() const +{ + KPlainBuffer *Buffer = dynamic_cast<KPlainBuffer *>(DataBuffer); + return Buffer ? Buffer->maxSize() : -1; +} + + +void KBytesEdit::setMaxDataSize( int MS ) +{ + KPlainBuffer *Buffer = dynamic_cast<KPlainBuffer *>(DataBuffer); + if( Buffer ) + Buffer->setMaxSize( MS ); +} + + +bool KBytesEdit::keepsMemory() const +{ + KPlainBuffer *Buffer = dynamic_cast<KPlainBuffer *>(DataBuffer); + return Buffer ? Buffer->keepsMemory() : false; +} + + +void KBytesEdit::setKeepsMemory( bool KM ) +{ + KPlainBuffer *Buffer = dynamic_cast<KPlainBuffer *>(DataBuffer); + if( Buffer ) + Buffer->setKeepsMemory( KM ); +} + + +bool KBytesEdit::isAutoDelete() const { return AutoDelete; } + + +void KBytesEdit::repaintRange( int i1, int i2 ) +{ + bool ChangeCursor = !(CursorPaused) && KSection(i1,i2).includes( BufferCursor->index() ); + if( ChangeCursor ) + pauseCursor(); + + BufferRanges->addChangedRange( i1, i2 ); + + repaintChanged(); + + if( ChangeCursor ) + unpauseCursor(); +} + + +void KBytesEdit::clean() +{ + if( DataBuffer ) + { + if( AutoDelete ) + { + char *D = data(); + if( D ) + delete [] D; + } + delete DataBuffer; + } +} + + +#include "kbytesedit.moc" diff --git a/khexedit/lib/kbytesedit.h b/khexedit/lib/kbytesedit.h new file mode 100644 index 0000000..daf8b6e --- /dev/null +++ b/khexedit/lib/kbytesedit.h @@ -0,0 +1,163 @@ +/*************************************************************************** + kbytesedit.h - description + ------------------- + begin : Die Jul 9 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KBYTESEDIT_H +#define KHE_KBYTESEDIT_H + + +#include "khexedit.h" + +#include <khexedit_export.h> + +namespace KHE +{ + +class KDataBuffer; +class KBytesEditPrivate; + +/** the beginner's hex edit widget ;) + * + * It hides the concept of the KDataBuffer and accepts a pure pointer + * to a reasonable large array of bytes + * + * 1. used as viewer + * a) static data ranges -> no changes for data pointer and length + * possible changes are told to the widget by repaintRange + * b) changing data ranges -> data pointer and length might change + * changes told by + * * resetData( char *, int size, bool repaint ); + * * + * 2. used as editor + * a) static data ranges + * data pointer stays the same + * b) changing data ranges + * pointer to the data changes in charge of the widget: + * given pointer and intermediate pointer are possibly invalid + * problem: who cares about the array if the data is deleted? + * -> solved by setAutoDelete() + * + * + *@author Friedrich W. H. Kossebau + */ +//TODO: give the bytes edit widget an empty buffer as default +class KHEXEDIT_EXPORT KBytesEdit : public KHexEdit +{ + Q_OBJECT + //_PROPERTY( char * Data READ data ) + Q_PROPERTY( int DataSize READ dataSize ) + Q_PROPERTY( int MaxDataSize READ maxDataSize WRITE setMaxDataSize ) + Q_PROPERTY( bool AutoDelete READ isAutoDelete WRITE setAutoDelete DESIGNABLE false ) + + + public: + /** creates a new widget to view/edit data + * @param D pointer to memory + * @param S size of used memory + * @param RS_ real size of the memory + * @param KM keep the memory on resize (RS_ is then the maximum size) + * @param Parent parent widget + * @param Name name for this widget + * @param F flags + */ + KBytesEdit( char *D, int DS_, int RS_, bool KM, QWidget *Parent = 0, const char *Name = 0, WFlags F = 0 ); + /** hands over to the editor a new byte array. + * If there exists an old one and autodelete is set the old one gets deleted. + * @param D pointer to memory + * @param S size of used memory + * @param RS_ real size of the memory + * @param KM keep the memory on resize (RS_ is the maximum size) + */ + KBytesEdit( char *D, int DS_, QWidget *Parent = 0, const char *Name = 0, WFlags F = 0 ); + /** hands over to the editor a new byte array. + * If there exists an old one and autodelete is set the old one gets deleted. + * @param D pointer to memory + * @param S size of used memory + * @param RS_ real size of the memory + * @param KM keep the memory on resize (RS_ is the maximum size) + */ + KBytesEdit( QWidget *Parent = 0, const char *Name = 0, WFlags F = 0 ); + virtual ~KBytesEdit(); + + + public: // value access + /** returns the pointer to the actual byte array. This can be but must not be the one + * that was given in the constructor. + */ + char *data() const; + /** returns the size of the actual byte array */ + int dataSize() const; + /** returns the maximal allowed size for the byte array */ + int maxDataSize () const; + /** returns whether autodelete is set for the byte array */ + bool isAutoDelete() const; + /** returns whether the memory of the byte array is kept */ + bool keepsMemory() const; + + public: // logic value service + + public: // modification access + + public slots: + /** hands over to the editor a new byte array. + * If there exists an old one and autodelete is set the old one gets deleted. + * @param D pointer to memory + * @param S size of used memory + * @param RS_ real size of the memory + * @param KM keep the memory on resize (RS_ is the maximum size) + */ + void setData( char *D, int S, int RS_ = -1, bool KM = true ); + + /** sets whether the given array should be handled read only or not */ + virtual void setReadOnly( bool RO = true ); + /** sets the maximal size of the actual byte array. If the actual array is already larger + * it will not be modified but there can be only done non-inserting actions + * until the array's is below the limit + */ + void setMaxDataSize( int MS ); + /** sets whether the array should be deleted on the widget's end or if a new array is set. + * Default is false + */ + void setAutoDelete( bool AD = true ); + /** sets whether the memory given by setData or in the constructor should be kept on resize + */ + void setKeepsMemory( bool KM = true ); + + /** repaint the indizes from i1 to i2 */ + void repaintRange( int i1, int i2 ); + + protected: + /** deletes the databuffer */ + void clean(); + + + protected slots: + + + protected: + /** */ + bool AutoDelete:1; + /** */ + KBytesEditPrivate *d; + + private: // Disabling copy constructor and operator= - not useful + KBytesEdit( const KBytesEdit & ); + KBytesEdit &operator=( const KBytesEdit & ); +}; + +} + +#endif diff --git a/khexedit/lib/kcharcodec.h b/khexedit/lib/kcharcodec.h new file mode 100644 index 0000000..9d1b628 --- /dev/null +++ b/khexedit/lib/kcharcodec.h @@ -0,0 +1,55 @@ +/*************************************************************************** + kcharcodec.h - description + ------------------- + begin : Do Nov 25 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCHARCODEC_H +#define KHE_KCHARCODEC_H + +// qt specific +#include <qstringlist.h> +// lib specific +#include "khe.h" +#include "khechar.h" +#include "khexedit_export.h" + + +namespace KHE +{ + +class KHEXEDIT_EXPORT KCharCodec +{ + public: + /** */ + static KCharCodec* createCodec( KEncoding E ); + /** */ + static KCharCodec* createCodec( const QString &Name ); + + static const QStringList &codecNames(); + + public: // API to be implemented + virtual KHEChar decode( char Byte ) const = 0; + virtual bool encode( char *D, const QChar &C ) const = 0; + virtual const QString& name() const = 0; + + protected: + /** */ + static QStringList CodecNames; +}; + +} + +#endif + diff --git a/khexedit/lib/kcharcoltextexport.cpp b/khexedit/lib/kcharcoltextexport.cpp new file mode 100644 index 0000000..bc4a60e --- /dev/null +++ b/khexedit/lib/kcharcoltextexport.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + kcharcoltextexport.cpp - description + ------------------- + begin : Wed Sep 03 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kbufferlayout.h" +#include "kcharcolumn.h" +#include "kcharcodec.h" +#include "kcharcoltextexport.h" + +using namespace KHE; + + +KCharColTextExport::KCharColTextExport( const KCharColumn* TC, const char *D, KCoordRange CR, const QString &CodecName ) + : KBufferColTextExport( TC, D, CR, 1 ), + CharCodec( KCharCodec::createCodec(CodecName) ), + SubstituteChar( TC->substituteChar() ), + UndefinedChar( TC->undefinedChar() ) +{ +} + + +KCharColTextExport::~KCharColTextExport() +{ + delete CharCodec; +} + + +void KCharColTextExport::print( QString &T ) const +{ + int p = 0; + int pEnd = NoOfBytesPerLine; + // correct boundaries + if( PrintLine == CoordRange.start().line() ) + p = CoordRange.start().pos(); + if( PrintLine == CoordRange.end().line() ) + pEnd = CoordRange.end().pos()+1; + + // draw individual chars + uint e = 0; + for( ; p<pEnd; ++p, ++PrintData ) + { + // get next position + uint t = Pos[p]; + // clear spacing + T.append( whiteSpace(t-e) ); + + // print char + KHEChar B = CharCodec->decode( *PrintData ); + + T.append( B.isUndefined() ? KHEChar(UndefinedChar) : !B.isPrint() ? KHEChar(SubstituteChar) : B ); + e = t + 1; + } + + T.append( whiteSpace(NoOfCharsPerLine-e) ); + + ++PrintLine; +} diff --git a/khexedit/lib/kcharcoltextexport.h b/khexedit/lib/kcharcoltextexport.h new file mode 100644 index 0000000..05a570c --- /dev/null +++ b/khexedit/lib/kcharcoltextexport.h @@ -0,0 +1,50 @@ +/*************************************************************************** + kcharcoltextexport.h - description + ------------------- + begin : Wed Sep 3 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCHARCOLTEXTEXPORT_H +#define KHE_KCHARCOLTEXTEXPORT_H + +// lib specific +#include "khe.h" +#include "kbuffercoltextexport.h" + + +namespace KHE +{ + +class KCharColumn; +class KCharCodec; + + +class KCharColTextExport : public KBufferColTextExport +{ + public: + KCharColTextExport( const KCharColumn* BF, const char *D, KCoordRange CR, const QString &CodecName ); + virtual ~KCharColTextExport(); + + protected: //API + virtual void print( QString &T ) const; + + protected: + KCharCodec *CharCodec; + QChar SubstituteChar; + QChar UndefinedChar; +}; + +} + +#endif diff --git a/khexedit/lib/kcharcolumn.cpp b/khexedit/lib/kcharcolumn.cpp new file mode 100644 index 0000000..9ecbd5a --- /dev/null +++ b/khexedit/lib/kcharcolumn.cpp @@ -0,0 +1,61 @@ +/*************************************************************************** + kcharcolumn.cpp - description + ------------------- + begin : Mit Sep 3 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// c specific +#include <ctype.h> +// qt specific +#include <qpainter.h> +// kde specific +#include <kcharsets.h> +#include <klocale.h> +#include <kglobal.h> +// lib specific +#include "kcolumnsview.h" +#include "kbuffercursor.h" +#include "kbufferlayout.h" +#include "kbufferranges.h" +#include "kcharcolumn.h" + +using namespace KHE; + +static const bool DefaultShowUnprintable = false; +static const QChar DefaultSubstituteChar = (char)'.'; +static const QChar DefaultUndefinedChar = (char)'?'; + + +KCharColumn::KCharColumn( KColumnsView *CV, KDataBuffer *B, KBufferLayout *L, KBufferRanges *R ) + : KBufferColumn( CV, B, L, R ), + ShowUnprintable( DefaultShowUnprintable ), + SubstituteChar( DefaultSubstituteChar ), + UndefinedChar( DefaultUndefinedChar ) +{ + setSpacing( 0, 0, 0 ); +} + + +KCharColumn::~KCharColumn() +{ +} + +void KCharColumn::drawByte( QPainter *P, char /*Byte*/, KHEChar B, const QColor &Color ) const +{ + // make a drawable String out of it + QString BS( B.isUndefined() ? KHEChar(UndefinedChar) : ( !(ShowUnprintable || B.isPrint()) ? KHEChar(SubstituteChar) : B )); + + P->setPen( Color ); + P->drawText( 0, DigitBaseLine, BS ); +} diff --git a/khexedit/lib/kcharcolumn.h b/khexedit/lib/kcharcolumn.h new file mode 100644 index 0000000..1e875b0 --- /dev/null +++ b/khexedit/lib/kcharcolumn.h @@ -0,0 +1,116 @@ +/*************************************************************************** + kcharcolumn.h - description + ------------------- + begin : Mit Sep 3 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCHARCOLUMN_H +#define KHE_KCHARCOLUMN_H + +// qt specific +#include <qstring.h> +// lib specific +#include "kbuffercolumn.h" + +class QPainter; +class QColor; + + +namespace KHE +{ + + +/** buffer column that interprets the bytes as chars + * + *@author Friedrich W. H. Kossebau + */ +class KCharColumn : public KBufferColumn +{ + public: + KCharColumn( KColumnsView *CV, KDataBuffer *B, KBufferLayout *L, KBufferRanges *R ); + virtual ~KCharColumn(); + + + public: // modification access + /** sets whether "unprintable" chars (>32) should be displayed in the char column + * with their corresponding character. + * @param SU + * returns true if there was a change + */ + bool setShowUnprintable( bool SU = true ); + /** sets the substitute character for "unprintable" chars + * returns true if there was a change + */ + bool setSubstituteChar( QChar SC ); + /** sets the undefined character for "undefined" chars + * returns true if there was a change + */ + bool setUndefinedChar( QChar UC ); + + + public: // value access + /** returns true if "unprintable" chars (>32) are displayed in the char column + * with their corresponding character, default is false + */ + bool showUnprintable() const; + /** returns the actually used substitute character for "unprintable" chars, default is '.' */ + QChar substituteChar() const; + /** returns the actually used undefined character for "undefined" chars, default is '?' */ + QChar undefinedChar() const; + + + protected: // KBufferColumn API + virtual void drawByte( QPainter *P, char Byte, KHEChar B, const QColor &Color ) const; + + protected: + /** */ + bool ShowUnprintable; + /** */ + QChar SubstituteChar; + /** */ + QChar UndefinedChar; +}; + + +inline bool KCharColumn::showUnprintable() const { return ShowUnprintable; } +inline QChar KCharColumn::substituteChar() const { return SubstituteChar; } +inline QChar KCharColumn::undefinedChar() const { return UndefinedChar; } + +inline bool KCharColumn::setSubstituteChar( QChar SC ) +{ + if( SubstituteChar == SC ) + return false; + SubstituteChar = SC; + return true; +} + +inline bool KCharColumn::setUndefinedChar( QChar UC ) +{ + if( UndefinedChar == UC ) + return false; + UndefinedChar = UC; + return true; +} + +inline bool KCharColumn::setShowUnprintable( bool SU ) +{ + if( ShowUnprintable == SU ) + return false; + ShowUnprintable = SU; + return true; +} + +} + +#endif diff --git a/khexedit/lib/kcoltextexport.h b/khexedit/lib/kcoltextexport.h new file mode 100644 index 0000000..d0b3918 --- /dev/null +++ b/khexedit/lib/kcoltextexport.h @@ -0,0 +1,40 @@ +/*************************************************************************** + kcoltextexport.h - description + ------------------- + begin : Sam Aug 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCOLTEXTEXPORT_H +#define KHE_KCOLTEXTEXPORT_H + +class QString; + +namespace KHE +{ +/** + * interface for the text export of columns + * @author Friedrich W. H. Kossebau <Friedrich.W.H@Kossebau.de> + */ +class KColTextExport +{ + public: // API + virtual void printFirstLine( QString &T, int Line ) const = 0; + virtual void printNextLine( QString &T ) const = 0; + /** tells how much chars per line are needed */ + virtual int charsPerLine() const = 0; +}; + +} + +#endif diff --git a/khexedit/lib/kcolumn.cpp b/khexedit/lib/kcolumn.cpp new file mode 100644 index 0000000..f9b0ce5 --- /dev/null +++ b/khexedit/lib/kcolumn.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** + kcolumn.cpp - description + ------------------- + begin : Mit Mai 21 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qpainter.h> +// lib specific +#include "kcolumnsview.h" +#include "kcolumn.h" + +using namespace KHE; + + +KColumn::KColumn( KColumnsView *V ) + : View( V ), + Visible( true ), //TODO: would false be better? + LineHeight( V->lineHeight() ), + XSpan( 0,0,true ) +{ + V->addColumn( this ); +} + + +void KColumn::paintFirstLine( QPainter *P, KPixelXs, int /*FirstLine*/ ) +{ + paintBlankLine( P ); +} + + +void KColumn::paintNextLine( QPainter *P ) +{ + paintBlankLine( P ); +} + + +void KColumn::paintBlankLine( QPainter *P ) const +{ + if( LineHeight > 0 ) + P->fillRect( 0,0,width(),LineHeight, View->backgroundBrush() ); +} + + +void KColumn::paintEmptyColumn( QPainter *P, KPixelXs Xs, KPixelYs Ys ) +{ + Xs.restrictTo( XSpan ); + P->fillRect( Xs.start(), Ys.start(), Xs.width(), Ys.width(), View->backgroundBrush() ); +} diff --git a/khexedit/lib/kcolumn.h b/khexedit/lib/kcolumn.h new file mode 100644 index 0000000..37c3118 --- /dev/null +++ b/khexedit/lib/kcolumn.h @@ -0,0 +1,126 @@ +/*************************************************************************** + kcolumn.h - description + ------------------- + begin : Mit Mai 21 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCOLUMN_H +#define KHE_KCOLUMN_H + + +// lib specific +#include "kadds.h" +#include "ksection.h" + +class QPainter; + +namespace KHE +{ + +class KColumnsView; + +/** base class for columns of the KColumnsView + * + * + *@author Friedrich W. H. Kossebau + */ + +class KColumn +{ +// friend class KColumnsView; + public: + KColumn( KColumnsView *V ); + virtual ~KColumn() {} + + + public: // API to be reimplemented in the subclasses + /** Before an update of the columns view each column that intersects with the area to be painted + * will be called with this function. As often multiple lines of a column are affected + * for each lines the same values (like first and last char positions) might be calculated. + * This function enables a one-time-calculation for such data that must be stored in some + * class members, though. + * @param P painter variable + * @param cx + * @param cw + * @param FirstLine no of the first of the range of lines to paint + */ + virtual void paintFirstLine( QPainter *P, KPixelXs Xs, int FirstLine ); + /** the actual painting call for a column's line. + * The default implementation simply paints the background + */ + virtual void paintNextLine( QPainter *P ); + + /** */ + virtual void paintEmptyColumn( QPainter *P, KPixelXs Xs, KPixelYs Ys ); + + public: // modification access + /** sets starting point of the column */ + void setX( KPixelX NewX ); + /** sets visibily */ + void setVisible( bool V ); + /** buffer actual line height in column */ + void setLineHeight( KPixelY H ); + + public: // value access + /** left offset x in pixel */ + KPixelX x() const; + /** total width in pixel */ + KPixelX width() const; + /** right offset x in pixel */ + KPixelX rightX() const; + /** should Column be displayed? */ + bool isVisible() const; + /** convinience: returns width if visible else 0 */ + KPixelX visibleWidth() const; + + public: // functional logic + /** true if column overlaps with pixels between x-positions x1, x2 */ + bool overlaps( KPixelXs Xs ) const; + + protected: + /** sets width of the column */ + void setWidth( KPixelX W ); + /** */ + void paintBlankLine( QPainter *P ) const; + + protected: // general column data + /** pointer to the view */ + KColumnsView *View; + /** should Column be displayed? */ + bool Visible; + + /** buffered value */ + KPixelY LineHeight; + + /** left offset x in pixel */ + KPixelXs XSpan; +}; + + +inline KPixelX KColumn::x() const { return XSpan.start(); } +inline KPixelX KColumn::rightX() const { return XSpan.end(); } +inline KPixelX KColumn::width() const { return XSpan.width(); } +inline bool KColumn::isVisible() const { return Visible; } +inline KPixelX KColumn::visibleWidth() const { return Visible ? XSpan.width(): 0; } + +inline void KColumn::setX( KPixelX NewX ) { XSpan.moveToStart( NewX ); } +inline void KColumn::setWidth( KPixelX W ) { XSpan.setEndByWidth( W ); } +inline void KColumn::setVisible( bool V ) { Visible = V; } +inline void KColumn::setLineHeight( KPixelY H ) { LineHeight = H; } + +inline bool KColumn::overlaps( KPixelXs Xs ) const { return XSpan.overlaps(Xs); } + +} + +#endif diff --git a/khexedit/lib/kcolumnsview.cpp b/khexedit/lib/kcolumnsview.cpp new file mode 100644 index 0000000..1c93af8 --- /dev/null +++ b/khexedit/lib/kcolumnsview.cpp @@ -0,0 +1,236 @@ +/*************************************************************************** + kcolumnsview.cpp - description + ------------------- + begin : Mit Mai 21 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +//#include <kdebug.h> + +// qt specific +#include <qpainter.h> +// lib specific +#include "kcolumn.h" +#include "kcolumnsview.h" + + +using namespace KHE; + +static bool DefaultHorizontalGrid = false; + +KColumnsView::KColumnsView( /*bool R,*/ QWidget *Parent, const char *Name, WFlags Flags ) + : QScrollView( Parent, Name, Flags | WRepaintNoErase /*| WStaticContents*/ ), + NoOfLines( 0 ), + LineHeight( 0 ), + TotalWidth( 0 ), + HorizontalGrid( DefaultHorizontalGrid ), +// Reversed( R ), + d( 0 ) +{ + viewport()->setBackgroundMode( PaletteBase ); + setBackgroundMode( PaletteBackground, PaletteBase ); + viewport()->setFocusProxy( this ); + + Columns.setAutoDelete( true ); +} + +KColumnsView::~KColumnsView() +{ +} + + +void KColumnsView::setNoOfLines( int NewNoOfLines ) +{ + NoOfLines = NewNoOfLines; +} + + +void KColumnsView::setLineHeight( KPixelY LH ) +{ + LineHeight = LH; + for( KColumn *C=Columns.first(); C; C=Columns.next() ) + C->setLineHeight( LineHeight ); + verticalScrollBar()->setLineStep( LineHeight ); + + updateLineBufferSize(); +} + + +void KColumnsView::updateWidths() +{ + TotalWidth = 0; + for( KColumn *C=Columns.first(); C; C=Columns.next() ) + { + C->setX( TotalWidth ); + TotalWidth += C->visibleWidth(); + } + + updateLineBufferSize(); +} + + +void KColumnsView::updateLineBufferSize() +{ + int w = totalWidth(); + int h = LineHeight; + + if( w != LineBuffer.width() || h != LineBuffer.height() ) + LineBuffer.resize( w, h ); +} + + +int KColumnsView::noOfLinesPerPage() const +{ + if( !viewport() || LineHeight == 0 ) + return 1; +// int NoOfLinesPerPage = (visibleHeight()-1) / LineHeight; // -1 ensures to get always the last visible line + int NoOfLinesPerPage = (viewport()->height()-1) / LineHeight; // -1 ensures to get always the last visible line + + if( NoOfLinesPerPage == 0 ) + // ensure to move down at least one line + NoOfLinesPerPage = 1; + return NoOfLinesPerPage; +} + + +void KColumnsView::addColumn( KColumn *C ) +{ +// if( Reversed ) +// Columns.prepend( C ); +// else + Columns.append( C ); + + updateWidths(); +} + + +void KColumnsView::removeColumn( KColumn *C ) +{ + Columns.remove( C ); + + updateWidths(); +} + + +void KColumnsView::updateView() +{ + resizeContents( totalWidth(), totalHeight() ); + updateContents(); +} + + +void KColumnsView::repaintView() +{ + resizeContents( totalWidth(), totalHeight() ); + repaintContents( false ); +} + + +void KColumnsView::paintEmptyArea( QPainter *P, int cx ,int cy, int cw, int ch) +{ + P->fillRect( cx, cy, cw, ch, backgroundBrush() ); +} + + +void KColumnsView::drawContents( QPainter *P, int cx, int cy, int cw, int ch ) +{ + //kdDebug(1501) << "drawContents(" << cx<<","<<cw<<"#"<<cy<<","<<ch<<")\n"; + KPixelXs AffectedXs( cx, cw, true ); + // content to be shown? + if( AffectedXs.startsBefore(TotalWidth) ) + { + KPixelYs AffectedYs( cy, ch, true ); + + // collect affected columns + QPtrList<KColumn> RedrawColumns; + for( KColumn *C=Columns.first(); C; C=Columns.next() ) + if( C->isVisible() && C->overlaps(AffectedXs) ) + RedrawColumns.append( C ); + + // any lines to be drawn? + if( NoOfLines > 0 ) + { + // calculate affected lines + KSection AffectedLines = visibleLines( AffectedYs ); + AffectedLines.restrictEndTo( NoOfLines - 1 ); + + if( AffectedLines.isValid() ) + { + QPainter Paint; + Paint.begin( &LineBuffer, this ); + + // starting painting with the first line + KColumn *C = RedrawColumns.first(); + Paint.translate( C->x(), 0 ); + + for( ; C; C=RedrawColumns.next() ) + { + C->paintFirstLine( &Paint, AffectedXs, AffectedLines.start() ); + Paint.translate( C->width(), 0 ); + } + + // Go through the other lines + KPixelY y = AffectedLines.start() * LineHeight; + int l = AffectedLines.start(); + while( true ) + { + Paint.end(); + P->drawPixmap( cx, y, LineBuffer, cx, 0, cw, LineHeight ); // bitBlt directly impossible: lack of real coord + + // copy to screen +// bitBlt( viewport(), cx - contentsX(), y - contentsY(), +// &LineBuffer, cx, 0, cw, LineHeight ); + + ++l; + y += LineHeight; + + if( l > AffectedLines.end() ) + break; + + // to avoid flickers we first paint to the linebuffer + Paint.begin( &LineBuffer, this ); + + KColumn *C = RedrawColumns.first(); + Paint.translate( C->x(), 0 ); + + for( ; C; C=RedrawColumns.next() ) + { + C->paintNextLine( &Paint ); + Paint.translate( C->width(), 0 ); + } + + if( HorizontalGrid && cx < TotalWidth ) + Paint.drawLine( cx, LineHeight-1, TotalWidth-1, LineHeight-1 ); // TODO: use a additional TotalHeight? + } + } + } + + // draw empty columns? + AffectedYs.setStart( totalHeight() ); + if( AffectedYs.isValid() ) + { + for( KColumn *C = RedrawColumns.first(); C; C=RedrawColumns.next() ) + C->paintEmptyColumn( P, AffectedXs, AffectedYs ); + } + } + + // Paint empty rects + AffectedXs.setStart( TotalWidth ); + if( AffectedXs.isValid() ) + paintEmptyArea( P, AffectedXs.start(), cy, AffectedXs.width(), ch ); +} + +// Implemented to get rid of a compiler warning +void KColumnsView::drawContents( QPainter * ) {} + +#include "kcolumnsview.moc" diff --git a/khexedit/lib/kcolumnsview.h b/khexedit/lib/kcolumnsview.h new file mode 100644 index 0000000..aa3521d --- /dev/null +++ b/khexedit/lib/kcolumnsview.h @@ -0,0 +1,168 @@ +/*************************************************************************** + kcolumnsview.h - description + ------------------- + begin : Mit Mai 21 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCOLUMNSVIEW_H +#define KHE_KCOLUMNSVIEW_H + +// qt specific +#include <qptrlist.h> +#include <qwidget.h> +#include <qpixmap.h> +#include <qscrollview.h> +// lib specific +#include "kadds.h" +#include "ksection.h" // TODO: think about moving this out of the public API + +namespace KHE +{ + +class KColumn; +class KColumnsViewPrivate; + +/** general class for widgets with columns that display different aspects of the same data + * with the same lineheight for all lines + * + *@author Friedrich W. H. Kossebau + */ + +class KColumnsView : public QScrollView +{ + Q_OBJECT + + friend class KColumn; + + public: + KColumnsView( /*bool R = false,*/ QWidget *parent=0, const char *name=0, WFlags Flags=0 ); + virtual ~KColumnsView(); + + public: // drawing + virtual void paintEmptyArea( QPainter *p, int cx, int cy, int cw, int ch ); + virtual void drawContents( QPainter *p, int cx, int cy, int cw, int ch ); + + public: // data-wise sizes + /** returns the number of all lines */ + int noOfLines() const; + /** returns number of fully visible lines, at least 1 (as needed by page down/up) + * doesn't care about the total height being smaller than the display height + */ + int noOfLinesPerPage() const; + + public: // pixel-wise sizes + /** returns the height of each line */ + KPixelY lineHeight() const; + /** returns the size of all visible columns together */ + QSize totalViewSize() const; + /** returns the width of all visible columns together */ + KPixelX totalWidth() const; + /** returns the height of all lines together */ + KPixelY totalHeight() const; + + public: // services + /** gives the index of the line that would include y in pixel coord. + * y is not forced to be inside the total height. + */ + uint lineAt( KPixelY y ) const; + /** gives the index of the first and the last line that would be visible + * these lines might not contain anything + */ + KSection visibleLines() const; + /** gives the index of the first and the last line that would be visible in the given pixel range + * these lines might not contain anything + */ + KSection visibleLines( KPixelYs YPixels ) const; + + + protected: + /** called by KColumn */ + void addColumn( KColumn *C ); + void removeColumn( KColumn *C ); + + + protected: // + /** sets height of all lines and propagates this information to all columns + * doesn't update the content size + * @param NewLineHeight height in pixels + */ + virtual void setLineHeight( KPixelY NewLineHeight ); + /** sets the number of lines + * doesn't update the content size + * @param NewNoOfLines new number of lines to display + */ + virtual void setNoOfLines( int NewNoOfLines ); + + protected: // recalculations + /** recalculates the positions of the columns and the total width */ + void updateWidths(); + /** ensures that the line buffer has the size of the whole line */ + void updateLineBufferSize(); + + protected: // painting + void updateView(); + void repaintView(); + + private: + /** hiding it*/ + void drawContents( QPainter* ); + + + protected: // calculated + /** collection of all the columns. All columns will be autodeleted. */ + QPtrList<KColumn> Columns; + /** the number of lines which the column view has */ + int NoOfLines; + /** the height of each line in pixels */ + KPixelY LineHeight; + /** the width of all visible columns together */ + KPixelX TotalWidth; +// /** width that is used by columns that are not resizeable (if shown) */ +// KPixelX ReservedWidth; + + protected: + // TODO: do we really want this? + bool HorizontalGrid; + /** Buffer where each line is drawn to before it is copied onto the screen */ + QPixmap LineBuffer; +// bool Reversed; + + private: + KColumnsViewPrivate *d; +}; + + +inline int KColumnsView::noOfLines() const { return NoOfLines; } +inline KPixelY KColumnsView::lineHeight() const { return LineHeight; } +inline uint KColumnsView::lineAt( KPixelY y ) const { return LineHeight!=0 ? y / LineHeight : 0; } +inline KSection KColumnsView::visibleLines() const +{ + KPixelY cy = contentsY(); + KPixelY ch = visibleHeight(); + return KSection( lineAt(cy), lineAt(cy+ch-1) ); +} + +inline KSection KColumnsView::visibleLines( KPixelYs YPixels ) const +{ + return KSection( lineAt(YPixels.start()), lineAt(YPixels.end()) ); +} + +inline KPixelY KColumnsView::totalHeight() const { return NoOfLines*LineHeight; } +inline KPixelX KColumnsView::totalWidth() const { return TotalWidth; } + +inline QSize KColumnsView::totalViewSize() const { return QSize( totalWidth(), totalHeight() ); } + +} + +#endif diff --git a/khexedit/lib/kcoordrange.h b/khexedit/lib/kcoordrange.h new file mode 100644 index 0000000..0d5b186 --- /dev/null +++ b/khexedit/lib/kcoordrange.h @@ -0,0 +1,95 @@ +/*************************************************************************** + kcoordrange.h - description + ------------------- + begin : Sun 03.08.2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de +****************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCOORDRANGE_H +#define KHE_KCOORDRANGE_H + +// lib specific +#include "krange.h" +#include "kbuffercoord.h" +#include "ksection.h" + +namespace KHE +{ + +template<> +inline const KBufferCoord KRange<KBufferCoord>::null() const { return KBufferCoord(-1,-1);} + +typedef KRange<KBufferCoord> KBasicCoordRange; + +/** describes a range in the buffercoord + *@author Friedrich W. H. Kossebau + */ +class KCoordRange : public KRange<KBufferCoord> +{ + public: + /** + * @param SC start coord + * @param EC end coord + */ + KCoordRange( KBufferCoord SC, KBufferCoord EC ); + /** + * @param Pos start and end pos + * @param Lines start and end line + */ + KCoordRange( KSection Pos, KSection Lines ); + KCoordRange(); + ~KCoordRange(); + + public: + KCoordRange &operator=( const KCoordRange &S ); + + public: + bool operator==( const KCoordRange &S ) const; + + public: + /** calculates the number of coords that are covered if a line has the given length. + * If the range is invalid the behaviour is undefined. + * @param LineLength + * @return the number of points covered if a line has a length of LineLength. + */ + int width( int LineLength ) const; + /** calculates the number of lines that are covered by the range. + * If the range is invalid the behaviour is undefined. + * @return number of lines covered + */ + int lines() const; + /** tests if the given line is included by the range. + * If the range is invalid or the line < 0 the behaviour is undefined. + * @param Line index of line + * @return @c true if Line is included, otherwise @c false + */ + bool includesLine( int Line ) const; +}; + + +inline KCoordRange::KCoordRange( KBufferCoord SC, KBufferCoord EC ) : KBasicCoordRange(SC,EC) {} +inline KCoordRange::KCoordRange( KSection Pos, KSection Lines ) + : KBasicCoordRange( KBufferCoord(Pos.start(),Lines.start()), KBufferCoord(Pos.end(),Lines.end()) ) {} +inline KCoordRange::KCoordRange() {} +inline KCoordRange::~KCoordRange() {} + +inline bool KCoordRange::operator==( const KCoordRange &R ) const { return KBasicCoordRange::operator==(R); } + +inline KCoordRange &KCoordRange::operator=( const KCoordRange &R ) { KBasicCoordRange::operator=(R); return *this; } + +inline int KCoordRange::width( int LineLength ) const { return LineLength*(lines()-1) + End.pos() - Start.pos()+1; } +inline int KCoordRange::lines() const { return End.line() - Start.line() + 1; } +inline bool KCoordRange::includesLine( int Line ) const { return Line >= Start.line() && Line <= End.line(); } +} + +#endif diff --git a/khexedit/lib/kcoordrangelist.cpp b/khexedit/lib/kcoordrangelist.cpp new file mode 100644 index 0000000..3028c7d --- /dev/null +++ b/khexedit/lib/kcoordrangelist.cpp @@ -0,0 +1,78 @@ +/*************************************************************************** + kcoordrangelist.cpp - description + ------------------- + begin : Mon Jun 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kcoordrangelist.h" + +using namespace KHE; + +KCoordRangeList::KCoordRangeList() +{ +} + + +KCoordRangeList::~KCoordRangeList() +{ +} + + +void KCoordRangeList::addCoordRange( KCoordRange NewCoordRange ) +{ + if( !NewCoordRange.isValid() ) + return; + // we try to insert it by ascending indizes + // if sections are overlapping we combine them + iterator S = begin(); + for( ; S!=end(); ++S ) + { + // is next CoordRange behind the new CoordRange? + if( NewCoordRange.endsBefore(*S) ) + { + // put the new before it + insert( S, NewCoordRange ); + return; + } + + // does the next CoordRange overlap? + if( (*S).overlaps(NewCoordRange) ) + { + // Start of the combined sections is the smaller one + NewCoordRange.extendStartTo( (*S).start() ); + // next we search all the overlapping sections and keep the highest end index + KBufferCoord End((*S).end()); + iterator LS = S; + for( ++LS; LS!=end(); ++LS ) + { + if( !(*LS).overlaps(NewCoordRange) ) + break; + End = (*LS).end(); + } + // the higher end is the end of the combined CoordRange + NewCoordRange.extendEndTo( End ); + // remove all overlapping sections + S = erase( S, LS ); + // and instead insert the combined one + insert( S, NewCoordRange ); + return; + } + } + + // all others are before the new? + if( S == end() ) + // add it at the end + append( NewCoordRange ); +} diff --git a/khexedit/lib/kcoordrangelist.h b/khexedit/lib/kcoordrangelist.h new file mode 100644 index 0000000..187ec7f --- /dev/null +++ b/khexedit/lib/kcoordrangelist.h @@ -0,0 +1,44 @@ +/*************************************************************************** + kcoordrangelist.h - description + ------------------- + begin : Wed Aug 13 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCOORDRANGELIST_H +#define KHE_KCOORDRANGELIST_H + +// qt specific +#include <qvaluelist.h> +// lib specific +#include "kcoordrange.h" + +namespace KHE { + +typedef QValueList<KCoordRange> KCoordRangeBasicList; +/** +@author Friedrich W. H. Kossebau +*/ +class KCoordRangeList : public KCoordRangeBasicList +{ + public: + KCoordRangeList(); + ~KCoordRangeList(); + + public: + void addCoordRange( KCoordRange S ); +}; + +} + +#endif diff --git a/khexedit/lib/kcursor.cpp b/khexedit/lib/kcursor.cpp new file mode 100644 index 0000000..3150751 --- /dev/null +++ b/khexedit/lib/kcursor.cpp @@ -0,0 +1,49 @@ +/*************************************************************************** + kcursor.cpp - description + ------------------- + begin : Mit Jun 26 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#include "kcursor.h" + +using namespace KHE; + +KCursor::KCursor() +: CursorX( 0 ), + CursorW( -1 ) +{ +} + + +KCursor::~KCursor() +{ +} + + + +void KCursor::setSize( KPixelX Width, KPixelY Height ) +{ + if( Width != OnPixmap.width() || Height != OnPixmap.height() ) + { + OnPixmap.resize( Width, Height ); + OffPixmap.resize( Width, Height ); + } +} + + +void KCursor::setShape( KPixelX X, KPixelX W ) +{ + CursorX = X; + CursorW = W; +} diff --git a/khexedit/lib/kcursor.h b/khexedit/lib/kcursor.h new file mode 100644 index 0000000..428c7ed --- /dev/null +++ b/khexedit/lib/kcursor.h @@ -0,0 +1,68 @@ +/*************************************************************************** + kbuffercolumn.h - description + ------------------- + begin : Mit Jun 26 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KCURSOR_H +#define KHE_KCURSOR_H + + +#include <qpixmap.h> + +#include "kadds.h" + +namespace KHE +{ + +/** + *@author Friedrich W. H. Kossebau + */ +class KCursor +{ + public: + KCursor(); + virtual ~KCursor(); + + public: + /** sets size of the full cursor */ + void setSize( KPixelX Width, KPixelY Height ); + /** sets the shape of the cursor to be drawn */ + void setShape( KPixelX X, KPixelX W ); + + public: // access + const QPixmap &onPixmap() const; + const QPixmap &offPixmap() const; + KPixelX cursorX() const; + KPixelX cursorW() const; + + + protected: + QPixmap OnPixmap; + QPixmap OffPixmap; + + KPixelX CursorX; + KPixelX CursorW; +}; + + +inline const QPixmap &KCursor::onPixmap() const { return OnPixmap; } +inline const QPixmap &KCursor::offPixmap() const { return OffPixmap; } + +inline KPixelX KCursor::cursorX() const { return CursorX; } +inline KPixelX KCursor::cursorW() const { return CursorW; } + +} + +#endif diff --git a/khexedit/lib/kdatabuffer.cpp b/khexedit/lib/kdatabuffer.cpp new file mode 100644 index 0000000..054d792 --- /dev/null +++ b/khexedit/lib/kdatabuffer.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + kdatabuffer.cpp - description + ------------------- + begin : Fri Aug 01 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// c specific +#include <ctype.h> +// lib specific +#include "kdatabuffer.h" + +using namespace KHE; + + +int KDataBuffer::insert( int Pos, const char* D, int Length ) +{ + return replace( Pos,0,D,Length ); +} + + +int KDataBuffer::remove( KSection Remove ) +{ + replace( Remove, 0, 0 ); + return Remove.width(); // TODO: check if this is true +} + +int KDataBuffer::copyTo( char* Dest, int Pos, int Length ) const +{ + return copyTo( Dest, KSection(Pos,Length,false) ); +} + + + +int KDataBuffer::copyTo( char* Dest, KSection Source ) const +{ + Source.restrictEndTo( size()-1 ); + for( int i=Source.start(); i<=Source.end(); ++i ) + *Dest++ = datum( i ); + return Source.width(); +} diff --git a/khexedit/lib/kdatabuffer.h b/khexedit/lib/kdatabuffer.h new file mode 100644 index 0000000..e9733d8 --- /dev/null +++ b/khexedit/lib/kdatabuffer.h @@ -0,0 +1,246 @@ +/*************************************************************************** + kdatabuffer.h - description + ------------------- + begin : Mit Mai 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KDATABUFFER_H +#define KHE_KDATABUFFER_H + + +// lib specific +#include "ksection.h" +#include "khexedit_export.h" + +namespace KHE +{ + +/** could it be useful to hide the data access behind an iterator? * +class KDataBufferIterator +{ + public: + bool hasNext(); + char next(); + protected: + + protected: + char * + int Length; +} + +bool KDataBufferIterator::hasNext() +{ +} +// this function should be simple as possible +char KDataBufferIterator::next() +{ + // if next span is empty + if( ) + return *NextChar++; +} +*/ +/** base class for all Data buffers that are used to display + * TODO: think about a way to inform KHexEdit that there has been + * a change in the buffer outside. what kind of changes are possible? + * + * Operations on the data: + * + * Finding: is implemented stateless. FindNext has to be done by perhaps a FindManager + * Replacing: not available. Implement within a ReplaceManager + * + *@author Friedrich W. H. Kossebau + */ + +class KHEXEDIT_EXPORT KDataBuffer +{ + friend class KDataBufferIterator; + + + protected: + KDataBuffer(); + public: + virtual ~KDataBuffer(); + + + public: // data access API + /** locates working range + * The idea behind is to tell buffer which range will be requested in the following time, + * so that e.g. the corresponding pages will be loaded in advance + * TODO: do we really need this? Where will this lead to real enhancements? + * @param Range + * @return @c true if successfull, @c false otherwise + */ + virtual bool prepareRange( KSection Range ) const = 0; + /** convenience function, same as above */ + bool prepareRange( int Offset, int Length ) const; + + /** creates an iterator to */ + //virtual KDataBufferIterator *iterator() const = 0; + /** expects pointer to memory, should be in prepared range + * it is only expected to be a valid pointer until any further call + * to this or any modifying function + * @param Section + * @return pointer to + */ + virtual const char *dataSet( KSection Section ) const = 0; + /** convenience function, same as above */ + const char *dataSet( int Offset, int Length ) const; + + /** requests a single byte + * if the offset is not valid the behaviout is undefined + * @param Offset offset of the datum requested + */ + virtual char datum( unsigned int Offset ) const = 0; + + /** + * @return the size of the data + */ + virtual int size() const = 0; + + + public: // state read API + /** + * @return @c true if the buffer can only be read, @c false if writing is allowed + */ + virtual bool isReadOnly() const; + /** + * @return @c true if the buffer has been modified, @c false otherwise + */ + virtual bool isModified() const = 0; + + + public: // modification API + /** inserts bytes copied from the given source at Position. + * The original data beginnung at the position is moved + * with the buffer enlarged as needed + * If the buffer is readOnly this is a noop and returns 0. + * @param Pos + * @param Source data source + * @param SourceLength number of bytes to copy + * @return length of inserted data + */ + virtual int insert( int Pos, const char* Source, int SourceLength ); + + /** removes beginning with position as much as possible + * @param Section + * @return length of removed data + */ + virtual int remove( KSection Section ); + /** convenience function, behaves as above */ + int remove( int Pos, int Length ); + + /** replaces as much as possible + * @param DestSection + * @param Source + * @param SourceLength + * @return length of replacced data + */ + virtual unsigned int replace( KSection DestSection, const char* Source, unsigned int SourceLength ) = 0; + /** convenience function, behaves as above */ + unsigned int replace( unsigned int Pos, unsigned int RemoveLength, + const char* Source, unsigned int SourceLength ); + + /** moves a part of the data to a new position, while floating the other data around + * when moving to a higher place the length of the block must be taken into account + * if the new positions extend beyond the buffers end the section is moved to the end. + * @param DesPos position of the data where the section should be moved behind + * @param SourceSection data section to be moved + * @return new pos of moved data or old, if failed + */ + virtual int move( int DestPos, KSection SourceSection ) = 0; + + /** + * fills the buffer with the FillChar. If the buffer is to small it will be extended as much as possible. + * @param FillChar char to use + * @param Length number of chars to fill. If Length is -1, the current buffer length is used. + * @param Pos position where the filling starts + * @return number of filled characters + */ + virtual int fill( const char FillChar, int Length = -1, unsigned int Pos = 0 ) = 0; + + /** sets a single byte + * if the offset is not valid the behaviour is undefined + * @param Offset offset of the datum requested + * @param Char new byte value + */ + virtual void setDatum( unsigned int Offset, const char Char ) = 0; + + /** sets the modified flag for the buffer + * @param M + */ + virtual void setModified( bool M ) = 0; + + + public: // service functions + /** copies the data of the section into a given array Dest. If the section extends the buffers range + * the section is limited to the buffer's end. If the section is invalid the behaviour is undefined. + * @param Dest pointer to a char array large enough to hold the copied section + * @param Source + * @return number of copied bytes + */ + virtual int copyTo( char* Dest, KSection Source ) const; + /** convenience function, behaves as above */ + int copyTo( char* Dest, int Pos, int n ) const; + + + public: // finding API + /** searches beginning with byte at Pos. + * @param + * @param Length length of search string + * @param Pos the position to start the search + * @return index of the first or -1 + */ + //virtual int find( const char*, int Length, int Pos = 0 ) const = 0; + /** searches for a given data string + * The section limits the data within which the key has to be found + * If the end of the section is lower then the start the search continues at the start??? + * @param + * @param Length length of search string + * @param Section section within the keydata is to be found + * @return index of the first occurence or -1 + */ + virtual int find( const char*KeyData, int Length, KSection Section ) const = 0; + /** searches backward beginning with byte at Pos. + * @param + * @param Length length of search string + * @param Pos the position to start the search. If -1 the search starts at the end. + * @return index of the first or -1 + */ + virtual int rfind( const char*, int Length, int Pos = -1 ) const = 0; + +/* virtual int find( const QString &expr, bool cs, bool wo, bool forward = true, int *index = 0 ); */ +}; + + +inline KDataBuffer::KDataBuffer() {} +inline KDataBuffer::~KDataBuffer() {} + +inline bool KDataBuffer::prepareRange( int Offset, int Length ) const +{ return prepareRange( KSection(Offset,Offset+Length-1) ); } + +inline const char *KDataBuffer::dataSet( int Offset, int Length ) const +{ return dataSet( KSection(Offset,Offset+Length-1) ); } + +inline int KDataBuffer::remove( int Pos, int Length ) +{ return remove( KSection(Pos,Pos+Length-1) ); } + +inline unsigned int KDataBuffer::replace( unsigned int Pos, unsigned int RemoveLength, + const char* D, unsigned int InputLength ) +{ return replace( KSection(Pos,Pos+RemoveLength-1), D, InputLength ); } + +inline bool KDataBuffer::isReadOnly() const { return false; } + +} + +#endif diff --git a/khexedit/lib/kfixedsizebuffer.cpp b/khexedit/lib/kfixedsizebuffer.cpp new file mode 100644 index 0000000..2945620 --- /dev/null +++ b/khexedit/lib/kfixedsizebuffer.cpp @@ -0,0 +1,272 @@ +/*************************************************************************** + kfixedsizebuffer.cpp - description + ------------------- + begin : Mit Jun 03 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + +//#include <kdebug.h> +// c specific +#include <string.h> +// lib specific +#include "kfixedsizebuffer.h" + +using namespace KHE; + +KFixedSizeBuffer::KFixedSizeBuffer( char *D, unsigned int S, char FUC ) + : Data( D ), + Size( S ), + FillUpChar( FUC ), + ReadOnly( true ), + Modified( false ), + AutoDelete( false ) +{ +} + +KFixedSizeBuffer::KFixedSizeBuffer( unsigned int S, char FUC ) + : Data( new char[S] ), + Size( S ), + FillUpChar( FUC ), + ReadOnly( false ), + Modified( false ), + AutoDelete( true ) +{ + reset( 0, S ); +} + +KFixedSizeBuffer::~KFixedSizeBuffer() +{ + if( AutoDelete ) + delete [] Data; +} + + + +int KFixedSizeBuffer::insert( int Pos, const char* D, int InputLength ) +{ + // check all parameters + if( Pos >= (int)Size || InputLength == 0 ) + return 0; + if( Pos + InputLength > (int)Size ) + InputLength = Size - Pos; + + unsigned int BehindInsertPos = Pos + InputLength; + // fmove right data behind the input range + memmove( &Data[BehindInsertPos], &Data[Pos], Size-BehindInsertPos ); + // insert input + memcpy( &Data[Pos], D, InputLength ); + + Modified = true; + return InputLength; +} + + +int KFixedSizeBuffer::remove( KSection Remove ) +{ + if( Remove.start() >= (int)Size || Remove.width() == 0 ) + return 0; + + Remove.restrictEndTo( Size-1 ); + + int RemoveLength = Remove.width(); + int BehindRemovePos = Remove.end()+1;; + // fmove right data behind the input range + memmove( &Data[Remove.start()], &Data[BehindRemovePos], Size-BehindRemovePos ); + // clear freed space + reset( Size-RemoveLength, RemoveLength ); + + Modified = true; + return RemoveLength; +} + + +unsigned int KFixedSizeBuffer::replace( KSection Remove, const char* D, unsigned int InputLength ) +{ + // check all parameters + if( Remove.startsBehind( Size-1 ) || (Remove.width()==0 && InputLength==0) ) + return 0; + + Remove.restrictEndTo( Size-1 ); + if( Remove.start() + InputLength > Size ) + InputLength = Size - Remove.start(); + + int SizeDiff = InputLength - Remove.width(); + + // is input longer than removed? + if( SizeDiff > 0 ) + { + unsigned int BehindInsertPos = Remove.start() + InputLength; + // fmove right data behind the input range + memmove( &Data[BehindInsertPos], &Data[Remove.end()+1], Size-BehindInsertPos ); + } + // is input smaller than removed? + else if( SizeDiff < 0 ) + { + unsigned int BehindRemovePos = Remove.end()+1; + // fmove right data behind the input range + memmove( &Data[Remove.start()+InputLength], &Data[BehindRemovePos], Size-BehindRemovePos ); + // clear freed space + reset( Size+SizeDiff, -SizeDiff ); + } + // insert input + memcpy( &Data[Remove.start()], D, InputLength ); + + Modified = true; + return InputLength; +} + + +int KFixedSizeBuffer::move( int DestPos, KSection SourceSection ) +{ + // check all parameters + if( SourceSection.start() >= (int)Size || SourceSection.width() == 0 + || DestPos > (int)Size || SourceSection.start() == DestPos ) + return SourceSection.start(); + + SourceSection.restrictEndTo( Size-1 ); + bool ToRight = DestPos > SourceSection.start(); + int MovedLength = SourceSection.width(); + int DisplacedLength = ToRight ? DestPos - SourceSection.end()-1 : SourceSection.start() - DestPos; + + // find out section that is smaller + int SmallPartLength, LargePartLength, SmallPartStart, LargePartStart, SmallPartDest, LargePartDest; + // moving part is smaller? + if( MovedLength < DisplacedLength ) + { + SmallPartStart = SourceSection.start(); + SmallPartLength = MovedLength; + LargePartLength = DisplacedLength; + // moving part moves right? + if( ToRight ) + { + SmallPartDest = DestPos - MovedLength; + LargePartStart = SourceSection.end()+1; + LargePartDest = SourceSection.start(); + } + else + { + SmallPartDest = DestPos; + LargePartStart = DestPos; + LargePartDest = DestPos + MovedLength; + } + } + else + { + LargePartStart = SourceSection.start(); + LargePartLength = MovedLength; + SmallPartLength = DisplacedLength; + // moving part moves right? + if( ToRight ) + { + LargePartDest = DestPos - MovedLength; + SmallPartStart = SourceSection.end()+1; + SmallPartDest = SourceSection.start(); + } + else + { + LargePartDest = DestPos; + SmallPartStart = DestPos; + SmallPartDest = DestPos + MovedLength; + } + } + + // copy smaller part to tempbuffer + char *Temp = new char[SmallPartLength]; + memcpy( Temp, &Data[SmallPartStart], SmallPartLength ); + + // move the larger part + memmove( &Data[LargePartDest], &Data[LargePartStart], LargePartLength ); + + // copy smaller part to its new dest + memcpy( &Data[SmallPartDest], Temp, SmallPartLength ); + delete [] Temp; + + Modified = true; + return MovedLength < DisplacedLength ? SmallPartDest : LargePartDest; +} + + +int KFixedSizeBuffer::fill( const char FChar, int FillLength, unsigned int Pos ) +{ + // nothing to fill + if( Pos >= Size ) + return 0; + + unsigned int LengthToEnd = Size - Pos; + + if( FillLength < 0 || FillLength > (int)LengthToEnd ) + FillLength = LengthToEnd; + + memset( &Data[Pos], FChar, FillLength ); + Modified = true; + return FillLength; +} + + +int KFixedSizeBuffer::compare( const KDataBuffer &Other, KSection OtherRange, unsigned int Pos ) +{ + //kdDebug() << QString("Pos: %1, OtherRange: (%3/%4)" ).arg(Pos).arg(OtherRange.start()).arg(OtherRange.end()) + // << endl; + // test other values + if( OtherRange.startsBehind(Other.size()-1) ) + return 1; + + // check own values + if( Pos >= Size ) + return -1; + + int ValueByLength = 0; // default: equal + + KSection Range( Pos, OtherRange.width(), true ); + int Last = Other.size()-1; + // + if( OtherRange.endsBehind(Last) ) + { + // make shorter + OtherRange.setEnd( Last ); + if( OtherRange.width() < Range.width() ) + ValueByLength = 1; + } + Last = Size-1; + if( Range.endsBehind(Last) ) + { + // make shorter + Range.setEnd( Last ); + if( OtherRange.width() > Range.width() ) + ValueByLength = -1; + } + //kdDebug() + // << QString( "Range: (%1/%2), OtherRange: (%3/%4)" ).arg(Range.start()).arg(Range.end()).arg(OtherRange.start()).arg(OtherRange.end()) + // << endl; + int oi = OtherRange.start(); + for( int i=Range.start(); i<=Range.end(); ++i,++oi ) + { + char OD = Other.datum(oi); + char D = Data[i]; + //kdDebug() << QString("%1==%2").arg((int)D).arg((int)OD) << endl; + if( OD == D ) + continue; + return OD < D ? 1 : -1; + } + + return ValueByLength; +} + + +int KFixedSizeBuffer::find( const char*/*KeyData*/, int /*Length*/, KSection /*Section*/ ) const { return 0; } +int KFixedSizeBuffer::rfind( const char*, int /*Length*/, int /*Pos*/ ) const { return 0; } + + +void KFixedSizeBuffer::reset( unsigned int Pos, unsigned int Length ) +{ + memset( &Data[Pos], FillUpChar, Length ); +} diff --git a/khexedit/lib/kfixedsizebuffer.h b/khexedit/lib/kfixedsizebuffer.h new file mode 100644 index 0000000..15c17da --- /dev/null +++ b/khexedit/lib/kfixedsizebuffer.h @@ -0,0 +1,116 @@ +/*************************************************************************** + kfixedsizebuffer.h - description + ------------------- + begin : Mit Jun 03 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KFIXEDSIZEBUFFER_H +#define KHE_KFIXEDSIZEBUFFER_H + +#include "kdatabuffer.h" + +namespace KHE +{ + +/** base class for all Data buffers that are used to display + * TODO: think about a way to inform KHexEdit that there has been + * a change in the buffer outside. what kind of changes are possible? + *@author Friedrich W. H. Kossebau + */ + +class KFixedSizeBuffer : public KDataBuffer +{ + public: + /** creates a readonly buffer around the given data */ + KFixedSizeBuffer( char *D, unsigned int S, char FUC = '\0' ); + /** creates a writeable buffer which is deleted at the end */ + KFixedSizeBuffer( unsigned int S, char FUC = '\0' ); + virtual ~KFixedSizeBuffer(); + + public: // KDataBuffer API + virtual bool prepareRange( KSection Range ) const; + virtual const char *dataSet( KSection S ) const; + virtual char datum( unsigned int Offset ) const; + virtual int size() const; + virtual bool isReadOnly() const; + virtual bool isModified() const; + + virtual int insert( int Pos, const char*, int Length ); + virtual int remove( KSection Remove ); + virtual unsigned int replace( KSection Remove, const char*, unsigned int InputLength ); + virtual int move( int DestPos, KSection SourceSection ); + virtual int fill( const char FillChar, int Length = -1, unsigned int Pos = 0 ); + virtual void setDatum( unsigned int Offset, const char Char ); + + virtual void setModified( bool M = true ); + + virtual int find( const char*KeyData, int Length, KSection Section ) const; + virtual int rfind( const char*, int Length, int Pos = -1 ) const; + +/* virtual int find( const QString &expr, bool cs, bool wo, bool forward = true, int *index = 0 ); */ + + public: + void setReadOnly( bool RO = true ); + int compare( const KDataBuffer &Other, KSection Range, unsigned int Pos = 0 ); + int compare( const KDataBuffer &Other, int OtherPos, int Length, unsigned int Pos = 0 ); + int compare( const KDataBuffer &Other ); + + public: + char *rawData() const; + + protected: + void reset( unsigned int Pos, unsigned int Length ); + + protected: + /** */ + char *Data; + /***/ + unsigned int Size; + /** */ + char FillUpChar; + /** */ + bool ReadOnly:1; + /** */ + bool Modified:1; + /** */ + bool AutoDelete:1; +}; + + +inline bool KFixedSizeBuffer::prepareRange( KSection ) const { return true; } +inline const char *KFixedSizeBuffer::dataSet( KSection S ) const { return &Data[S.start()]; } + +inline char KFixedSizeBuffer::datum( unsigned int Offset ) const { return Data[Offset]; } +inline int KFixedSizeBuffer::size() const { return Size; } + +inline void KFixedSizeBuffer::setDatum( unsigned int Offset, const char Char ) +{ Data[Offset] = Char; Modified = true; } + +inline bool KFixedSizeBuffer::isReadOnly() const { return ReadOnly; } +inline bool KFixedSizeBuffer::isModified() const { return Modified; } + +inline void KFixedSizeBuffer::setReadOnly( bool RO ) { ReadOnly = RO; } +inline void KFixedSizeBuffer::setModified( bool M ) { Modified = M; } + +inline int KFixedSizeBuffer::compare( const KDataBuffer &Other ) +{ return compare( Other, KSection(0,Other.size()-1),0 ); } + +inline int KFixedSizeBuffer::compare( const KDataBuffer &Other, int OtherPos, int Length, unsigned int Pos ) +{ return compare( Other, KSection(OtherPos,Length,true),Pos ); } + +inline char *KFixedSizeBuffer::rawData() const { return Data; } + +} + +#endif diff --git a/khexedit/lib/khe.h b/khexedit/lib/khe.h new file mode 100644 index 0000000..af029ea --- /dev/null +++ b/khexedit/lib/khe.h @@ -0,0 +1,95 @@ +/*************************************************************************** + khe.h - description + ------------------- + begin : Mon Jul 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KHE_H +#define KHE_KHE_H + +// here we collect all general data +// let's see how much it gets ;) + +namespace KHE +{ + enum KCoding { HexadecimalCoding=0, DecimalCoding=1, OctalCoding=2, BinaryCoding=3, MaxCodingId=0xFFFF }; + static const int NoOfCodings = 4; + + /** */ + enum KEncoding + { + /** the coding of your shell */ + LocalEncoding=0, + /** ASCII encoding, also known as Latin1 */ + ISO8859_1Encoding, + /** */ + ISO8859_2Encoding, + /** */ + ISO8859_3Encoding, + /** */ + ISO8859_4Encoding, + /** */ + ISO8859_5Encoding, + /** */ + ISO8859_6Encoding, + /** */ + ISO8859_7Encoding, + /** */ + ISO8859_8Encoding, + /** */ + ISO8859_8_IEncoding, + /** */ + ISO8859_9Encoding, + /** */ + ISO8859_11Encoding, + /** */ + ISO8859_13Encoding, + /** */ + ISO8859_15Encoding, + /** */ + CP1250Encoding, + /** */ + CP1251Encoding, + /** */ + CP1252Encoding, + /** */ + CP1253Encoding, + /** */ + CP1254Encoding, + /** */ + CP1255Encoding, + /** */ + CP1256Encoding, + /** */ + CP1257Encoding, + /** */ + CP1258Encoding, + /** */ + IBM850Encoding, + /** */ + IBM866Encoding, + /** */ + KOI8_REncoding, + /** */ + KOI8_UEncoding, + /** the most common EBCDIC codepage */ + EBCDIC1047Encoding, + /** Offset for own encodings which are bound in by plugins */ + StartOfOwnEncoding=0x8000, + /** this should enable extension without breaking binary compatibility */ + MaxEncodingId=0xFFFF + }; +} + +#endif diff --git a/khexedit/lib/khechar.h b/khexedit/lib/khechar.h new file mode 100644 index 0000000..4f51e9e --- /dev/null +++ b/khexedit/lib/khechar.h @@ -0,0 +1,44 @@ +/*************************************************************************** + helper.h - description + ------------------- + begin : Do Nov 25 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + +#ifndef KHE_KHECHAR_H +#define KHE_KHECHAR_H + +// qt specific +#include <qstring.h> + +namespace KHE +{ + +class KHEChar : public QChar +{ + public: + KHEChar( QChar C ); + KHEChar( QChar C, bool U ); + public: + bool isUndefined() const; + protected: + // the byte is not defined + bool IsUndefined:1; +}; + +inline KHEChar::KHEChar( QChar C ) : QChar( C ), IsUndefined( false ) {} +inline KHEChar::KHEChar( QChar C, bool U ) : QChar( C ), IsUndefined( U ) {} +inline bool KHEChar::isUndefined() const { return IsUndefined; } + +} + +#endif diff --git a/khexedit/lib/khexedit.cpp b/khexedit/lib/khexedit.cpp new file mode 100644 index 0000000..85478e5 --- /dev/null +++ b/khexedit/lib/khexedit.cpp @@ -0,0 +1,2032 @@ +/*************************************************************************** + khexedit.cpp - description + ------------------- + begin : Die Mai 13 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +//#include <kdebug.h> + +// c specific +#include <stdlib.h> +//#include <limits.h> +// c++ specific +//#include <limits> +// qt specific +#include <qstyle.h> +#include <qpainter.h> +#include <qtimer.h> +#include <qcursor.h> +#include <qapplication.h> +// kde specific +#ifndef QT_ONLY +#include <kglobalsettings.h> +#endif +// lib specific +#include "kdatabuffer.h" +#include "koffsetcolumn.h" +#include "kvaluecolumn.h" +#include "kcharcolumn.h" +#include "kbordercolumn.h" +#include "kbuffercursor.h" +#include "kbufferlayout.h" +#include "kbufferranges.h" +#include "controller/ktabcontroller.h" +#include "controller/knavigator.h" +#include "controller/kvalueeditor.h" +#include "controller/kchareditor.h" +#include "kbufferdrag.h" +#include "kcursor.h" +#include "kbytecodec.h" +#include "kcharcodec.h" +#include "kwordbufferservice.h" +#include "khexedit.h" + +using namespace KHE; + +// zooming is done in steps of font size points +static const int DefaultZoomStep = 1; +static const int DefaultStartOffset = 0;//5; +static const int DefaultFirstLineOffset = 0; +static const int DefaultNoOfBytesPerLine = 16; +static const KHexEdit::KResizeStyle DefaultResizeStyle = KHexEdit::FullSizeUsage; +static const KHexEdit::KEncoding DefaultEncoding = KHexEdit::LocalEncoding; +static const int DefaultScrollTimerPeriod = 100; +static const int InsertCursorWidth = 2; + + + +KHexEdit::KHexEdit( KDataBuffer *Buffer, QWidget *Parent, const char *Name, WFlags Flags ) + : KColumnsView( Parent, Name, Flags ), + DataBuffer( Buffer ), + BufferLayout( new KBufferLayout(DefaultNoOfBytesPerLine,DefaultStartOffset,0) ), + BufferCursor( new KBufferCursor(BufferLayout) ), + BufferRanges( new KBufferRanges(BufferLayout) ), + CursorBlinkTimer( new QTimer(this) ), + ScrollTimer( new QTimer(this) ), + DragStartTimer( new QTimer(this) ), + TrippleClickTimer( new QTimer(this) ), + CursorPixmaps( new KCursor() ), + Codec( 0 ), + ClipboardMode( QClipboard::Clipboard ), + ResizeStyle( DefaultResizeStyle ), + Encoding( MaxEncodingId ), // forces update + ReadOnly( false ), +// Modified( false ), + OverWriteOnly( false ), + OverWrite( true ), + MousePressed( false ), + InDoubleClick( false ), + InDnD( false ), + DragStartPossible( false ), + CursorPaused( false ), + BlinkCursorVisible( false ), + InZooming( false ), + d( 0 ) +{ + // initalize layout + if( DataBuffer ) + BufferLayout->setLength( DataBuffer->size() ); + BufferLayout->setNoOfLinesPerPage( noOfLinesPerPage() ); + + // creating the columns in the needed order + OffsetColumn = new KOffsetColumn( this, DefaultFirstLineOffset, DefaultNoOfBytesPerLine, KOffsetFormat::Hexadecimal ); + FirstBorderColumn = new KBorderColumn( this, false ); + ValueColumn = new KValueColumn( this, DataBuffer, BufferLayout, BufferRanges ); + SecondBorderColumn = new KBorderColumn( this, true ); + CharColumn = new KCharColumn( this, DataBuffer, BufferLayout, BufferRanges ); + + // select the active column + ActiveColumn = &charColumn(); + InactiveColumn = &valueColumn(); + + // set encoding + Codec = KCharCodec::createCodec( (KHE::KEncoding)DefaultEncoding ); + valueColumn().setCodec( Codec ); + charColumn().setCodec( Codec ); + Encoding = DefaultEncoding; + + TabController = new KTabController( this, 0 ); + Navigator = new KNavigator( this, TabController ); + ValueEditor = new KValueEditor( ValueColumn, BufferCursor, this, Navigator ); + CharEditor = new KCharEditor( CharColumn, BufferCursor, this, Navigator ); + + Controller = Navigator; + +#ifdef QT_ONLY + QFont FixedFont( "fixed", 10 ); + FixedFont.setFixedPitch( true ); + setFont( FixedFont ); +#else + setFont( KGlobalSettings::fixedFont() ); +#endif + + // get the full control + viewport()->setFocusProxy( this ); + viewport()->setFocusPolicy( WheelFocus ); + + viewport()->installEventFilter( this ); + installEventFilter( this ); + + connect( CursorBlinkTimer, SIGNAL(timeout()), this, SLOT(blinkCursor()) ); + connect( ScrollTimer, SIGNAL(timeout()), this, SLOT(autoScrollTimerDone()) ); + connect( DragStartTimer, SIGNAL(timeout()), this, SLOT(startDrag()) ); + + viewport()->setAcceptDrops( true ); +} + + +KHexEdit::~KHexEdit() +{ + delete TabController; + delete Navigator; + delete ValueEditor; + delete CharEditor; +} + + +int KHexEdit::noOfBytesPerLine() const { return BufferLayout->noOfBytesPerLine(); } +int KHexEdit::firstLineOffset() const { return OffsetColumn->firstLineOffset(); } +int KHexEdit::startOffset() const { return BufferLayout->startOffset(); } +KHexEdit::KResizeStyle KHexEdit::resizeStyle() const { return ResizeStyle; } +KHexEdit::KCoding KHexEdit::coding() const { return (KHexEdit::KCoding)valueColumn().coding(); } +KPixelX KHexEdit::byteSpacingWidth() const { return valueColumn().byteSpacingWidth(); } +int KHexEdit::noOfGroupedBytes() const { return valueColumn().noOfGroupedBytes(); } +KPixelX KHexEdit::groupSpacingWidth() const { return valueColumn().groupSpacingWidth(); } +KPixelX KHexEdit::binaryGapWidth() const { return valueColumn().binaryGapWidth(); } +bool KHexEdit::isOverwriteMode() const { return OverWrite; } +bool KHexEdit::isOverwriteOnly() const { return OverWriteOnly; } +bool KHexEdit::isReadOnly() const { return ReadOnly; } +bool KHexEdit::isModified() const { return DataBuffer->isModified(); } +bool KHexEdit::tabChangesFocus() const { return TabController->tabChangesFocus(); } +bool KHexEdit::showUnprintable() const { return charColumn().showUnprintable(); } +QChar KHexEdit::substituteChar() const { return charColumn().substituteChar(); } +QChar KHexEdit::undefinedChar() const { return charColumn().undefinedChar(); } +KHexEdit::KEncoding KHexEdit::encoding() const { return (KHexEdit::KEncoding)Encoding; } +const QString &KHexEdit::encodingName() const { return Codec->name(); } + +KSection KHexEdit::selection() const { return BufferRanges->selection(); } +int KHexEdit::cursorPosition() const { return BufferCursor->index(); } +bool KHexEdit::isCursorBehind() const { return BufferCursor->isBehind(); } +KHexEdit::KBufferColumnId KHexEdit::cursorColumn() const +{ return static_cast<KHE::KValueColumn *>( ActiveColumn ) == &valueColumn()? ValueColumnId : CharColumnId; } + +void KHexEdit::setOverwriteOnly( bool OO ) { OverWriteOnly = OO; if( OverWriteOnly ) setOverwriteMode( true ); } +void KHexEdit::setModified( bool M ) { DataBuffer->setModified(M); } +void KHexEdit::setTabChangesFocus( bool TCF ) { TabController->setTabChangesFocus(TCF); } +void KHexEdit::setFirstLineOffset( int FLO ) { OffsetColumn->setFirstLineOffset( FLO ); } + +bool KHexEdit::offsetColumnVisible() const { return OffsetColumn->isVisible(); } +int KHexEdit::visibleBufferColumns() const +{ return (valueColumn().isVisible() ? ValueColumnId : 0) | (charColumn().isVisible() ? CharColumnId : 0); } + + +void KHexEdit::setOverwriteMode( bool OM ) +{ + if( (OverWriteOnly && !OM) || (OverWrite == OM) ) + return; + + OverWrite = OM; + + // affected: + // cursor shape + bool ChangeCursor = !( CursorPaused || ValueEditor->isInEditMode() ); + if( ChangeCursor ) + pauseCursor(); + + BufferCursor->setAppendPosEnabled( !OverWrite ); + + if( ChangeCursor ) + unpauseCursor(); + + emit cutAvailable( !OverWrite && BufferRanges->hasSelection() ); +} + + +void KHexEdit::setDataBuffer( KDataBuffer *B ) +{ + //pauseCursor(); + ValueEditor->reset(); + CursorPaused = true; + + DataBuffer = B; + valueColumn().set( DataBuffer ); + charColumn().set( DataBuffer); + + // affected: + // length -> no of lines -> width + BufferLayout->setLength( DataBuffer->size() ); + adjustLayoutToSize(); + + // ensure that the widget is readonly if the buffer is + if( DataBuffer->isReadOnly() ) + setReadOnly( true ); + + updateView(); + BufferCursor->gotoStart(); + ensureCursorVisible(); + unpauseCursor(); +} + + +void KHexEdit::setStartOffset( int SO ) +{ + if( !BufferLayout->setStartOffset(SO) ) + return; + + pauseCursor(); + // affects: + // the no of lines -> width + adjustLayoutToSize(); + + updateView(); + + BufferCursor->updateCoord(); + ensureCursorVisible(); + unpauseCursor(); +} + + +void KHexEdit::setReadOnly( bool RO ) +{ + // don't set editor readwrite if databuffer is readonly + ReadOnly = (DataBuffer && DataBuffer->isReadOnly()) ? true : RO; + + Controller = ReadOnly ? (KController*)Navigator : + cursorColumn() == CharColumnId ? (KController*)CharEditor : (KController*)ValueEditor; +} + + +void KHexEdit::setBufferSpacing( KPixelX ByteSpacing, int NoOfGroupedBytes, KPixelX GroupSpacing ) +{ + if( !valueColumn().setSpacing(ByteSpacing,NoOfGroupedBytes,GroupSpacing) ) + return; + + updateViewByWidth(); +} + + +void KHexEdit::setCoding( KCoding C ) +{ + uint OldCodingWidth = valueColumn().byteCodec()->encodingWidth(); + + if( !valueColumn().setCoding((KHE::KCoding)C) ) + return; + + uint NewCodingWidth = valueColumn().byteCodec()->encodingWidth(); + ValueEditor->ByteBuffer.setLength( NewCodingWidth ); //hack for now + + // no change in the width? + if( NewCodingWidth == OldCodingWidth ) + updateColumn( valueColumn() ); + else + updateViewByWidth(); +} + + +void KHexEdit::setResizeStyle( KResizeStyle NewStyle ) +{ + if( ResizeStyle == NewStyle ) + return; + + ResizeStyle = NewStyle; + + updateViewByWidth(); +} + + +void KHexEdit::setNoOfBytesPerLine( int NoBpL ) +{ + // if the number is explicitly set we expect a wish for no automatic resize + ResizeStyle = NoResize; + + if( !BufferLayout->setNoOfBytesPerLine(NoBpL) ) + return; + updateViewByWidth(); +} + + +void KHexEdit::setByteSpacingWidth( int/*KPixelX*/ BSW ) +{ + if( !valueColumn().setByteSpacingWidth(BSW) ) + return; + updateViewByWidth(); +} + +void KHexEdit::setNoOfGroupedBytes( int NoGB ) +{ + if( !valueColumn().setNoOfGroupedBytes(NoGB) ) + return; + updateViewByWidth(); +} + + +void KHexEdit::setGroupSpacingWidth( int/*KPixelX*/ GSW ) +{ + if( !valueColumn().setGroupSpacingWidth(GSW) ) + return; + updateViewByWidth(); +} + + +void KHexEdit::setBinaryGapWidth( int/*KPixelX*/ BGW ) +{ + if( !valueColumn().setBinaryGapWidth(BGW) ) + return; + updateViewByWidth(); +} + + +void KHexEdit::setSubstituteChar( QChar SC ) +{ + if( !charColumn().setSubstituteChar(SC) ) + return; + pauseCursor(); + updateColumn( charColumn() ); + unpauseCursor(); +} + +void KHexEdit::setUndefinedChar( QChar UC ) +{ + if( !charColumn().setUndefinedChar(UC) ) + return; + pauseCursor(); + updateColumn( charColumn() ); + unpauseCursor(); +} + +void KHexEdit::setShowUnprintable( bool SU ) +{ + if( !charColumn().setShowUnprintable(SU) ) + return; + pauseCursor(); + updateColumn( charColumn() ); + unpauseCursor(); +} + + +void KHexEdit::setEncoding( KEncoding C ) +{ + if( Encoding == C ) + return; + + KCharCodec *NC = KCharCodec::createCodec( (KHE::KEncoding)C ); + if( NC == 0 ) + return; + + valueColumn().setCodec( NC ); + charColumn().setCodec( NC ); + + delete Codec; + Codec = NC; + Encoding = C; + + pauseCursor(); + updateColumn( valueColumn() ); + updateColumn( charColumn() ); + unpauseCursor(); +} + +// TODO: join with function above! +void KHexEdit::setEncoding( const QString& EncodingName ) +{ + if( EncodingName == Codec->name() ) + return; + + KCharCodec *NC = KCharCodec::createCodec( EncodingName ); + if( NC == 0 ) + return; + + valueColumn().setCodec( NC ); + charColumn().setCodec( NC ); + + delete Codec; + Codec = NC; + Encoding = LocalEncoding; // TODO: add encoding no to every known codec + + pauseCursor(); + updateColumn( valueColumn() ); + updateColumn( charColumn() ); + unpauseCursor(); +} + + +void KHexEdit::fontChange( const QFont &OldFont ) +{ + QScrollView::fontChange( OldFont ); + + if( !InZooming ) + DefaultFontSize = font().pointSize(); + + // get new values + QFontMetrics FM( fontMetrics() ); + KPixelX DigitWidth = FM.maxWidth(); + KPixelY DigitBaseLine = FM.ascent(); + + setLineHeight( FM.height() ); + + // update all dependant structures + BufferLayout->setNoOfLinesPerPage( noOfLinesPerPage() ); + + OffsetColumn->setMetrics( DigitWidth, DigitBaseLine ); + valueColumn().setMetrics( DigitWidth, DigitBaseLine ); + charColumn().setMetrics( DigitWidth, DigitBaseLine ); + + updateViewByWidth(); +} + + +void KHexEdit::updateViewByWidth() +{ + pauseCursor(); + + adjustToLayoutNoOfBytesPerLine(); + adjustLayoutToSize(); + + updateView(); + + BufferCursor->updateCoord(); + ensureCursorVisible(); + + unpauseCursor(); +} + + +void KHexEdit::zoomIn() { zoomIn( DefaultZoomStep ); } +void KHexEdit::zoomOut() { zoomOut( DefaultZoomStep ); } + +void KHexEdit::zoomIn( int PointInc ) +{ + InZooming = true; + QFont F( font() ); + F.setPointSize( QFontInfo(F).pointSize() + PointInc ); + setFont( F ); + InZooming = false; +} + +void KHexEdit::zoomOut( int PointDec ) +{ + InZooming = true; + QFont F( font() ); + F.setPointSize( QMAX( 1, QFontInfo(F).pointSize() - PointDec ) ); + setFont( F ); + InZooming = false; +} + + +void KHexEdit::zoomTo( int PointSize ) +{ + InZooming = true; + QFont F( font() ); + F.setPointSize( PointSize ); + setFont( F ); + InZooming = false; +} + + +void KHexEdit::unZoom() +{ + zoomTo( DefaultFontSize ); +} + + +void KHexEdit::adjustLayoutToSize() +{ + // check whether there is a change with the numbers of fitting bytes per line + if( ResizeStyle != NoResize ) + { + int FittingBytesPerLine = fittingBytesPerLine( size() ); + +// std::cout<<"FitBpL"<<FittingBytesPerLine<<std::endl; + + // changes? + if( BufferLayout->setNoOfBytesPerLine(FittingBytesPerLine) ) + adjustToLayoutNoOfBytesPerLine(); + } + + setNoOfLines( BufferLayout->noOfLines() ); +} + + +void KHexEdit::adjustToLayoutNoOfBytesPerLine() +{ + OffsetColumn->setDelta( BufferLayout->noOfBytesPerLine() ); + valueColumn().resetXBuffer(); + charColumn().resetXBuffer(); + + updateWidths(); +} + + +void KHexEdit::setNoOfLines( int NewNoOfLines ) +{ + KColumnsView::setNoOfLines( NewNoOfLines>1?NewNoOfLines:1 ); +} + + +void KHexEdit::toggleOffsetColumn( bool Visible ) +{ + bool OCVisible = OffsetColumn->isVisible(); + // no change? + if( OCVisible == Visible ) + return; + + OffsetColumn->setVisible( Visible ); + FirstBorderColumn->setVisible( Visible ); + + updateViewByWidth(); +} + + +QSize KHexEdit::sizeHint() const +{ + return QSize( totalWidth(), totalHeight() ); +} + + +QSize KHexEdit::minimumSizeHint() const +{ + // TODO: better minimal width (visibility!) + return QSize( OffsetColumn->visibleWidth()+FirstBorderColumn->visibleWidth()+SecondBorderColumn->visibleWidth()+valueColumn().byteWidth()+charColumn().byteWidth(), + lineHeight() + noOfLines()>1? style().pixelMetric(QStyle::PM_ScrollBarExtent):0 ); +} + + +void KHexEdit::resizeEvent( QResizeEvent *ResizeEvent ) +{ + if( ResizeStyle != NoResize ) + { + int FittingBytesPerLine = fittingBytesPerLine( ResizeEvent->size() ); + + // changes? + if( BufferLayout->setNoOfBytesPerLine(FittingBytesPerLine) ) + { + setNoOfLines( BufferLayout->noOfLines() ); + updateViewByWidth(); + } + } + + QScrollView::resizeEvent( ResizeEvent ); + + BufferLayout->setNoOfLinesPerPage( noOfLinesPerPage() ); // TODO: doesn't work with the new size!!! +} + + +int KHexEdit::fittingBytesPerLine( const QSize &NewSize ) const +{ + KPixelX ReservedWidth = OffsetColumn->visibleWidth() + FirstBorderColumn->visibleWidth() + SecondBorderColumn->visibleWidth(); + + // abstract framewidth as well as offset and border columns width + int UsedbyFrameWidth = 2 * frameWidth(); + KPixelX FullWidth = NewSize.width() - UsedbyFrameWidth - ReservedWidth; + +// // no width left for resizeable columns? TODO: put this in resizeEvent +// if( FullWidth < 0 ) +// return; + + KPixelY FullHeight = NewSize.height() - UsedbyFrameWidth; + + // check influence of dis-/appearing of the vertical scrollbar + bool VerticalScrollbarIsVisible = verticalScrollBar()->isVisible(); + KPixelX ScrollbarExtent = style().pixelMetric( QStyle::PM_ScrollBarExtent );//verticalScrollBar()->width(); + + KPixelX AvailableWidth = FullWidth; + if( VerticalScrollbarIsVisible ) + AvailableWidth -= ScrollbarExtent; + + enum KMatchTrial { FirstRun, RerunWithScrollbarOn, TestWithoutScrollbar }; + KMatchTrial MatchRun = FirstRun; + + // prepare needed values + KPixelX DigitWidth = valueColumn().digitWidth(); + KPixelX TextByteWidth = charColumn().isVisible() ? DigitWidth : 0; + KPixelX HexByteWidth = valueColumn().isVisible() ? valueColumn().byteWidth() : 0; + KPixelX ByteSpacingWidth = valueColumn().isVisible() ? valueColumn().byteSpacingWidth() : 0; + KPixelX GroupSpacingWidth; + int NoOfGroupedBytes = valueColumn().noOfGroupedBytes(); + // no grouping? + if( NoOfGroupedBytes == 0 ) + { + // faking grouping by 1 + NoOfGroupedBytes = 1; + GroupSpacingWidth = 0; + } + else + GroupSpacingWidth = valueColumn().isVisible() ? valueColumn().groupSpacingWidth() : 0; + + KPixelX HexByteGroupWidth = NoOfGroupedBytes * HexByteWidth + (NoOfGroupedBytes-1)*ByteSpacingWidth; + KPixelX TextByteGroupWidth = NoOfGroupedBytes * TextByteWidth; + KPixelX TotalGroupWidth = HexByteGroupWidth + GroupSpacingWidth + TextByteGroupWidth; + + int FittingBytesPerLine; + int WithScrollbarFittingBytesPerLine = 0; + for(;;) + { +// std::cout << "matchWidth: " << FullWidth +// << " (v:" << visibleWidth() +// << ", f:" << frameWidth() +// << ", A:" << AvailableWidth +// << ", S:" << ScrollbarExtent +// << ", R:" << ReservedWidth << ")" << std::endl; + + // calculate fitting groups per line + int FittingGroupsPerLine = (AvailableWidth+GroupSpacingWidth) // fake spacing after last group + / TotalGroupWidth; + + // calculate the fitting bytes per line by groups + FittingBytesPerLine = NoOfGroupedBytes * FittingGroupsPerLine; + + // not only full groups? + if( ResizeStyle == FullSizeUsage && NoOfGroupedBytes > 1 ) + { + if( FittingGroupsPerLine > 0 ) + AvailableWidth -= FittingGroupsPerLine*TotalGroupWidth; // includes additional spacing after last group + +// std::cout << "Left: " << AvailableWidth << "("<<HexByteWidth<<", "<<TextByteWidth<<")" << std::endl; + + if( AvailableWidth > 0 ) + FittingBytesPerLine += (AvailableWidth+ByteSpacingWidth) / (HexByteWidth+ByteSpacingWidth+TextByteWidth); + + // is there not even the space for a single byte? + if( FittingBytesPerLine == 0 ) + { + // ensure at least one byte per line + FittingBytesPerLine = 1; + // and + break; + } + } + // is there not the space for a single group? + else if( FittingBytesPerLine == 0 ) + { + // ensures at least one group + FittingBytesPerLine = NoOfGroupedBytes; + break; + } + +// std::cout << "meantime: " << FittingGroupsPerLine << " (T:" << TotalGroupWidth +// << ", h:" << HexByteGroupWidth +// << ", t:" << TextByteGroupWidth +// << ", s:" << GroupSpacingWidth << ") " <<FittingBytesPerLine<< std::endl; + + int NewNoOfLines = (BufferLayout->length()+BufferLayout->startOffset()+FittingBytesPerLine-1) + / FittingBytesPerLine; + KPixelY NewHeight = NewNoOfLines * LineHeight; + + if( VerticalScrollbarIsVisible ) + { + if( MatchRun == TestWithoutScrollbar ) + { + // did the test without the scrollbar fail, don't the data fit into the view? + if( NewHeight>FullHeight ) + // reset to old calculated value + FittingBytesPerLine = WithScrollbarFittingBytesPerLine; + break; + } + + // a chance for to perhaps fit in height? + if( FittingBytesPerLine <= BufferLayout->noOfBytesPerLine() ) + { + // remember this trial's result and calc number of bytes with vertical scrollbar on + WithScrollbarFittingBytesPerLine = FittingBytesPerLine; + AvailableWidth = FullWidth; + MatchRun = TestWithoutScrollbar; +// std::cout << "tested without scrollbar..." << std::endl; + continue; + } + } + else + { + // doesn't it fit into the height anymore? + if( NewHeight>FullHeight && MatchRun==FirstRun ) + { + // need for a scrollbar has risen... ->less width, new calculation + AvailableWidth = FullWidth - ScrollbarExtent; + MatchRun = RerunWithScrollbarOn; +// std::cout << "rerun with scrollbar on..." << std::endl; + continue; + } + } + + break; + } + + return FittingBytesPerLine; +} + + +bool KHexEdit::selectWord( /*unsigned TODO:change all unneeded signed into unsigned!*/ int Index ) +{ + if( Index >= 0 && Index < BufferLayout->length() ) + { + KWordBufferService WBS( DataBuffer, Codec ); + KSection WordSection = WBS.wordSection( Index ); + if( WordSection.isValid() ) + { + pauseCursor(); + + BufferRanges->setFirstWordSelection( WordSection ); + BufferCursor->gotoIndex( WordSection.end()+1 ); + repaintChanged(); + + unpauseCursor(); + return true; + } + } + return false; +} + +void KHexEdit::select( KSection Section ) +{ + if( !Section.isValid() ) + return; + + Section.restrictTo( KSection(0,BufferLayout->length()-1) ); + + pauseCursor(); + + BufferRanges->setSelection( Section ); + BufferCursor->gotoIndex( Section.end()+1 ); + repaintChanged(); + + unpauseCursor(); + + if( !OverWrite ) emit cutAvailable( BufferRanges->hasSelection() ); + emit copyAvailable( BufferRanges->hasSelection() ); + emit selectionChanged( Section.start(), Section.end() ); +} + +void KHexEdit::selectAll( bool Select ) +{ + KSection Selection; + + pauseCursor( true ); + + if( !Select ) + BufferRanges->removeSelection(); + else + { + Selection.set( 0, BufferLayout->length()-1 ); + BufferRanges->setSelection( Selection ); + BufferCursor->gotoEnd(); + } + + repaintChanged(); + + unpauseCursor(); + + if( !OverWrite ) emit cutAvailable( BufferRanges->hasSelection() ); + emit copyAvailable( BufferRanges->hasSelection() ); + emit selectionChanged( Selection.start(), Selection.end() ); + viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor ); +} + + +bool KHexEdit::hasSelectedData() const +{ + return BufferRanges->hasSelection(); +} + + +QByteArray KHexEdit::selectedData() const +{ + if( !BufferRanges->hasSelection() ) + return QByteArray(); + + KSection Selection = BufferRanges->selection(); + QByteArray SD( Selection.width() ); + DataBuffer->copyTo( SD.data(), Selection.start(), Selection.width() ); + return SD; +} + + +KBufferDrag *KHexEdit::dragObject( QWidget *Parent ) const +{ + if( !BufferRanges->hasSelection() ) + return 0; + + const KOffsetColumn *OC; + const KValueColumn *HC; + const KCharColumn *TC; + KCoordRange Range; + + if( static_cast<KHE::KCharColumn *>( ActiveColumn ) == &charColumn() ) + { + OC = 0; + HC = 0; + TC = 0; + } + else + { + OC = OffsetColumn->isVisible() ? OffsetColumn : 0; + HC = valueColumn().isVisible() ? &valueColumn() : 0; + TC = charColumn().isVisible() ? &charColumn() : 0; + KSection S = BufferRanges->selection(); + Range.set( BufferLayout->coordOfIndex(S.start()),BufferLayout->coordOfIndex(S.end()) ); + } + + return new KBufferDrag( selectedData(), Range, OC, HC, TC, + charColumn().substituteChar(), charColumn().undefinedChar(), + Codec->name(), Parent ); +} + + +void KHexEdit::cut() +{ + if( isReadOnly() || OverWrite ) + return; + + KBufferDrag *Drag = dragObject(); + if( !Drag ) + return; + + QApplication::clipboard()->setData( Drag, ClipboardMode ); + + removeSelectedData(); +} + + +void KHexEdit::copy() +{ + KBufferDrag *Drag = dragObject(); + if( !Drag ) + return; + + QApplication::clipboard()->setData( Drag, ClipboardMode ); +} + + +void KHexEdit::paste() +{ + if( isReadOnly() ) + return; + + QMimeSource *Source = QApplication::clipboard()->data( ClipboardMode ); + pasteFromSource( Source ); +} + + +void KHexEdit::pasteFromSource( QMimeSource *Source ) +{ + if( !Source || !KBufferDrag::canDecode(Source) ) + return; + + QByteArray Data; + if( !KBufferDrag::decode(Source,Data) ) + return; + + if( !Data.isEmpty() ) + insert( Data ); +} + + +void KHexEdit::insert( const QByteArray &D ) +{ + pauseCursor( true ); + + KSection ChangedRange; + + if( OverWrite ) + { + if( BufferRanges->hasSelection() ) + { + // replacing the selection: + // we restrict the replacement to the minimum length of selection and input + ChangedRange = BufferRanges->selection(); + ChangedRange.restrictEndTo( ChangedRange.start()+D.size()-1 ); + int W = DataBuffer->replace( ChangedRange, D.data(), ChangedRange.width() ); + BufferCursor->gotoCIndex( ChangedRange.start()+W ); + BufferRanges->removeSelection(); + } + else + { + if( !BufferCursor->isBehind() ) + { + // replacing the normal data, at least until the end + ChangedRange.setByWidth( BufferCursor->realIndex(), D.size() ); + ChangedRange.restrictEndTo( BufferLayout->length()-1 ); + if( ChangedRange.isValid() ) + { + int W = DataBuffer->replace( ChangedRange, D.data(), ChangedRange.width() ); + BufferCursor->gotoNextByte( W ); + } + } + } + } + else + { + if( BufferRanges->hasSelection() ) + { + // replacing the selection + KSection Selection = BufferRanges->selection(); + int OldLastIndex = BufferLayout->length() - 1; + int W = DataBuffer->replace( Selection, D.data(), D.size() ); + updateLength(); + BufferCursor->gotoIndex( Selection.start() + W ); + if( W > 0 ) + { + if( Selection.width() == (int)D.size() ) + ChangedRange = Selection; + else + { + int NewLastIndex = DataBuffer->size() - 1; + ChangedRange.set( Selection.start(), NewLastIndex>OldLastIndex?NewLastIndex:OldLastIndex ); + } + } + BufferRanges->removeSelection(); + } + else + { + bool Appending = BufferCursor->atAppendPos(); + int OldIndex = BufferCursor->realIndex(); + int W = DataBuffer->insert( OldIndex, D.data(), D.size() ); + updateLength(); + // worked? + if( W > 0 ) + { + if( Appending ) + BufferCursor->gotoEnd(); + else + BufferCursor->gotoNextByte( W ); + ChangedRange.set( OldIndex, DataBuffer->size()-1 ); + } + } + } + + bool Changed = ChangedRange.isValid(); + if( Changed ) + { + BufferRanges->addChangedRange( ChangedRange ); + repaintChanged(); + } + ensureCursorVisible(); + + unpauseCursor(); + + if( Changed ) emit bufferChanged( ChangedRange.start(), ChangedRange.end() ); + KSection Selection = BufferRanges->selection(); + emit selectionChanged( Selection.start(), Selection.end() ); +} + + +void KHexEdit::removeSelectedData() +{ + // Can't we do this? + if( isReadOnly() || OverWrite || ValueEditor->isInEditMode() ) + return; + + pauseCursor(); + + KSection Selection = BufferRanges->selection(); + + BufferRanges->removeFurtherSelections(); + + KSection ChangedRange = removeData( Selection ); + BufferRanges->removeSelection(); + + repaintChanged(); + + BufferCursor->gotoCIndex( Selection.start() ); + + ensureCursorVisible(); +// clearUndoRedo(); + viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor ); + + unpauseCursor(); + + if( ChangedRange.isValid() ) emit bufferChanged( ChangedRange.start(), ChangedRange.end() ); + emit selectionChanged( -1, -1 ); +} + + +KSection KHexEdit::removeData( KSection Indizes ) +{ +// if( undoEnabled ) +// { +// checkUndoRedoInfo( UndoRedoInfo::RemoveSelected ); +// if( !undoRedoInfo.valid() ) +// { +// doc->selectionStart( selNum, undoRedoInfo.id, undoRedoInfo.index ); +// undoRedoInfo.d->text = QString::null; +// } +// readFormats( c1, c2, undoRedoInfo.d->text, TRUE ); +// } + + KSection ChangedRange( Indizes.start(), BufferLayout->length()-1 ); + // do it! + DataBuffer->remove( Indizes ); + updateLength(); + BufferRanges->addChangedRange( ChangedRange ); + + return ChangedRange; +} + + +void KHexEdit::updateLength() +{ + BufferLayout->setLength( DataBuffer->size() ); + setNoOfLines( BufferLayout->noOfLines() ); +} + + +void KHexEdit::clipboardChanged() +{ + // don't listen to selection changes + disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0 ); + selectAll( false ); +} + + +void KHexEdit::setCursorPosition( int Index, bool Behind ) +{ + pauseCursor( true ); + + BufferCursor->gotoCIndex( Index ); + if( Behind ) + BufferCursor->stepBehind(); + + BufferRanges->removeSelection(); + bool RangesModifed = BufferRanges->isModified(); + if( RangesModifed ) + { + repaintChanged(); + + viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor ); + + } + ensureCursorVisible(); + unpauseCursor(); + + if( RangesModifed ) + { + if( !OverWrite ) emit cutAvailable( BufferRanges->hasSelection() ); + emit copyAvailable( BufferRanges->hasSelection() ); + emit selectionChanged( -1, -1 ); + } +} + + +void KHexEdit::showBufferColumns( int CCs ) +{ + int Columns = visibleBufferColumns(); + + // no changes or no column selected? + if( CCs == Columns || !(CCs&( ValueColumnId | CharColumnId )) ) + return; + + valueColumn().setVisible( ValueColumnId & CCs ); + charColumn().setVisible( CharColumnId & CCs ); + SecondBorderColumn->setVisible( CCs == (ValueColumnId|CharColumnId) ); + + // active column not visible anymore? + if( !activeColumn().isVisible() ) + { + KBufferColumn *H = ActiveColumn; + ActiveColumn = InactiveColumn; + InactiveColumn = H; + Controller = ReadOnly ? (KController*)Navigator : + cursorColumn() == CharColumnId ? (KController*)CharEditor : (KController*)ValueEditor; + } + + updateViewByWidth(); +} + + +void KHexEdit::setCursorColumn( KBufferColumnId CC ) +{ + // no changes or not visible? + if( CC == cursorColumn() + || (CC == ValueColumnId && !valueColumn().isVisible()) + || (CC == CharColumnId && !charColumn().isVisible()) ) + return; + + pauseCursor( true ); + + if( CC == ValueColumnId ) + { + ActiveColumn = &valueColumn(); + InactiveColumn = &charColumn(); + } + else + { + ActiveColumn = &charColumn(); + InactiveColumn = &valueColumn(); + } + Controller = ReadOnly ? (KController*)Navigator : + cursorColumn() == CharColumnId ? (KController*)CharEditor : (KController*)ValueEditor; + + ensureCursorVisible(); + unpauseCursor(); +} + + +void KHexEdit::placeCursor( const QPoint &Point ) +{ + resetInputContext(); + + // switch active column if needed + if( charColumn().isVisible() && Point.x() >= charColumn().x() ) + { + ActiveColumn = &charColumn(); + InactiveColumn = &valueColumn(); + } + else + { + ActiveColumn = &valueColumn(); + InactiveColumn = &charColumn(); + } + Controller = ReadOnly ? (KController*)Navigator : + cursorColumn() == CharColumnId ? (KController*)CharEditor : (KController*)ValueEditor; + + // get coord of click and whether this click was closer to the end of the pos + KBufferCoord C( activeColumn().magPosOfX(Point.x()), lineAt(Point.y()) ); + + BufferCursor->gotoCCoord( C ); +} + + +int KHexEdit::indexByPoint( const QPoint &Point ) const +{ + const KBufferColumn *C; + if( charColumn().isVisible() && Point.x() >= charColumn().x() ) + C = &charColumn(); + else + C = &valueColumn(); + + KBufferCoord Coord( C->posOfX(Point.x()), lineAt(Point.y()) ); + + return BufferLayout->indexAtCCoord( Coord ); +} + + +void KHexEdit::showEvent( QShowEvent *e ) +{ + KColumnsView::showEvent( e ); + BufferLayout->setNoOfLinesPerPage( noOfLinesPerPage() ); +} + + +bool KHexEdit::eventFilter( QObject *O, QEvent *E ) +{ + if( O == this || O == viewport() ) + { + if( E->type() == QEvent::FocusIn ) + { + startCursor(); + } + else if( E->type() == QEvent::FocusOut ) + { + stopCursor(); + } + } + +// if( O == this && E->type() == QEvent::PaletteChange ) +// { +// QColor old( viewport()->colorGroup().color(QColorGroup::Text) ); +// +// if( old != colorGroup().color(QColorGroup::Text) ) +// { +// QColor c( colorGroup().color(QColorGroup::Text) ); +// doc->setMinimumWidth( -1 ); +// doc->setDefaultFormat( doc->formatCollection()->defaultFormat()->font(), c ); +// lastFormatted = doc->firstParagraph(); +// formatMore(); +// repaintChanged(); +// } +// } + + return QScrollView::eventFilter( O, E ); +} + + +void KHexEdit::blinkCursor() +{ + // skip the cursor drawing? + if( CursorPaused || ValueEditor->isInEditMode() ) + return; + + // switch the cursor state + paintActiveCursor( !BlinkCursorVisible ); +} + + +void KHexEdit::startCursor() +{ + CursorPaused = false; + + updateCursor(); + + CursorBlinkTimer->start( QApplication::cursorFlashTime()/2 ); +} + + +void KHexEdit::unpauseCursor() +{ + CursorPaused = false; + + if( CursorBlinkTimer->isActive() ) + updateCursor(); +} + + +void KHexEdit::updateCursor() +{ + createCursorPixmaps(); + + paintActiveCursor( true ); + paintInactiveCursor( true ); +} + + +void KHexEdit::stopCursor() +{ + CursorBlinkTimer->stop(); + + pauseCursor(); +} + + +void KHexEdit::pauseCursor( bool LeaveEdit ) +{ + paintActiveCursor( false ); + paintInactiveCursor( false ); + + if( LeaveEdit ) + ValueEditor->InEditMode = false; + CursorPaused = true; +} + + +void KHexEdit::createCursorPixmaps() +{ + // create CursorPixmaps + CursorPixmaps->setSize( activeColumn().byteWidth(), LineHeight ); + + int Index = BufferCursor->validIndex(); + + QPainter Paint; + Paint.begin( &CursorPixmaps->offPixmap(), this ); + activeColumn().paintByte( &Paint, Index ); + Paint.end(); + + Paint.begin( &CursorPixmaps->onPixmap(), this ); + activeColumn().paintCursor( &Paint, Index ); + Paint.end(); + + // calculat the shape + KPixelX CursorX; + KPixelX CursorW; + if( BufferCursor->isBehind() ) + { + CursorX = QMAX( 0, CursorPixmaps->onPixmap().width()-InsertCursorWidth ); + CursorW = InsertCursorWidth; + } + else + { + CursorX = 0; + CursorW = OverWrite ? -1 : InsertCursorWidth; + } + CursorPixmaps->setShape( CursorX, CursorW ); +} + + +void KHexEdit::pointPainterToCursor( QPainter &Painter, const KBufferColumn &Column ) const +{ + int x = Column.xOfPos( BufferCursor->pos() ) - contentsX(); + int y = LineHeight * BufferCursor->line() - contentsY(); + + Painter.begin( viewport() ); + Painter.translate( x, y ); +} + + +void KHexEdit::paintActiveCursor( bool CursorOn ) +{ + // any reason to skip the cursor drawing? + if( !isUpdatesEnabled() || !viewport()->isUpdatesEnabled() + || (CursorOn && !hasFocus() && !viewport()->hasFocus() && !InDnD ) ) + return; + + QPainter Painter; + pointPainterToCursor( Painter, activeColumn() ); + + // paint edited byte? + if( ValueEditor->isInEditMode() ) + { + int Index = BufferCursor->index(); + + if( CursorOn ) + valueColumn().paintEditedByte( &Painter, ValueEditor->EditValue, ValueEditor->ByteBuffer ); + else + valueColumn().paintByte( &Painter, Index ); + } + else + { + + Painter.drawPixmap( CursorPixmaps->cursorX(), 0, + CursorOn?CursorPixmaps->onPixmap():CursorPixmaps->offPixmap(), + CursorPixmaps->cursorX(),0,CursorPixmaps->cursorW(),-1 ); + // store state + BlinkCursorVisible = CursorOn; + } +} + + +void KHexEdit::paintInactiveCursor( bool CursorOn ) +{ + // any reason to skip the cursor drawing? + if( !isUpdatesEnabled() + || !viewport()->isUpdatesEnabled() + || !inactiveColumn().isVisible() + || (CursorOn && !hasFocus() && !viewport()->hasFocus() && !InDnD) ) + return; + + int Index = BufferCursor->validIndex(); + + QPainter Painter; + pointPainterToCursor( Painter, inactiveColumn() ); + if( CursorOn ) + { + KBufferColumn::KFrameStyle Style = + BufferCursor->isBehind() ? KBufferColumn::Right : + (OverWrite||ValueEditor->isInEditMode()) ? KBufferColumn::Frame : + KBufferColumn::Left; + inactiveColumn().paintFramedByte( &Painter, Index, Style ); + } + else + inactiveColumn().paintByte( &Painter, Index ); +} + + +void KHexEdit::drawContents( QPainter *P, int cx, int cy, int cw, int ch ) +{ + KColumnsView::drawContents( P, cx, cy, cw, ch ); + // TODO: update non blinking cursors. Should this perhaps be done in the buffercolumn? + // Then it needs to know about inactive, insideByte and the like... well... + // perhaps subclassing the buffer columns even more, to KCharColumn and KValueColumn? + + if( !CursorPaused && visibleLines(KPixelYs(cy,ch,false)).includes(BufferCursor->line()) ) + { + paintActiveCursor( true ); + paintInactiveCursor( true ); + } +} + +void KHexEdit::updateColumn( KColumn &Column ) +{ + //kdDebug(1501) << "updateColumn\n"; + if( Column.isVisible() ) + updateContents( Column.x(), 0, Column.width(), totalHeight() ); +} + + +void KHexEdit::keyPressEvent( QKeyEvent *KeyEvent ) +{ + if( !Controller->handleKeyPress( KeyEvent ) ) + KeyEvent->ignore(); +} + + +void KHexEdit::repaintChanged() +{ + if( !isUpdatesEnabled() || !viewport()->isUpdatesEnabled() || !BufferRanges->isModified() ) + return; + + // TODO: we do this only to let the scrollview handle new or removed lines. overlaps with repaintRange + resizeContents( totalWidth(), totalHeight() ); + + KPixelXs Xs( contentsX(), visibleWidth(), true ); + + // collect affected buffer columns + QPtrList<KBufferColumn> RepaintColumns; + + KBufferColumn *C = ValueColumn; + while( true ) + { + if( C->isVisible() && C->overlaps(Xs) ) + { + RepaintColumns.append( C ); + C->preparePainting( Xs ); + } + + if( C == CharColumn ) + break; + C = CharColumn; + } + + // any colums to paint? + if( RepaintColumns.count() > 0 ) + { + KPixelYs Ys( contentsY(), visibleHeight(), true ); + + // calculate affected lines/indizes + KSection FullPositions( 0, BufferLayout->noOfBytesPerLine()-1 ); + KCoordRange VisibleRange( FullPositions, visibleLines(Ys) ); + + KCoordRange ChangedRange; + // as there might be multiple selections on this line redo until no more is changed + while( hasChanged(VisibleRange,&ChangedRange) ) + { +// std::cout << " changed->"<<FirstChangedIndex<<","<<LastChangedIndex<<std::endl; + + // only one line? + if( ChangedRange.start().line() == ChangedRange.end().line() ) + for( KBufferColumn *C=RepaintColumns.first(); C; C=RepaintColumns.next() ) + paintLine( C, ChangedRange.start().line(), + KSection(ChangedRange.start().pos(),ChangedRange.end().pos()) ); + // + else + { + // first line + for( KBufferColumn *C=RepaintColumns.first(); C; C=RepaintColumns.next() ) + paintLine( C, ChangedRange.start().line(), + KSection(ChangedRange.start().pos(),FullPositions.end()) ); + + // at least one full line? + for( int l = ChangedRange.start().line()+1; l < ChangedRange.end().line(); ++l ) + for( KBufferColumn *C=RepaintColumns.first(); C; C=RepaintColumns.next() ) + paintLine( C, l, FullPositions ); + + // last line + for( KBufferColumn *C=RepaintColumns.first(); C; C=RepaintColumns.next() ) + paintLine( C, ChangedRange.end().line(), + KSection(FullPositions.start(),ChangedRange.end().pos()) ); + } + + // continue the search at the overnext index + VisibleRange.setStart( ChangedRange.end()+2 ); + if( !VisibleRange.isValid() ) + break; + } + } + + + // Paint possible removed bytes at the end of the last line + // Paint new/removed trailing lines +// drawContents( P, cx, cy, cw, ch ); + // Paint empty rects +// paintEmptyArea( P, cx, cy, cw, ch ); +// BufferLayout->noOfLines() + + BufferRanges->resetChangedRanges(); +} + + +void KHexEdit::paintLine( KBufferColumn *C, int Line, KSection Positions ) +{ + Positions.restrictTo( C->visiblePositions() ); + + // nothing to paint? + if( !Positions.isValid() ) + return; +// std::cout << " paintLine->"<<Line<< ":"<<FirstPos<<","<<LastPos<<std::endl; + + // calculating pixel values + KPixelXs XPixels = C->wideXPixelsOfPos( Positions ); + + KPixelY cy = Line * LineHeight; + + // to avoid flickers we first paint to the linebuffer + QPainter Paint; + Paint.begin( &LineBuffer, this ); + + Paint.translate( C->x(), 0 ); + C->paintPositions( &Paint, Line, Positions ); + Paint.translate( -C->x(), 0 ); + + if( HorizontalGrid && XPixels.start() < TotalWidth ) + Paint.drawLine( XPixels.start(), LineHeight-1, XPixels.width(), LineHeight-1 ); // TODO: use a additional TotalHeight? + + Paint.end(); + // copy to screen + bitBlt( viewport(), XPixels.start() - contentsX(), cy - contentsY(), + &LineBuffer, XPixels.start(), 0, XPixels.width(), LineHeight ); +} + + +bool KHexEdit::hasChanged( const KCoordRange &VisibleRange, KCoordRange *ChangedRange ) const +{ + if( !BufferRanges->overlapsChanges(VisibleRange,ChangedRange) ) + return false; + + ChangedRange->restrictTo( VisibleRange ); + return true; +} + + +void KHexEdit::ensureCursorVisible() +{ +// // Not visible or the user is draging the window, so don't position to caret yet +// if ( !isVisible() || isHorizontalSliderPressed() || isVerticalSliderPressed() ) +// { +// d->ensureCursorVisibleInShowEvent = true; +// return; +// } + + KPixelX x = activeColumn().xOfPos( BufferCursor->pos() )+ activeColumn().byteWidth()/2; + KPixelY y = LineHeight * BufferCursor->line() + LineHeight/2; + int xMargin = activeColumn().byteWidth()/2 + 1; + int yMargin = LineHeight/2 + 1; + ensureVisible( x, y, xMargin, yMargin ); +} + + + +void KHexEdit::contentsMousePressEvent( QMouseEvent *e ) +{ +// clearUndoRedo(); + pauseCursor( true ); + + // care about a left button press? + if( e->button() == LeftButton ) + { + MousePressed = true; + + // select whole line? + if( TrippleClickTimer->isActive() + && (e->globalPos()-DoubleClickPoint).manhattanLength() < QApplication::startDragDistance() ) + { + BufferRanges->setSelectionStart( BufferLayout->indexAtLineStart(DoubleClickLine) ); + BufferCursor->gotoLineEnd(); + BufferRanges->setSelectionEnd( BufferCursor->realIndex() ); + repaintChanged(); + + unpauseCursor(); + return; + } + + QPoint MousePoint = e->pos(); + placeCursor( MousePoint ); + ensureCursorVisible(); + + // start of a drag perhaps? + if( BufferRanges->selectionIncludes(BufferCursor->index()) ) + { + DragStartPossible = true; + DragStartTimer->start( QApplication::startDragTime(), true ); + DragStartPoint = MousePoint; + + unpauseCursor(); + return; + } + + int RealIndex = BufferCursor->realIndex(); + if( BufferRanges->selectionStarted() ) + { + if( e->state() & ShiftButton ) + BufferRanges->setSelectionEnd( RealIndex ); + else + { + BufferRanges->removeSelection(); + BufferRanges->setSelectionStart( RealIndex ); + } + } + else // start of a new selection possible + { + BufferRanges->setSelectionStart( RealIndex ); + + if( !isReadOnly() && (e->state()&ShiftButton) ) // TODO: why only for readwrite? + BufferRanges->setSelectionEnd( RealIndex ); + } + + BufferRanges->removeFurtherSelections(); + } + else if( e->button() == MidButton ) + BufferRanges->removeSelection(); + + if( BufferRanges->isModified() ) + { + repaintChanged(); + viewport()->setCursor( isReadOnly() ? arrowCursor : ibeamCursor ); + } + + unpauseCursor(); +} + + +void KHexEdit::contentsMouseMoveEvent( QMouseEvent *e ) +{ + if( MousePressed ) + { + if( DragStartPossible ) + { + DragStartTimer->stop(); + // moved enough for a drag? + if( (e->pos()-DragStartPoint).manhattanLength() > QApplication::startDragDistance() ) + startDrag(); + if( !isReadOnly() ) + viewport()->setCursor( ibeamCursor ); + return; + } + // selecting + QPoint MousePoint = e->pos(); + handleMouseMove( MousePoint ); + } + else if( !isReadOnly() ) + { + // visual feedback for possible dragging + bool InSelection = BufferRanges->hasSelection() && BufferRanges->selectionIncludes( indexByPoint(e->pos()) ); + viewport()->setCursor( InSelection?arrowCursor:ibeamCursor ); + } +} + + +void KHexEdit::contentsMouseReleaseEvent( QMouseEvent *e ) +{ + // this is not the release of a doubleclick so we need to process it? + if( !InDoubleClick ) + { + int Line = lineAt( e->pos().y() ); + int Pos = activeColumn().posOfX( e->pos().x() ); // TODO: can we be sure here about the active column? + int Index = BufferLayout->indexAtCCoord( KBufferCoord(Pos,Line) ); // TODO: can this be another index than the one of the cursor??? + emit clicked( Index ); + } + + if( MousePressed ) + { + MousePressed = false; + + if( ScrollTimer->isActive() ) + ScrollTimer->stop(); + + // was only click inside selection, nothing dragged? + if( DragStartPossible ) + { + selectAll( false ); + DragStartTimer->stop(); + DragStartPossible = false; + + unpauseCursor(); + } + // was end of selection operation? + else if( BufferRanges->hasSelection() ) + { + if( QApplication::clipboard()->supportsSelection() ) + { + ClipboardMode = QClipboard::Selection; + disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0); + + copy(); + + connect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, SLOT(clipboardChanged()) ); + ClipboardMode = QClipboard::Clipboard; + } + } + } + // middle mouse button paste? + else if( e->button() == MidButton && !isReadOnly() ) + { + pauseCursor(); + + placeCursor( e->pos() ); + + // replace no selection? + if( BufferRanges->hasSelection() && !BufferRanges->selectionIncludes(BufferCursor->index()) ) + BufferRanges->removeSelection(); + + ClipboardMode = QClipboard::Selection; + paste(); + ClipboardMode = QClipboard::Clipboard; + + // ensure selection changes to be drawn TODO: create a insert/pasteAtCursor that leaves out drawing + repaintChanged(); + + ensureCursorVisible(); + unpauseCursor(); + } + + InDoubleClick = false; + + if( BufferRanges->selectionJustStarted() ) + BufferRanges->removeSelection(); + + emit cursorPositionChanged( BufferCursor->index() ); + + if( !OverWrite ) emit cutAvailable( BufferRanges->hasSelection() ); + emit copyAvailable( BufferRanges->hasSelection() ); + KSection Selection = BufferRanges->selection(); + emit selectionChanged( Selection.start(), Selection.end() ); +} + + +// gets called after press and release instead of a plain press event (?) +void KHexEdit::contentsMouseDoubleClickEvent( QMouseEvent *e ) +{ + // we are only interested in LMB doubleclicks + if( e->button() != Qt::LeftButton ) + { + e->ignore(); + return; + } + + DoubleClickLine = BufferCursor->line(); + + int Index = BufferCursor->validIndex(); + + if( ActiveColumn == &charColumn() ) + { + selectWord( Index ); + + // as we already have a doubleclick maybe it is a tripple click + TrippleClickTimer->start( qApp->doubleClickInterval(), true ); + DoubleClickPoint = e->globalPos(); + } +// else +// ValueEditor->goInsideByte(); TODO: make this possible again + + InDoubleClick = true; // + MousePressed = true; + + emit doubleClicked( Index ); +} + + +void KHexEdit::autoScrollTimerDone() +{ + if( MousePressed ) + handleMouseMove( viewportToContents(viewport()->mapFromGlobal( QCursor::pos() )) ); +} + + +void KHexEdit::handleMouseMove( const QPoint& Point ) // handles the move of the mouse with pressed buttons +{ + // no scrolltimer and outside of viewport? + if( !ScrollTimer->isActive() && Point.y() < contentsY() || Point.y() > contentsY() + visibleHeight() ) + ScrollTimer->start( DefaultScrollTimerPeriod, false ); + // scrolltimer but inside of viewport? + else if( ScrollTimer->isActive() && Point.y() >= contentsY() && Point.y() <= contentsY() + visibleHeight() ) + ScrollTimer->stop(); + + pauseCursor(); + + placeCursor( Point ); + ensureCursorVisible(); + + // do wordwise selection? + if( InDoubleClick && BufferRanges->hasFirstWordSelection() ) + { + int NewIndex = BufferCursor->realIndex(); + KSection FirstWordSelection = BufferRanges->firstWordSelection(); + KWordBufferService WBS( DataBuffer, Codec ); + // are we before the selection? + if( NewIndex < FirstWordSelection.start() ) + { + BufferRanges->ensureWordSelectionForward( false ); + NewIndex = WBS.indexOfLeftWordSelect( NewIndex ); + } + // or behind? + else if( NewIndex > FirstWordSelection.end() ) + { + BufferRanges->ensureWordSelectionForward( true ); + NewIndex = WBS.indexOfRightWordSelect( NewIndex ); + } + // or inside? + else + { + BufferRanges->ensureWordSelectionForward( true ); + NewIndex = FirstWordSelection.end()+1; + } + + BufferCursor->gotoIndex( NewIndex ); + } + + if( BufferRanges->selectionStarted() ) + BufferRanges->setSelectionEnd( BufferCursor->realIndex() ); + + repaintChanged(); + + unpauseCursor(); +} + + +void KHexEdit::startDrag() +{ + // reset states + MousePressed = false; + InDoubleClick = false; + DragStartPossible = false; + + // create data + QDragObject *Drag = dragObject( viewport() ); + if( !Drag ) + return; + + // will we only copy the data? + if( isReadOnly() || OverWrite ) + Drag->dragCopy(); + // or is this left to the user and he choose to move? + else if( Drag->drag() ) + // Not inside this widget itself? + if( QDragObject::target() != this && QDragObject::target() != viewport() ) + removeSelectedData(); +} + + +void KHexEdit::contentsDragEnterEvent( QDragEnterEvent *e ) +{ + // interesting for this widget? + if( isReadOnly() || !KBufferDrag::canDecode(e) ) + { + e->ignore(); + return; + } + + e->acceptAction(); + InDnD = true; +} + + +void KHexEdit::contentsDragMoveEvent( QDragMoveEvent *e ) +{ + // is this content still interesting for us? + if( isReadOnly() || !KBufferDrag::canDecode(e) ) + { + e->ignore(); + return; + } + + // let text cursor follow mouse + pauseCursor( true ); + placeCursor( e->pos() ); + unpauseCursor(); + + e->acceptAction(); +} + + +void KHexEdit::contentsDragLeaveEvent( QDragLeaveEvent * ) +{ + // bye... and thanks for all the cursor movement... + InDnD = false; +} + + + +void KHexEdit::contentsDropEvent( QDropEvent *e ) +{ + // after drag enter and move check one more time + if( isReadOnly() ) + return; + + // leave state + InDnD = false; + e->acceptAction(); + + if( !KBufferDrag::canDecode(e) ) //TODO: why do we acept the action still? + return; + + // is this an internal dnd? + if( e->source() == this || e->source() == viewport() ) + handleInternalDrag( e ); + else + { + //BufferRanges->removeSelection(); + pasteFromSource( e ); + } +} + + +void KHexEdit::handleInternalDrag( QDropEvent *e ) +{ + KSection ChangedRange; + + // stop ui + pauseCursor(); + + // get drag origin + KSection Selection = BufferRanges->selection(); + int InsertIndex = BufferCursor->realIndex(); + + // is this a move? + if( e->action() == QDropEvent::Move ) + { + // ignore the copy hold in the event but only move + int NewIndex = DataBuffer->move( InsertIndex, Selection ); + if( NewIndex != Selection.start() ) + { + BufferCursor->gotoCIndex( NewIndex+Selection.width() ); + ChangedRange.set( QMIN(InsertIndex,Selection.start()), QMAX(InsertIndex,Selection.end()) ); + } + } + // is a copy + else + { + // get data + QByteArray Data; + if( KBufferDrag::decode(e,Data) && !Data.isEmpty() ) + { + if( OverWrite ) + { + if( !BufferCursor->isBehind() ) + { + ChangedRange.setByWidth( InsertIndex, Data.size() ); + ChangedRange.restrictEndTo( BufferLayout->length()-1 ); + if( ChangedRange.isValid() ) + { + int NoOfReplaced = DataBuffer->replace( ChangedRange, Data.data(), ChangedRange.width() ); + BufferCursor->gotoNextByte( NoOfReplaced ); + } + } + } + else + { + int NoOfInserted = DataBuffer->insert( InsertIndex, Data.data(), Data.size() ); + updateLength(); + if( NoOfInserted > 0 ) + { + BufferCursor->gotoCIndex( InsertIndex + NoOfInserted ); + ChangedRange.set( InsertIndex, DataBuffer->size()-1 ); + } + } + } + } + BufferRanges->addChangedRange( ChangedRange ); + BufferRanges->removeSelection(); + + repaintChanged(); + ensureCursorVisible(); + + // open ui + unpauseCursor(); + + // emit appropriate signals. + emit selectionChanged( -1, -1 ); + if( ChangedRange.isValid() ) emit bufferChanged( ChangedRange.start(), ChangedRange.end() ); + emit cursorPositionChanged( BufferCursor->index() ); +} + + +void KHexEdit::contentsWheelEvent( QWheelEvent *e ) +{ + if( isReadOnly() ) + { + if( e->state() & ControlButton ) + { + if( e->delta() > 0 ) + zoomOut(); + else if( e->delta() < 0 ) + zoomIn(); + return; + } + } + QScrollView::contentsWheelEvent( e ); +} + + +#if 0 +void KHexEdit::contentsContextMenuEvent( QContextMenuEvent *e ) +{ +// clearUndoRedo(); + MousePressed = false; + + e->accept(); + + QPopupMenu *PopupMenu = createPopupMenu( e->pos() ); + if( !PopupMenu ) + PopupMenu = createPopupMenu(); + if( !PopupMenu ) + return; + int r = PopupMenu->exec( e->globalPos() ); + delete PopupMenu; + + if ( r == d->id[ IdClear ] ) + clear(); + else if ( r == d->id[ IdSelectAll ] ) + { + selectAll(); + // if the clipboard support selections, put the newly selected text into the clipboard + if( QApplication::clipboard()->supportsSelection() ) + { + ClipboardMode = QClipboard::Selection; + disconnect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, 0); + + copy(); + + connect( QApplication::clipboard(), SIGNAL(selectionChanged()), this, SLOT(clipboardChanged()) ); + ClipboardMode = QClipboard::Clipboard; + } + } + else if( r == d->id[IdUndo] ) + undo(); + else if( r == d->id[IdRedo] ) + redo(); + else if( r == d->id[IdCut] ) + cut(); + else if( r == d->id[IdCopy] ) + copy(); + else if( r == d->id[IdPaste] ) + paste(); +} +#endif + +#include "khexedit.moc" diff --git a/khexedit/lib/khexedit.h b/khexedit/lib/khexedit.h new file mode 100644 index 0000000..66059c8 --- /dev/null +++ b/khexedit/lib/khexedit.h @@ -0,0 +1,562 @@ +/*************************************************************************** + khexedit.h - description + ------------------- + begin : Die Mai 13 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KHEXEDIT_H +#define KHE_KHEXEDIT_H + +// qt specific +#include <qclipboard.h> +// lib specific +// #include "khe.h" +#include "khexedit_export.h" +#include "kcolumnsview.h" + +class QTimer; + +namespace KHE +{ + +class KCoordRange; + +class KDataBuffer; + +class KCharColumn; +class KValueColumn; +class KBufferColumn; +class KOffsetColumn; +class KBorderColumn; + +class KBufferCursor; +class KBufferLayout; +class KBufferRanges; + +class KController; +class KTabController; +class KNavigator; +class KValueEditor; +class KCharEditor; + +class KBufferDrag; + +class KCursor; +class KCharCodec; + +class KHexEditPrivate; + + +/** the main widget + * + * The functions split up in helper functions and those that are complete. + * + * Complete functions can be called from the outside and leave the widget in + * a consistent state. They care for exceptions so one can safely call them in all + * situations (like empty buffer, cursor behind end etc.) + * + * Helper functions do only partial tasks and need to be completed. They often do not + * check for exceptions so one has to care for this. + * + *@author Friedrich W. H. Kossebau + */ + +class KHEXEDIT_EXPORT KHexEdit : public KColumnsView +{ + friend class KTabController; + friend class KNavigator; + friend class KEditor; + friend class KValueEditor; + friend class KCharEditor; + + Q_OBJECT + Q_ENUMS( KResizeStyle KCoding ) + Q_PROPERTY( bool OverwriteMode READ isOverwriteMode WRITE setOverwriteMode ) + Q_PROPERTY( bool OverwriteOnly READ isOverwriteOnly WRITE setOverwriteOnly ) + Q_PROPERTY( bool Modified READ isModified WRITE setModified DESIGNABLE false ) + Q_PROPERTY( bool ReadOnly READ isReadOnly WRITE setReadOnly ) + + Q_PROPERTY( int NoOfBytesPerLine READ noOfBytesPerLine WRITE setNoOfBytesPerLine ) + Q_PROPERTY( bool TabChangesFocus READ tabChangesFocus WRITE setTabChangesFocus ) + + //Q_PROPERTY( bool hasSelectedData READ hasSelectedData ) + //Q_PROPERTY( QByteArray SelectedData READ selectedData ) + Q_PROPERTY( KResizeStyle ResizeStyle READ resizeStyle WRITE setResizeStyle ) + Q_PROPERTY( int StartOffset READ startOffset WRITE setStartOffset ) + Q_PROPERTY( int FirstLineOffset READ firstLineOffset WRITE setFirstLineOffset ) + //_PROPERTY( int undoDepth READ undoDepth WRITE setUndoDepth ) + //_PROPERTY( bool undoRedoEnabled READ isUndoRedoEnabled WRITE setUndoRedoEnabled ) + // value column + Q_PROPERTY( KCoding Coding READ coding WRITE setCoding ) + Q_PROPERTY( int ByteSpacingWidth READ byteSpacingWidth WRITE setByteSpacingWidth ) + Q_PROPERTY( int NoOfGroupedBytes READ noOfGroupedBytes WRITE setNoOfGroupedBytes ) + Q_PROPERTY( int GroupSpacingWidth READ groupSpacingWidth WRITE setGroupSpacingWidth ) + Q_PROPERTY( int BinaryGapWidth READ binaryGapWidth WRITE setBinaryGapWidth ) + // char column + Q_PROPERTY( bool ShowUnprintable READ showUnprintable WRITE setShowUnprintable ) + Q_PROPERTY( QChar SubstituteChar READ substituteChar WRITE setSubstituteChar ) + + public: + enum KResizeStyle { NoResize=0, LockGrouping=1, FullSizeUsage=2, MaxResizeStyleId=0xFF }; + enum KCoding { HexadecimalCoding=0, DecimalCoding=1, OctalCoding=2, BinaryCoding=3, MaxCodingId=0xFFFF }; + enum KEncoding { LocalEncoding=0, ISO8859_1Encoding=1, EBCDIC1047Encoding=2, + StartOfOwnEncoding=0x8000, MaxEncodingId=0xFFFF }; + + enum KBufferColumnId { ValueColumnId=1, CharColumnId=2 }; + + + public: + KHexEdit( KDataBuffer *Buffer = 0, QWidget *Parent = 0, const char *Name = 0, WFlags F = 0 ); + virtual ~KHexEdit(); + + + public: // KColumnsView API + virtual void drawContents( QPainter *p, int cx, int cy, int cw, int ch ); + + public: // QWidget API +// void focusInEvent( QFocusEvent *FocusEvent ); // TODO: why don't these work? +// void focusOutEvent( QFocusEvent *FocusEvent ); + virtual bool eventFilter( QObject *O, QEvent *E ); + + virtual QSize sizeHint() const; + virtual QSize minimumSizeHint() const; + + + public: // value access + /** returns the index of the cursor position */ + int cursorPosition() const; + /***/ + bool isCursorBehind() const; + KBufferColumnId cursorColumn() const; + + bool isOverwriteMode() const; + bool isOverwriteOnly() const; + bool isReadOnly() const; + bool isModified() const; + + bool tabChangesFocus() const; + + KResizeStyle resizeStyle() const; + int noOfBytesPerLine() const; + int startOffset() const; + int firstLineOffset() const; + + bool offsetColumnVisible() const; + int visibleBufferColumns() const; + + // value column + KCoding coding() const; + int/*KPixelX*/ byteSpacingWidth() const; + int noOfGroupedBytes() const; + int/*KPixelX*/ groupSpacingWidth() const; + int/*KPixelX*/ binaryGapWidth() const; + + // char column + /** reports if "unprintable" chars (value<32) are displayed in the char column + * with their original character. Default is false + * @return @c true if original chars are displayed, otherwise @c false + */ + bool showUnprintable() const; + /** gives the used substitute character for "unprintable" chars, default is '.' + * @return substitute character + */ + QChar substituteChar() const; + /** returns the actually used undefined character for "undefined" chars, default is '?' */ + QChar undefinedChar() const; + /** + * @return encoding used in the char column + */ + KEncoding encoding() const; + /** + * @return name of the encoding used in the char column + */ + const QString &encodingName() const; + + public: // logic value service + /** calculates the number of bytes per line that fit into a widget with the given size + * tests whether a vertical scroll bar is needed at all or not due to the given width + * takes the frame width into account + * @param TestSize Size the widget might have + * @return number of bytes per line that fit into a widget with the given size + */ + int fittingBytesPerLine( const QSize &TestSize ) const; + /** detects the index of the byte at the given point + * @param Point in viewport coordinate system + * @return index of the byte that covers the point + */ + int indexByPoint(const QPoint &Point ) const; + + public: + /** returns true if there is a selected range in the array */ + bool hasSelectedData() const; + /** + * @return deep copy of the selected data + */ + QByteArray selectedData() const; + KSection selection() const; + + public: // modification access + /** puts the cursor to the position of index, handles all drawing + * @param Index + */ + void setCursorPosition( int Index, bool Behind=false ); + /** puts the cursor in the column at the pos of Point (in absolute coord), does not handle the drawing */ + void placeCursor( const QPoint &Point ); + /***/ + void setCursorColumn( KBufferColumnId ); +// void repaintByte( int row, int column, bool Erase = true ); +// void updateByte( int row, int column ); +// void ensureByteVisible( int row, int column ); + + public slots: + /** */ + void setDataBuffer( KDataBuffer *B ); + + /** switches the Offset column on/off */ + void toggleOffsetColumn( bool Visible ); + /** */ + void showBufferColumns( int Columns ); + /** scrolls the view as much as needed to have the cursor fully visible */ + void ensureCursorVisible(); + + // setting parameters + /** sets the resizestyle for the value column. Default is KHE::FullSizeUsage */ + void setResizeStyle( KResizeStyle Style ); + /** sets whether the widget is readonly or not, Default is true. + * If the databuffer which is worked on can't be written the widget stays readonly + */ + virtual void setReadOnly( bool b ); + /** sets whether the widget is overwriteonly or not. Default is false. */ + virtual void setOverwriteOnly( bool b ); + /** sets whether the widget is in overwrite mode or not. Default is true. */ + virtual void setOverwriteMode( bool b ); + /** sets whether the data should be treated modified or not */ + virtual void setModified( bool b ); + /** sets whether on a tab key there should be switched from the char column back to the value column + * or be switched to the next focusable widget. Default is false + */ + virtual void setTabChangesFocus( bool b = true ); + // + /** sets the number of bytes per line, switching the resize style to KHE::NoResize */ + virtual void setNoOfBytesPerLine( int NoCpL ); + /** sets absolut offset of the data */ + void setStartOffset( int SO ); + /** sets offset of the char in the upper left corner */ + void setFirstLineOffset( int FLO ); + // value column parameters + /** sets the spacing between the bytes in the value column + * @param BSW spacing between the bytes in pixels + * default is 3 + */ + void setByteSpacingWidth( int/*KPixelX*/ BSW ) ; + /** sets the number of grouped bytes in the value column + * @param NoGB numbers of grouped bytes, 0 means no grouping + * default is 4 + */ + void setNoOfGroupedBytes( int NoGB ); + /** sets the spacing between the groups of bytes in the value column + * @param GSW spacing between the groups in pixels + * default is 9 + */ + void setGroupSpacingWidth( int/*KPixelX*/ GSW ); + /** sets the spacing in the middle of a binary byte in the value column + * @param BinaryGapW spacing in the middle of a binary in pixels + * returns true if there was a change + */ + void setBinaryGapWidth( int BGW ); + /** sets the spacing in the value column + * @param ByteSpacingWidth spacing between the bytes in pixels + * @param NoOfGroupedBytes numbers of grouped bytes, 0 means no grouping + * @param GroupSpacingWidth spacing between the groups in pixels + * Default is 4 for NoOfGroupedBytes + */ + void setBufferSpacing( KPixelX ByteSpacingWidth, int NoOfGroupedBytes = 0, KPixelX GroupSpacingWidth = 0 ); + /** sets the format of the value column. Default is KHE::HexadecimalCoding */ + void setCoding( KCoding C ); + // char column parameters + /** sets whether "unprintable" chars (>32) should be displayed in the char column + * with their corresponding character. + * @param SU + * returns true if there was a change + */ + void setShowUnprintable( bool SU = true ); + /** sets the substitute character for "unprintable" chars + * returns true if there was a change + */ + void setSubstituteChar( QChar SC ); + /** sets the undefined character for "undefined" chars + * returns true if there was a change + */ + void setUndefinedChar( QChar UC ); + /** sets the encoding of the char column. Default is KHE::LocalEncoding. + * If the encoding is not available the format will not be changed. */ + void setEncoding( KEncoding C ); + /** sets the encoding of the char column. Default is KHE::LocalEncoding. + * If the encoding is not available the format will not be changed. + * @param Encoding name of the encoding + */ + void setEncoding( const QString& Encoding ); + + // interaction + /** de-/selects all data */ + void selectAll( bool select ); + /** de-/selects all data */ + void select( KSection S ); + /** selects word at index, returns true if there is one */ + bool selectWord( /*unsigned*/ int Index /*, Chartype*/ ); + /** removes the selected data, takes care of the cursor */ + virtual void removeSelectedData(); + /** inserts */ + virtual void insert( const QByteArray &D ); + + // clipboard interaction + virtual void copy(); + virtual void cut(); + virtual void paste(); + + // zooming + virtual void zoomIn( int PointInc ); + virtual void zoomIn(); + virtual void zoomOut( int PointInc ); + virtual void zoomOut(); + virtual void zoomTo( int PointSize ); + virtual void unZoom(); + + // cursor control + /** we have focus again, start the timer */ + virtual void startCursor(); + /** we lost focus, stop the timer */ + virtual void stopCursor(); + /** simply pauses any blinking, i.e. ignores any calls to blinkCursor */ + virtual void pauseCursor( bool LeaveEdit = false ); + /** undoes pauseCursor */ + virtual void unpauseCursor(); + + + signals: + /** Index of the byte that was clicked */ + void clicked( int Index ); + /** Index of the byte that was double clicked */ + void doubleClicked( int Index ); + + void cursorPositionChanged( int Index ); + /** selection has changed */ + void selectionChanged( int StartIndex, int EndIndex ); + /** there is a cut available or not */ + void cutAvailable( bool Really ); + /** there is a copy available or not */ + void copyAvailable( bool Really ); + /** there has been a change to the buffer */ + void bufferChanged( int StartIndex, int EndIndex ); + + + protected: // QWidget API + virtual void keyPressEvent( QKeyEvent *KeyEvent ); + virtual void resizeEvent( QResizeEvent *ResizeEvent ); + virtual void showEvent( QShowEvent *e ); + + protected: // QScrollView API + virtual void contentsMousePressEvent( QMouseEvent *e ); + virtual void contentsMouseReleaseEvent( QMouseEvent * e ); + virtual void contentsMouseMoveEvent( QMouseEvent *e ); + virtual void contentsMouseDoubleClickEvent( QMouseEvent * e ); + virtual void contentsDragEnterEvent( QDragEnterEvent *e ); + virtual void contentsDragMoveEvent( QDragMoveEvent *e ); + virtual void contentsDragLeaveEvent( QDragLeaveEvent * ); + virtual void contentsDropEvent( QDropEvent *e ); + virtual void contentsWheelEvent( QWheelEvent *e ); +// virtual void contentsContextMenuEvent( QContextMenuEvent *e ); + + protected: // KColumnsView API + virtual void setNoOfLines( int NewNoOfLines ); + + + protected: // element accessor functions + KValueColumn& valueColumn(); + KCharColumn& charColumn(); + KBufferColumn& activeColumn(); + KBufferColumn& inactiveColumn(); + const KValueColumn& valueColumn() const; + const KCharColumn& charColumn() const; + const KBufferColumn& activeColumn() const; + const KBufferColumn& inactiveColumn() const; + + protected: // atomic ui operations + /** handles screen update in case of a change to any of the width sizes + */ + void updateViewByWidth(); + /** repaints all the parts that are signed as changed */ + void repaintChanged(); + + protected: // drawing related operations + /** recreates the cursor pixmaps and paints active and inactive cursors if doable */ + void updateCursor(); + void createCursorPixmaps(); + void pointPainterToCursor( QPainter &Painter, const KBufferColumn &Column ) const; + /** draws the blinking cursor or removes it */ + void paintActiveCursor( bool CursorOn ); + void paintInactiveCursor( bool CursorOn ); + void paintLine( KBufferColumn *C, int Line, KSection Positions ); + + protected: // partial operations + void handleMouseMove( const QPoint& Point ); + KBufferDrag *dragObject( QWidget *Parent = 0 ) const; + void pasteFromSource( QMimeSource *Source ); + /** removes the section from the databuffer and updates all affected values */ + KSection removeData( KSection Indizes ); + /** sets ChangedRange to the range of VisibleRange that is actually changed + * @return true if there was a change within the visible range + */ + bool hasChanged( const KCoordRange &VisibleRange, KCoordRange *ChangedRange ) const; + void handleInternalDrag( QDropEvent *e ); + + protected: + /** recalcs all dependant values with the actual NoOfBytesPerLine */ + void adjustToLayoutNoOfBytesPerLine(); + /** recalcs a layout due to the resize style that fits into the view size + * and updates the dependant values + */ + void adjustLayoutToSize(); + /** */ + void updateLength(); + /** calls updateContent for the Column */ + void updateColumn( KColumn &Column ); + + protected slots: + /** gets called by the cursor blink timer */ + void blinkCursor(); + /** gets called by the scroll timer (for mouse selection) */ + void autoScrollTimerDone(); + /** */ + void clipboardChanged(); + /** */ + void startDrag(); + + protected slots: // QWidget API + virtual void fontChange( const QFont &OldFont ); + + + protected: + /** Buffer with the data */ + KDataBuffer *DataBuffer; + + /** holds the logical layout */ + KBufferLayout *BufferLayout; + /** */ + KBufferCursor *BufferCursor; + /** */ + KBufferRanges *BufferRanges; + + + protected: + KOffsetColumn *OffsetColumn; + KBorderColumn *FirstBorderColumn; + KValueColumn *ValueColumn; + KBorderColumn *SecondBorderColumn; + KCharColumn *CharColumn; + + /** points to the column with keyboard focus */ + KBufferColumn *ActiveColumn; + /** points to the column without keyboard focus (if there is) */ + KBufferColumn *InactiveColumn; + + /** the actual input controller */ + KController *Controller; + /** */ + KTabController *TabController; + /** */ + KNavigator *Navigator; + /** */ + KValueEditor *ValueEditor; + /** */ + KCharEditor *CharEditor; + + protected: + /** Timer that controls the blinking of the cursor */ + QTimer *CursorBlinkTimer; + /** Timer that triggers ensureCursorVisible function calls */ + QTimer *ScrollTimer; +/* QTimer *ChangeIntervalTimer, */ + /** Timer to start a drag */ + QTimer *DragStartTimer; + /** timer to measure whether the time between a double click and the following counts for a tripleclick */ + QTimer *TrippleClickTimer; + + /** object to store the blinking cursor pixmaps */ + KCursor *CursorPixmaps; + /** */ + KCharCodec *Codec; + + protected: + /** point at which the current double click happended (used by TrippleClick) */ + QPoint DoubleClickPoint; + /** line in which the current double click happended (used by TrippleClick) */ + int DoubleClickLine; + /** point at which the current dragging started */ + QPoint DragStartPoint; + /** */ + QClipboard::Mode ClipboardMode; + /** font size as set by user (used for zooming) */ + int DefaultFontSize; + + protected: // parameters + /** style of resizing */ + KResizeStyle ResizeStyle; + /** */ + KEncoding Encoding; + + /** flag whether the widget is set to readonly. Cannot override the databuffer's setting, of course. */ + bool ReadOnly:1; + /** flag if only overwrite is allowed */ + bool OverWriteOnly:1; + /** flag if overwrite mode is active */ + bool OverWrite:1; + /** flag if a mouse button is pressed */ + bool MousePressed:1; + /** flag if a double click is happening */ + bool InDoubleClick:1; + /** flag if a Drag'n'Drop is happening */ + bool InDnD:1; + /** flag if a drag might have started */ + bool DragStartPossible:1; + /** flag if the cursor should be invisible */ + bool CursorPaused:1; + /** flag if the cursor is visible */ + bool BlinkCursorVisible:1; + /** flag whether the font is changed due to a zooming */ + bool InZooming:1; + + private: + /** the binary compatibility saving helper */ + KHexEditPrivate* d; + + private: // Disabling copy constructor and operator= - not useful + KHexEdit( const KHexEdit & ); + KHexEdit &operator=( const KHexEdit & ); +}; + + +inline const KValueColumn& KHexEdit::valueColumn() const { return *ValueColumn; } +inline const KCharColumn& KHexEdit::charColumn() const { return *CharColumn; } +inline const KBufferColumn& KHexEdit::activeColumn() const { return *ActiveColumn; } +inline const KBufferColumn& KHexEdit::inactiveColumn() const { return *InactiveColumn; } + +inline KValueColumn& KHexEdit::valueColumn() { return *ValueColumn; } +inline KCharColumn& KHexEdit::charColumn() { return *CharColumn; } +inline KBufferColumn& KHexEdit::activeColumn() { return *ActiveColumn; } +inline KBufferColumn& KHexEdit::inactiveColumn() { return *InactiveColumn; } + +} + +#endif diff --git a/khexedit/lib/khexedit_export.h b/khexedit/lib/khexedit_export.h new file mode 100644 index 0000000..f922516 --- /dev/null +++ b/khexedit/lib/khexedit_export.h @@ -0,0 +1,25 @@ +/*************************************************************************** + khexedit_export.h - description + ------------------- + begin : 22 Nov 2004 + copyright : (C) 2004 Dirk Mueller + email : mueller@kde.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHEXEDIT_EXPORT_H +#define KHEXEDIT_EXPORT_H + +#include <kdemacros.h> + +#define KHEXEDIT_EXPORT KDE_EXPORT + +#endif diff --git a/khexedit/lib/koffsetcoltextexport.cpp b/khexedit/lib/koffsetcoltextexport.cpp new file mode 100644 index 0000000..c5644df --- /dev/null +++ b/khexedit/lib/koffsetcoltextexport.cpp @@ -0,0 +1,61 @@ +/*************************************************************************** + koffsetcoltextexport.cpp - description + ------------------- + begin : Sam Aug 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qstring.h> +// lib specific +#include "koffsetcolumn.h" +#include "koffsetcoltextexport.h" + +using namespace KHE; + + +KOffsetColTextExport::KOffsetColTextExport( const KOffsetColumn *OffsetColumn ) + : CodingWidth( OffsetColumn->codingWidth() ), + FirstLineOffset( OffsetColumn->firstLineOffset() ), + Delta( OffsetColumn->delta() ), + printFunction( OffsetColumn->printFunction() ) +{ +} + +int KOffsetColTextExport::charsPerLine() const +{ + return CodingWidth; +} + + +void KOffsetColTextExport::printFirstLine( QString &T, int Line ) const +{ + PrintLine = Line; + print( T ); +} + +void KOffsetColTextExport::printNextLine( QString &T ) const +{ + print( T ); +} + +void KOffsetColTextExport::print( QString &T ) const +{ + // TODO: fix me (no more printFunction) + char *B = new char[CodingWidth+1]; + printFunction( B, FirstLineOffset + Delta*PrintLine ); + T.append( B ); + delete [] B; + + ++PrintLine; +} diff --git a/khexedit/lib/koffsetcoltextexport.h b/khexedit/lib/koffsetcoltextexport.h new file mode 100644 index 0000000..e07e659 --- /dev/null +++ b/khexedit/lib/koffsetcoltextexport.h @@ -0,0 +1,57 @@ +/*************************************************************************** + koffsetcoltextexport.h - description + ------------------- + begin : Sam Aug 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KOFFSETCOLTEXTEXPORT_H +#define KHE_KOFFSETCOLTEXTEXPORT_H + +// lib specific +#include "kcoltextexport.h" +#include "koffsetformat.h" + + +namespace KHE +{ + +class KOffsetColumn; + +class KOffsetColTextExport : public KColTextExport +{ + public: + KOffsetColTextExport( const KOffsetColumn *OC ); + + public: // KColTextExport API + void printFirstLine( QString &T, int Line ) const; + void printNextLine( QString &T ) const; + /** tells how much chars per line are needed */ + int charsPerLine() const; + + protected: + void print( QString &T ) const; + + protected: + const int CodingWidth; + const int FirstLineOffset; + const int Delta; + const KOffsetFormat::print printFunction; + + /** the line we are in */ + mutable int PrintLine; +}; + +} + +#endif diff --git a/khexedit/lib/koffsetcolumn.cpp b/khexedit/lib/koffsetcolumn.cpp new file mode 100644 index 0000000..6bd6d09 --- /dev/null +++ b/khexedit/lib/koffsetcolumn.cpp @@ -0,0 +1,110 @@ +/*************************************************************************** + koffsetcolumn.cpp - description + ------------------- + begin : Mit Mai 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + +// qt specific +#include "qpainter.h" +// lib specific +#include "kcolumnsview.h" +#include "koffsetcolumn.h" + +using namespace KHE; + +KOffsetColumn::KOffsetColumn( KColumnsView *V, int FLO, int D, KOffsetFormat::KFormat F ) + : KColumn( V ), + FirstLineOffset( FLO ), + Delta( D ), + Margin( 0 ), + DigitWidth( 0 ), + DigitBaseLine( 0 ), + Format( KOffsetFormat::None ) +{ + setFormat( F ); +} + + +KOffsetColumn::~KOffsetColumn() +{ +} + + +void KOffsetColumn::paintLine( QPainter *P, int Line ) +{ + const QColor &ButtonColor = View->colorGroup().button(); + P->fillRect( 0,0,width(),LineHeight, QBrush(ButtonColor,Qt::SolidPattern) ); + + printFunction()( CodedOffset,FirstLineOffset+Delta*Line ); + P->drawText( 0, DigitBaseLine, QString().append(CodedOffset) ); +} + + +void KOffsetColumn::paintFirstLine( QPainter *P, KPixelXs, int FirstLine ) +{ + PaintLine = FirstLine; + paintLine( P, PaintLine++ ); +} + + +void KOffsetColumn::paintNextLine( QPainter *P ) +{ + paintLine( P, PaintLine++ ); +} + + + +void KOffsetColumn::paintEmptyColumn( QPainter *P, KPixelXs Xs, KPixelYs Ys ) +{ + Xs.restrictTo( XSpan ); + + const QColor &ButtonColor = View->colorGroup().button(); + P->fillRect( Xs.start(), Ys.start(), Xs.width(), Ys.width(), QBrush(ButtonColor,Qt::SolidPattern) ); +} + +void KOffsetColumn::setFormat( KOffsetFormat::KFormat F ) +{ + // no changes? + if( Format == F ) + return; + + Format = F; + + CodingWidth = KOffsetFormat::codingWidth( Format ); + PrintFunction = KOffsetFormat::printFunction( Format ); + + recalcX(); +} + +void KOffsetColumn::setMetrics( KPixelX DW, KPixelY DBL ) +{ + DigitBaseLine = DBL; + setDigitWidth( DW ); +} + +void KOffsetColumn::setDigitWidth( KPixelX DW ) +{ + // no changes? + if( DigitWidth == DW ) + return; + + DigitWidth = DW; + + recalcX(); +} + +void KOffsetColumn::recalcX() +{ + // recalculate depend sizes + setWidth( CodingWidth * DigitWidth ); +} diff --git a/khexedit/lib/koffsetcolumn.h b/khexedit/lib/koffsetcolumn.h new file mode 100644 index 0000000..ae182f9 --- /dev/null +++ b/khexedit/lib/koffsetcolumn.h @@ -0,0 +1,109 @@ +/*************************************************************************** + koffsetcolumn.h - description + ------------------- + begin : Mit Mai 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KOFFSETCOLUMN_H +#define KHE_KOFFSETCOLUMN_H + +// lib specific +#include "koffsetformat.h" +#include "kcolumn.h" + +namespace KHE +{ + +/** + *@author Friedrich W. H. Kossebau + */ + +class KOffsetColumn : public KColumn +{ + public: + KOffsetColumn( KColumnsView *V, int FLO, int D, KOffsetFormat::KFormat F ); + virtual ~KOffsetColumn(); + + public: // KColumn API + virtual void paintFirstLine( QPainter *P, KPixelXs Xs, int FirstLine ); + virtual void paintNextLine( QPainter *P ); + virtual void paintEmptyColumn( QPainter *P, KPixelXs Xs, KPixelYs Ys ); + + + public: + void setFirstLineOffset( int FLO ); + void setDelta( int D ); + + void setFormat( KOffsetFormat::KFormat F ); + /** sets width of digits and recalculates depend sizes */ + void setDigitWidth( KPixelX DW ); + /** */ + void setMetrics( KPixelX DW, KPixelY DBL ); + + public: // read access + int delta() const; + int firstLineOffset() const; + int codingWidth() const; + KOffsetFormat::print printFunction() const; + + + protected: + /** recalculates all x values */ + void recalcX(); + /** paints full line */ + void paintLine( QPainter *P, int Line ); + + + protected: // user settings + /** starting offset of the first line + * if different from StartOffset results in leading space + */ + int FirstLineOffset; + /** offset delta per line */ + int Delta; + + protected: // pixel related + /** size of the line margin */ + int Margin; + /** */ + KPixelX DigitWidth; + /** */ + KPixelY DigitBaseLine; + + protected: // general layout + KOffsetFormat::KFormat Format; + + int CodingWidth; + KOffsetFormat::print PrintFunction; + + /** buffer to hold the formatted coding */ + mutable char CodedOffset[KOffsetFormat::MaxFormatWidth+1]; + + protected: // firstnext trips related + /** */ + int PaintLine; +}; + + +inline int KOffsetColumn::firstLineOffset() const { return FirstLineOffset; } +inline void KOffsetColumn::setFirstLineOffset( int FLO ) { FirstLineOffset = FLO; } +inline int KOffsetColumn::delta() const { return Delta; } +inline void KOffsetColumn::setDelta( int D ) { Delta = D; } + +inline int KOffsetColumn::codingWidth() const { return CodingWidth; } +inline KOffsetFormat::print KOffsetColumn::printFunction() const { return PrintFunction; } + +} + +#endif diff --git a/khexedit/lib/koffsetformat.cpp b/khexedit/lib/koffsetformat.cpp new file mode 100644 index 0000000..e82fa9d --- /dev/null +++ b/khexedit/lib/koffsetformat.cpp @@ -0,0 +1,48 @@ +/*************************************************************************** + koffsetformat.cpp - description + ------------------- + begin : Mit Mai 21 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// c specific +#include <stdio.h> +// lib specific +#include "koffsetformat.h" + +using namespace KHE; + + +const unsigned int KOffsetFormat::CodingWidth[2] = { 9, 10 }; + +const KOffsetFormat::print KOffsetFormat::PrintFunction[2] = +{ KOffsetFormat::printHexadecimalOffset, KOffsetFormat::printDecimalOffset }; + + + +void KOffsetFormat::printHexadecimalOffset( char *Buffer, unsigned int Offset ) +{ + sprintf( Buffer, "%04X:%04X", Offset>>16, Offset&0x0000FFFF ); +} + + +void KOffsetFormat::printHexadecimalSmallOffset( char *Buffer, unsigned int Offset ) +{ + sprintf( Buffer, "%04x:%04x", Offset>>16, Offset&0x0000FFFF ); +} + + +void KOffsetFormat::printDecimalOffset( char *Buffer, unsigned int Offset ) +{ + sprintf( Buffer, "%010u", Offset ); +} diff --git a/khexedit/lib/koffsetformat.h b/khexedit/lib/koffsetformat.h new file mode 100644 index 0000000..8bd90e2 --- /dev/null +++ b/khexedit/lib/koffsetformat.h @@ -0,0 +1,70 @@ +/*************************************************************************** + koffsetformat.h - description + ------------------- + begin : Mit Mai 21 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KOFFSETFORMAT_H +#define KHE_KOFFSETFORMAT_H + +namespace KHE +{ + +/** + *@author Friedrich W. H. Kossebau + */ + +class KOffsetFormat +{ + public: + /** */ + typedef void (*print)( char *Buffer, unsigned int Offset ); + /** */ + enum KFormat { Hexadecimal=0, Decimal, None }; + /** */ + static const int MaxFormatWidth = 9; + + private: + KOffsetFormat(); + ~KOffsetFormat(); + + public: + /** */ + static unsigned int codingWidth( int i ); + /** */ + static print printFunction( int i ); + + public: + static void printHexadecimalOffset( char *Buffer, unsigned int Offset ); + static void printHexadecimalSmallOffset( char *Buffer, unsigned int Offset ); + static void printDecimalOffset( char *Buffer, unsigned int Offset ); + + protected: + /** */ + static const unsigned int CodingWidth[2]; //TODO: would sizeof(Coding} work? + /** */ + static const print PrintFunction[2]; +}; + + +inline unsigned int KOffsetFormat::codingWidth( int i ) +{ return CodingWidth[i]; } + +inline KOffsetFormat::print KOffsetFormat::printFunction( int i ) +{ return PrintFunction[i]; } + + +} + +#endif diff --git a/khexedit/lib/kplainbuffer.cpp b/khexedit/lib/kplainbuffer.cpp new file mode 100644 index 0000000..63c1db7 --- /dev/null +++ b/khexedit/lib/kplainbuffer.cpp @@ -0,0 +1,344 @@ +/*************************************************************************** + kplainbuffer.cpp - description + ------------------- + begin : Mit Jun 03 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + +//#include <kdebug.h> +// c specific +#include <string.h> +#include <stdlib.h> +// lib specific +#include "kplainbuffer.h" + + +static const unsigned int MinChunkSize = 512; +static const unsigned int MaxChunkSize = 1024*10; // TODO: get max. memory page size + +// TODO: think about realloc & Co. +using namespace KHE; + +KPlainBuffer::KPlainBuffer( char *D, unsigned int S, int RS, bool KM ) + : Data( D ), + Size( S ), + RawSize( RS<(int)S?S:RS ), + MaxSize( -1 ), + KeepsMemory( KM ), + ReadOnly( true ), + Modified( false ) +{ +} + +KPlainBuffer::KPlainBuffer( const char *D, unsigned int S ) + : Data( (char *)D ), + Size( S ), + RawSize( S ), + MaxSize( -1 ), + KeepsMemory( true ), + ReadOnly( true ), + Modified( false ) +{ +} + +KPlainBuffer::KPlainBuffer( int S, int MS ) + : Data( S?new char[S]:0 ), + Size( S ), + RawSize( S ), + MaxSize( MS ), + KeepsMemory( false ), + ReadOnly( true ), + Modified( false ) +{ +} + +KPlainBuffer::~KPlainBuffer() +{ +} + + + +int KPlainBuffer::insert( int Pos, const char* D, int Length ) +{ + // check all parameters + if( Length == 0 ) + return 0; + //kdDebug() << QString("before: Size: %1, RawSize: %2").arg(Size).arg(RawSize) << endl; + // correct for appending + if( Pos > (int)Size ) + Pos = Size; + + Length = addSize( Length, Pos, true ); + + // copy new data to its place + memcpy( &Data[Pos], D, Length ); + + //kdDebug() << QString("after: Size: %1, RawSize: %2").arg(Size).arg(RawSize) << endl; + + Modified = true; + return Length; +} + + +int KPlainBuffer::remove( KSection Remove ) +{ + if( Remove.startsBehind(Size-1) || Remove.width() == 0 ) + return 0; + + Remove.restrictEndTo( Size-1 ); + + unsigned int BehindRemovePos = Remove.end()+1; + // move right data behind the input range + memmove( &Data[Remove.start()], &Data[BehindRemovePos], Size-BehindRemovePos ); + + // set new values + Size -= Remove.width(); + + Modified = true; + return Remove.width(); +} + + +unsigned int KPlainBuffer::replace( KSection Remove, const char* D, unsigned int InputLength ) +{ + // check all parameters + if( Remove.start() >= (int)Size || (Remove.width()==0 && InputLength==0) ) + return 0; + + Remove.restrictEndTo( Size-1 ); + + int SizeDiff = InputLength - Remove.width(); + unsigned int NewSize = Size + SizeDiff; + // check if buffer does not get to big TODO: make algo simplier and less if else + if( MaxSize != -1 && (int)NewSize > MaxSize) + { + if( (int)Size == MaxSize ) + return 0; + InputLength -= NewSize - MaxSize; + NewSize = MaxSize; + } + else if( KeepsMemory && NewSize > RawSize ) + { + if( Size == RawSize ) + return 0; + InputLength -= NewSize - RawSize; + NewSize = RawSize; + } + + int BehindInsertPos = Remove.start() + InputLength; + int BehindRemovePos = Remove.end()+1; + + // raw array not big enough? + if( RawSize < NewSize ) + { + // create new buffer + char *NewData = new char[NewSize]; + if( NewData == 0 ) + return 0; + + // move old data to its (new) places + memcpy( NewData, Data, Remove.start() ); + memcpy( &NewData[BehindInsertPos], &Data[BehindRemovePos], Size-BehindRemovePos ); + + // remove old + delete [] Data; + // set new values + Data = NewData; + RawSize = NewSize; + } + else + // move old data to its (new) places + memmove( &Data[BehindInsertPos], &Data[BehindRemovePos], Size-BehindRemovePos ); + + // copy new data to its place + memcpy( &Data[Remove.start()], D, InputLength ); + + // set new values + Size = NewSize; + + Modified = true; + return InputLength; +} + + +int KPlainBuffer::move( int DestPos, KSection SourceSection ) +{ + // check all parameters + if( SourceSection.start() >= (int)Size || SourceSection.width() == 0 + || DestPos > (int)Size || SourceSection.start() == DestPos ) + return SourceSection.start(); + + SourceSection.restrictEndTo( Size-1 ); + bool ToRight = DestPos > SourceSection.start(); + int MovedLength = SourceSection.width(); + int DisplacedLength = ToRight ? DestPos - SourceSection.end()-1 : SourceSection.start() - DestPos; + + // find out section that is smaller + int SmallPartLength, LargePartLength, SmallPartStart, LargePartStart, SmallPartDest, LargePartDest; + // moving part is smaller? + if( MovedLength < DisplacedLength ) + { + SmallPartStart = SourceSection.start(); + SmallPartLength = MovedLength; + LargePartLength = DisplacedLength; + // moving part moves right? + if( ToRight ) + { + SmallPartDest = DestPos - MovedLength; + LargePartStart = SourceSection.end()+1; + LargePartDest = SourceSection.start(); + } + else + { + SmallPartDest = DestPos; + LargePartStart = DestPos; + LargePartDest = DestPos + MovedLength; + } + } + else + { + LargePartStart = SourceSection.start(); + LargePartLength = MovedLength; + SmallPartLength = DisplacedLength; + // moving part moves right? + if( ToRight ) + { + LargePartDest = DestPos - MovedLength; + SmallPartStart = SourceSection.end()+1; + SmallPartDest = SourceSection.start(); + } + else + { + LargePartDest = DestPos; + SmallPartStart = DestPos; + SmallPartDest = DestPos + MovedLength; + } + } + + // copy smaller part to tempbuffer + char *Temp = new char[SmallPartLength]; + memcpy( Temp, &Data[SmallPartStart], SmallPartLength ); + + // move the larger part + memmove( &Data[LargePartDest], &Data[LargePartStart], LargePartLength ); + + // copy smaller part to its new dest + memcpy( &Data[SmallPartDest], Temp, SmallPartLength ); + delete [] Temp; + + Modified = true; + return MovedLength < DisplacedLength ? SmallPartDest : LargePartDest; +} + + +int KPlainBuffer::fill( const char FChar, int FillLength, unsigned int Pos ) +{ + // nothing to fill + if( Pos >= Size ) + return 0; + + int LengthToEnd = Size - Pos; + + if( FillLength < 0 ) + FillLength = LengthToEnd; + else if( FillLength > LengthToEnd ) + FillLength = addSize( FillLength, Pos, false ); + + memset( &Data[Pos], FChar, FillLength ); + Modified = true; + return FillLength; +} + + +int KPlainBuffer::find( const char* SearchString, int Length, KSection Section ) const +{ + Section.restrictEndTo( Size-1 ); + + for( int i = Section.start(); i <= Section.end(); ++i ) + { + int Result; +// if( IgnoreCase ) +// result = strncasecmp( &data()[i], sc.key.data(), sc.key.size() ); +// else + Result = memcmp( &Data[i], SearchString, Length ); + // found? + if( Result == 0 ) + return i; + } + return -1; +} + +int KPlainBuffer::rfind( const char*, int /*Length*/, int /*Pos*/ ) const { return 0; } + + +int KPlainBuffer::addSize( int AddSize, int SplitPos, bool SaveUpperPart ) +{ + unsigned int NewSize = Size + AddSize; + // check if buffer does not get too big + if( MaxSize != -1 && (int)NewSize > MaxSize ) + { + if( (int)Size == MaxSize ) + return 0; + NewSize = MaxSize; + AddSize = NewSize - Size; + } + else if( KeepsMemory && NewSize > RawSize ) + { + if( Size == RawSize ) + return 0; + NewSize = RawSize; + AddSize = NewSize - Size; + } + + int BehindSplitPos = SplitPos + AddSize; + // raw array not big enough? + if( RawSize < NewSize ) + { + // get new raw size + unsigned int ChunkSize = MinChunkSize; + // find chunk size where newsize fits into + while( ChunkSize < NewSize ) + ChunkSize <<= 1; + // limit to max size + if( ChunkSize > MaxChunkSize ) + ChunkSize = MaxChunkSize; + // find add size + unsigned int NewRawSize = ChunkSize; + while( NewRawSize<NewSize ) + NewRawSize += ChunkSize; + // create new buffer + char *NewData = new char[NewRawSize]; + + // move old data to its (new) places + memcpy( NewData, Data, SplitPos ); + if( SaveUpperPart ) + memcpy( &NewData[BehindSplitPos], &Data[SplitPos], Size-SplitPos ); + + // remove old + delete [] Data; + // set new values + Data = NewData; + RawSize = NewRawSize; + } + // old buffer kept + else + { + if( SaveUpperPart ) + // move old data to its (new) places + memmove( &Data[BehindSplitPos], &Data[SplitPos], Size-SplitPos ); + } + + // set new values + Size = NewSize; + + return AddSize; +} diff --git a/khexedit/lib/kplainbuffer.h b/khexedit/lib/kplainbuffer.h new file mode 100644 index 0000000..27bbbad --- /dev/null +++ b/khexedit/lib/kplainbuffer.h @@ -0,0 +1,131 @@ +/*************************************************************************** + kplainbuffer.h - description + ------------------- + begin : Mit Jun 03 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KPLAINBUFFER_H +#define KHE_KPLAINBUFFER_H + +#include "kdatabuffer.h" + +namespace KHE +{ +/* +class KPlainBufferIterator : public KDataBufferIterator +{ +} +*/ +/** base class for all Data buffers that are used to display + * TODO: think about a way to inform KHexEdit that there has been + * a change in the buffer outside. what kind of changes are possible? + *@author Friedrich W. H. Kossebau + */ + +class KPlainBuffer : public KDataBuffer +{ + friend class KPlainBufferIterator; + + public: + KPlainBuffer( char *D, unsigned int S, int RS = -1, bool KM = true ); + KPlainBuffer( const char *D, unsigned int S ); + KPlainBuffer( int S=0, int MS = -1 ); + virtual ~KPlainBuffer(); + + public: // KDataBuffer API + virtual bool prepareRange( KSection Range ) const; + //virtual KDataBufferIterator *iterator() const; + virtual const char *dataSet( KSection S ) const; + virtual char datum( unsigned int Offset ) const; + virtual int size() const; + virtual bool isReadOnly() const; + virtual bool isModified() const; + + virtual int insert( int Pos, const char*, int Length ); + virtual int remove( KSection Remove ); + virtual unsigned int replace( KSection Remove, const char*, unsigned int InputLength ); + virtual int move( int DestPos, KSection SourceSection ); + virtual int fill( const char FillChar, int Length = -1, unsigned int Pos = 0 ); + virtual void setDatum( unsigned int Offset, const char Char ); + + virtual void setModified( bool M = true ); + + //virtual int find( const char*, int Length, int Pos = 0 ) const; + virtual int find( const char*KeyData, int Length, KSection Section ) const; + virtual int rfind( const char*, int Length, int Pos = -1 ) const; + +/* virtual int find( const QString &expr, bool cs, bool wo, bool forward = true, int *index = 0 ); */ + + public: + void setReadOnly( bool RO = true ); + void setMaxSize( int MS ); + /** sets whether the memory given by setData or in the constructor should be kept on resize + */ + void setKeepsMemory( bool KM = true ); + + public: + char *data() const; + int maxSize() const; + /** returns whether the memory of the byte array is kept */ + bool keepsMemory() const; + + protected: + /** resizes the buffer, if possible, saving the data and splitting the data, if demanded + * @param AddSize additional size the buffer should grow + * @param SplitPos if -1 does not split + * @param SaveUpperPart true if upper part should be copied into new buffer + * @return additional size the buffer has grown + */ + int addSize( int AddSize, int SplitPos = -1, bool SaveUpperPart = true ); + + protected: + /** */ + char *Data; + /** size of the data */ + unsigned int Size; + /** Size of data array */ + unsigned int RawSize; + /** maximal size of array, unlimited if -1 */ + int MaxSize; + /** flag whether the initially given memory should be kept */ + bool KeepsMemory:1; + /** */ + bool ReadOnly:1; + /** */ + bool Modified:1; +}; + + +inline bool KPlainBuffer::prepareRange( KSection ) const { return true; } +inline const char *KPlainBuffer::dataSet( KSection S ) const { return &Data[S.start()]; } +inline char KPlainBuffer::datum( unsigned int Offset ) const { return Data[Offset]; } +inline int KPlainBuffer::size() const { return Size; } + +inline bool KPlainBuffer::isReadOnly() const { return ReadOnly; } +inline bool KPlainBuffer::isModified() const { return Modified; } + +inline void KPlainBuffer::setDatum( unsigned int Offset, const char Char ) +{ Data[Offset] = Char; Modified = true; } + +inline void KPlainBuffer::setReadOnly( bool RO ) { ReadOnly = RO; } +inline void KPlainBuffer::setModified( bool M ) { Modified = M; } +inline void KPlainBuffer::setMaxSize( int MS ) { MaxSize = MS; } +inline void KPlainBuffer::setKeepsMemory( bool KM ) { KeepsMemory = KM; } + +inline char *KPlainBuffer::data() const { return Data; } +inline int KPlainBuffer::maxSize() const { return MaxSize; } +inline bool KPlainBuffer::keepsMemory() const { return KeepsMemory; } +} + +#endif diff --git a/khexedit/lib/krange.h b/khexedit/lib/krange.h new file mode 100644 index 0000000..a0df3f1 --- /dev/null +++ b/khexedit/lib/krange.h @@ -0,0 +1,123 @@ +/*************************************************************************** + krange.h - description + ------------------- + begin : Sun 03.08.2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de +****************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KRANGE_H +#define KHE_KRANGE_H + + +namespace KHE +{ + +/** This template describes a range. + * A range is something with a start and an end. + * The start is a value relative before the end. + * The distance cannot be estimated. + * + *@author Friedrich W. H. Kossebau + */ +template<class T> +class KRange +{ + public: + KRange( T S, T E ) : Start( S ), End( E ) {} + KRange() : Start( null() ), End( null() ) {} + ~KRange() {} + + public: + KRange &operator=( const KRange &R ) { Start = R.Start; End = R.End; return *this; } + + public: + bool operator==( const KRange &R ) const { return Start == R.Start && End == R.End; } + + public: // modification access + /** sets the first and the last index of the range */ + void set( T S, T E ) { Start = S; End = E; } + /** sets the first index of the range */ + void setStart( T S ) { Start = S; } + /** sets the last index of the range */ + void setEnd( T E ) { End = E; } + /** sets the range to null */ + void unset() { Start = End = null(); } + /** restricts the range to Limit. If one of both ranges is invalid the behaviour is undefined */ + void restrictTo( const KRange &Limit ) + { if( Start < Limit.start() ) Start = Limit.start(); if( End > Limit.end() ) End = Limit.end(); } + /** restricts the start to Limit. If the range is invalid the behaviour is undefined */ + void restrictStartTo( T Limit ) { if( Start < Limit ) Start = Limit; } + /** restricts the end to Limit. If the range is invalid the behaviour is undefined */ + void restrictEndTo( T Limit ) { if( End > Limit ) End = Limit; } + /** extends the range to Limit. If one of both is invalid the behaviour is undefined */ + void extendTo( const KRange &Limit ) + { if( Start > Limit.start() ) Start = Limit.start(); if( End < Limit.end() ) End = Limit.end(); } + /** extends the start to Limit. If the range is invalid the behaviour is undefined */ + void extendStartTo( T Limit ) { if( Start > Limit ) Start = Limit; } + /** extends the end to Limit. If the range is invalid the behaviour is undefined */ + void extendEndTo( T Limit ) { if( End < Limit ) End = Limit; } + /** moves the range by D. If the range is invalid the behaviour is undefined */ + void moveBy( T D ) { Start += D; End += D; } + + public: // value access + /** @return start */ + T start() const { return Start; } + /** @return end */ + T end() const { return End; } + + + public: // logic access + /** returns true if Value is covered */ + bool includes( T Value ) const { return Value <= End && Value >= Start; } + /** returns true if range is before index. if range is invalid the behaviour is undefined */ + bool endsBefore( T Value ) const { return End < Value; } + /** returns true if range is behind index. if range is invalid the behaviour is undefined */ + bool startsBehind( T Value ) const { return Start > Value; } + /** returns true is the range starts before index. If the range is invalid the behaviour is undefined */ + bool startsBefore( T Value ) const { return Start < Value; } + /** returns true is the range end later then index. If the range is invalid the behaviour is undefined */ + bool endsBehind( T Value ) const { return End > Value; } + + /** returns true is the range covers R. If one of both is invalid the behaviour is undefined */ + bool includes( const KRange &R ) const { return End >= R.End && Start <= R.Start; } + /** returns true is the range ends before R starts. If one of both is invalid the behaviour is undefined */ + bool endsBefore( const KRange &R ) const { return End < R.Start; } + /** returns true is the range starts later than R ends. If one of both is invalid the behaviour is undefined */ + bool startsBehind( const KRange &R ) const { return Start > R.End; } + /** returns true is the range starts prior than R. If one of both is invalid the behaviour is undefined */ + bool startsBefore( const KRange &R ) const { return Start < R.Start; } + /** returns true is the range ends later than R. If one of both is invalid the behaviour is undefined */ + bool endsBehind( const KRange &R ) const { return End > R.End; } + /** returns true is the range shares at least one index with R. If one of both is invalid the behaviour is undefined */ + bool overlaps( const KRange &R ) const { return Start <= R.End && End >= R.Start; } + + /** returns true if the range covers at least one index */ + bool isValid() const { return Start != null() && Start <= End; } + /** returns true if the range has not been set */ + bool isEmpty() const { return Start == null() && End == null(); } + + + protected: + /** delivers a null element. Should be specialiced for complexer types. */ + const T null () const { return T(-1);} + + protected: + /** first value of the range */ + T Start; + /** last value of the range */ + T End; +}; + +} + +#endif diff --git a/khexedit/lib/kreadonlybuffer.h b/khexedit/lib/kreadonlybuffer.h new file mode 100644 index 0000000..63264b2 --- /dev/null +++ b/khexedit/lib/kreadonlybuffer.h @@ -0,0 +1,45 @@ +/*************************************************************************** + kreadonlybuffer.h - description + ------------------- + begin : Mit Mai 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KREADONLYBUFFER_H +#define KHE_KREADONLYBUFFER_H + +#include "kdatabuffer.h" + +namespace KHE +{ + +/** + *@author Friedrich W. H. Kossebau + */ + +class KReadOnlyBuffer : public KDataBuffer +{ + public: + KReadOnlyBuffer() {} + ~KReadOnlyBuffer() {} + + public: // KDataBuffer API + /** is the buffer changeable ?*/ + virtual bool isReadOnly() const { return true; } + /** has the buffer been modified? */ + virtual bool isModified() const { return false; } +}; + +} + +#endif diff --git a/khexedit/lib/ksection.h b/khexedit/lib/ksection.h new file mode 100644 index 0000000..7693219 --- /dev/null +++ b/khexedit/lib/ksection.h @@ -0,0 +1,108 @@ +/*************************************************************************** + ksection.h - description + ------------------- + begin : Sun 22.06.2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de +****************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KSECTION_H +#define KHE_KSECTION_H + + +#include "krange.h" + +namespace KHE +{ + +/** describes a section of indizes + *@author Friedrich W. H. Kossebau + */ +class KSection : public KRange<int> +{ + public: + /** constructs a section + * @param SI starting index + * @param EI end index + */ + KSection( int SI, int EI ); + /** constructs a section + * @param SI starting index + * @param W width of the section + */ + KSection( int SI, int W, bool ); + KSection(); + ~KSection(); + + public: + KSection &operator=( const KSection &S ); + + public: + bool operator==( const KSection &S ) const; + + public: + void setByWidth( int S, int Width ); + /** sets the first index of the section's range one behind the other's end + * If one of both is invalid the behaviour is undefined + */ + void setStartBehind( KSection S ); + /** sets the first index of the section's range one behind the other's end + * If one of both is invalid or the other' start is 0 the behaviour is undefined + */ + void setEndBefore( KSection S ); + /** sets the first index of the section's range to be width-1 before the end + * If the section is invalid the behaviour is undefined + */ + void setStartByWidth( int Width ); + /** sets the last index of the section's range to be width-1 behind the start + * If the section is invalid the behaviour is undefined + */ + void setEndByWidth( int Width ); + /** moves the range defined by a new start. + * If the range is invalid the behaviour is undefined + */ + void moveToStart( int S ); + /** moves the range defined by a new start. + * If the range is invalid the behaviour is undefined + */ + void moveToEnd( int E ); + + public: + /** + * @return the numbered of included indizes or 0, if the section is invalid + */ + int width() const; +}; + + +inline KSection::KSection( int SI, int EI ) : KRange<int>(SI,EI) {} +inline KSection::KSection( int SI, int W, bool ) : KRange<int>(SI,SI+W-1) {} +inline KSection::KSection() {} +inline KSection::~KSection() {} + +inline bool KSection::operator==( const KSection &S ) const { return KRange<int>::operator==(S); } + +inline KSection &KSection::operator=( const KSection &S ) { KRange<int>::operator=(S); return *this; } + +inline int KSection::width() const { return isValid() ? end()-start()+1 : 0; } + +inline void KSection::setByWidth( int S, int Width ) { setStart( S ); setEnd( S+Width-1 ); } +inline void KSection::setStartByWidth( int Width ) { setStart( end()-Width+1 ); } +inline void KSection::setEndByWidth( int Width ) { setEnd( start()+Width-1 ); } +inline void KSection::setStartBehind( KSection S ) { setStart( S.end()+1 ); } +inline void KSection::setEndBefore( KSection S ) { setEnd( S.start()-1 ); } + +inline void KSection::moveToStart( int S ) { setEnd( S+width()-1 ); setStart( S ); } +inline void KSection::moveToEnd( int E ) { setStart( E-width()+1 ); setEnd( E ); } +} + +#endif diff --git a/khexedit/lib/ksectionlist.cpp b/khexedit/lib/ksectionlist.cpp new file mode 100644 index 0000000..eec54e4 --- /dev/null +++ b/khexedit/lib/ksectionlist.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + ksectionlist.cpp - description + ------------------- + begin : Mon Jun 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "ksectionlist.h" + +using namespace KHE; + +KSectionList::KSectionList() +{ +} + + +KSectionList::~KSectionList() +{ +} + + +void KSectionList::addSection( KSection NewSection ) +{ + if( !NewSection.isValid() ) + return; + + // we try to insert it by ascending indizes + // if sections are overlapping we combine them + iterator S = begin(); + for( ; S!=end(); ++S ) + { + // is new section before the next section? + if( NewSection.endsBefore(*S) ) + { + // put the new before it + insert( S, NewSection ); + return; + } + + // does the next section overlap? + if( (*S).overlaps(NewSection) ) + { + // Start of the combined sections is the smaller one + NewSection.extendStartTo( (*S).start() ); + // next we search all the overlapping sections and keep the highest end index + int End = (*S).end(); + iterator LS = S; + for( ++LS; LS!=end(); ++LS ) + { + if( !(*LS).overlaps(NewSection) ) + break; + End = (*LS).end(); + } + // the higher end is the end of the combined section + NewSection.extendEndTo( End ); + // remove all overlapping sections + S = erase( S, LS ); + // and instead insert the combined one + insert( S, NewSection ); + return; + } + } + + // all others are before the new? + if( S == end() ) + // add it at the end + append( NewSection ); +} diff --git a/khexedit/lib/ksectionlist.h b/khexedit/lib/ksectionlist.h new file mode 100644 index 0000000..7328e42 --- /dev/null +++ b/khexedit/lib/ksectionlist.h @@ -0,0 +1,44 @@ +/*************************************************************************** + ksectionlist.h - description + ------------------- + begin : Mon Jun 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KSECTIONLIST_H +#define KHE_KSECTIONLIST_H + +// qt specific +#include <qvaluelist.h> +// lib specific +#include "ksection.h" + +namespace KHE { + +typedef QValueList<KSection> KSectionBasicList; +/** +@author Friedrich W. H. Kossebau +*/ +class KSectionList : public KSectionBasicList +{ + public: + KSectionList(); + ~KSectionList(); + + public: + void addSection( KSection S ); +}; + +} + +#endif diff --git a/khexedit/lib/kselection.h b/khexedit/lib/kselection.h new file mode 100644 index 0000000..19b8a99 --- /dev/null +++ b/khexedit/lib/kselection.h @@ -0,0 +1,178 @@ +/*************************************************************************** + kbuffersection.h - description + ------------------- + begin : 22.06.2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de +****************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KSELECTION_H +#define KHE_KSELECTION_H + +#include "ksection.h" + +namespace KHE +{ + +/** This class describes a selected section of the buffer. + * As it is used as selection controlled by + * mouse and keyboard commands it offers two ways to set its range: + * - by giving the startposition (of the cursor) of an interactive selection + * and the subsequent end positions (until selection is finished) + * - direct setting (as provided by KSection) + * + * the interactive selection takes care that + * + *@author Friedrich W. H. Kossebau + */ +class KSelection : public KSection +{ + public: + /** creates a selection with a given start. + * @param Index index in front of which the selection begins + */ + KSelection( int Index ); + /** creates an invalid selection */ + KSelection(); + ~KSelection(); + + public: + KSelection &operator=( const KSelection &S ); + KSelection &operator=( const KSection &S ); + + public: // modification access + /** starts the selection. + * For this the anchor, start and end are set to the given index, + * so the initial selection is empty. + * @param Index index in front of which the selection begins + */ + void setStart( int Index ); + /** sets the end of the current selection + * If the end is before the start the selection will reach from the given index + * @param Index index in front of which the selection ends + */ + void setEnd( int Index ); + /** sets the selection to be invalid + */ + void cancel(); + /** sets the anchor to the start + * If the selection has not started the behaviour is undefined. + */ + void setForward(); + /** sets the anchor to the end + * If the selection has not started the behaviour is undefined. + */ + void setBackward(); + /** swaps anchor from start to end or vice versa + * If the selection has not started the behaviour is undefined. + */ + void reverse(); + + public: // value access + /** + * @return anchor value + */ + int anchor() const; + + public: // logic access + /** + * @return @c true if the anchor has been set, otherwise @c false. + */ + bool started() const; + /** + * @return @c true if the anchor has been set and the selection is empty, otherwise @c false. + */ + bool justStarted() const; + /** + * @return @c true if the anchor is at the begin of the selection + */ + bool isForward() const; + + protected: + /** cursor index where the selection starts */ + int Anchor; +}; + + +inline KSelection::KSelection() : Anchor( -1 ) {} +inline KSelection::KSelection( int Index ) : Anchor( Index ) {} +inline KSelection::~KSelection() {} + +inline KSelection &KSelection::operator=( const KSelection &S ) +{ + KSection::operator=(S); + Anchor = S.Anchor; + return *this; +} + +inline KSelection &KSelection::operator=( const KSection &S ) +{ + KSection::operator=(S); + Anchor = start(); + return *this; +} + + +inline void KSelection::setStart( int Index ) +{ + Anchor = Index; + unset(); +} + + +inline void KSelection::setEnd( int Index ) +{ + // nothing selected? + if( Index == Anchor ) + unset(); + // selecting forwards? + else if( Index > Anchor ) + { + KSection::setStart( Anchor ); + KSection::setEnd( Index-1 ); + } + // selecting backwards + else + { + KSection::setStart( Index ); + KSection::setEnd( Anchor-1 ); + } +} + +inline void KSelection::reverse() +{ + Anchor = isForward() ? end()+1 : start(); +} + +inline void KSelection::setForward() +{ + Anchor = start(); +} + +inline void KSelection::setBackward() +{ + Anchor = end()+1; +} + +inline int KSelection::anchor() const { return Anchor; } + +inline void KSelection::cancel() { Anchor = -1; unset(); } + +inline bool KSelection::started() const { return Anchor != -1; } + +inline bool KSelection::justStarted() const { return Anchor != -1 && start() == -1; } + +inline bool KSelection::isForward() const { return Anchor == start(); } + +} + +#endif diff --git a/khexedit/lib/kvaluecoltextexport.cpp b/khexedit/lib/kvaluecoltextexport.cpp new file mode 100644 index 0000000..009ad54 --- /dev/null +++ b/khexedit/lib/kvaluecoltextexport.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + kvaluecoltextexport.cpp - description + ------------------- + begin : Wed Sep 3 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kbufferlayout.h" +#include "kvaluecolumn.h" +#include "kvaluecoltextexport.h" +#include "helper.h" + + +using namespace KHE; + +KValueColTextExport::KValueColTextExport( const KValueColumn* HC, const char *D, KCoordRange CR ) + : KBufferColTextExport( HC, D, CR, HC->byteCodec()->encodingWidth() ), + ByteCodec( KByteCodec::createCodec(HC->coding()) ) +{ +} + + +KValueColTextExport::~KValueColTextExport() +{ + delete ByteCodec; +} + + + +void KValueColTextExport::print( QString &T ) const +{ + int p = 0; + int pEnd = NoOfBytesPerLine; + // correct boundaries + if( PrintLine == CoordRange.start().line() ) + p = CoordRange.start().pos(); + if( PrintLine == CoordRange.end().line() ) + pEnd = CoordRange.end().pos()+1; + + QString E; + E.setLength( ByteCodec->encodingWidth() ); + // draw individual chars + uint e = 0; + for( ; p<pEnd; ++p, ++PrintData ) + { + // get next position + uint t = Pos[p]; + // clear spacing + T.append( whiteSpace(t-e) ); + ByteCodec->encode( E, 0, *PrintData ); + T.append( E ); + e = t + ByteCodec->encodingWidth(); + } + + T.append( whiteSpace(NoOfCharsPerLine-e) ); + ++PrintLine; +} + diff --git a/khexedit/lib/kvaluecoltextexport.h b/khexedit/lib/kvaluecoltextexport.h new file mode 100644 index 0000000..be6bab4 --- /dev/null +++ b/khexedit/lib/kvaluecoltextexport.h @@ -0,0 +1,47 @@ +/*************************************************************************** + kvaluecoltextexport.h - description + ------------------- + begin : Sam Aug 30 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KVALUECOLTEXTEXPORT_H +#define KHE_KVALUECOLTEXTEXPORT_H + +#include "kbytecodec.h" +#include "kbuffercoltextexport.h" + + +namespace KHE +{ + +class KValueColumn; + + +class KValueColTextExport : public KBufferColTextExport +{ + public: + KValueColTextExport( const KValueColumn* BF, const char *D, KCoordRange CR ); + virtual ~KValueColTextExport(); + + protected: + virtual void print( QString &T ) const; + + + protected: + KByteCodec *ByteCodec; +}; + +} + +#endif diff --git a/khexedit/lib/kvaluecolumn.cpp b/khexedit/lib/kvaluecolumn.cpp new file mode 100644 index 0000000..82da795 --- /dev/null +++ b/khexedit/lib/kvaluecolumn.cpp @@ -0,0 +1,134 @@ +/*************************************************************************** + kvaluecolumn.cpp - description + ------------------- + begin : Mit Sep 3 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qpainter.h> +// lib specific +#include "kcolumnsview.h" +#include "kbuffercursor.h" +#include "kbufferlayout.h" +#include "kbufferranges.h" +#include "kvaluecolumn.h" +#include "helper.h" +#include "kcharcodec.h" + +using namespace KHE; + +static const KCoding DefaultCoding = HexadecimalCoding; +static const KCoding NotDefaultCoding = DecimalCoding; +static const int DefaultBinaryGapWidth = 1; + + +KValueColumn::KValueColumn( KColumnsView *CV, KDataBuffer *B, KBufferLayout *L, KBufferRanges *R ) + : KBufferColumn( CV, B, L, R ), + Coding( NotDefaultCoding ), + ByteCodec( 0 ), + BinaryGapWidth( DefaultBinaryGapWidth ) +{ + setCoding( DefaultCoding ); +} + + +KValueColumn::~KValueColumn() +{ +} + + + +bool KValueColumn::setCoding( KCoding C ) +{ + // no changes? + if( Coding == C ) + return false; + + delete ByteCodec; + + Coding = C; + ByteCodec = KByteCodec::createCodec( Coding ); + CodedByte.setLength( ByteCodec->encodingWidth() ); + + // recalculate depend sizes + recalcByteWidth(); + + if( PosX ) + recalcX(); + return true; +} + + +bool KValueColumn::setBinaryGapWidth( KPixelX BGW ) +{ + // no changes? + if( BinaryGapWidth == BGW ) + return false; + + BinaryGapWidth = BGW; + + // recalculate depend sizes + recalcByteWidth(); + + if( PosX ) + recalcX(); + return true; +} + + +void KValueColumn::recalcByteWidth() +{ + ByteWidth = ByteCodec->encodingWidth() * DigitWidth; + + if( Coding == BinaryCoding ) + { + BinaryHalfOffset = 4 * DigitWidth + BinaryGapWidth; + ByteWidth += BinaryGapWidth; + } + recalcVerticalGridX(); +} + + +// perhaps sometimes there will be a grammar +void KValueColumn::paintEditedByte( QPainter *P, char Byte, const QString &EditBuffer ) +{ + KHEChar B = Codec->decode( Byte ); + + const QColorGroup &CG = View->colorGroup(); + + P->fillRect( 0,0,ByteWidth,LineHeight, QBrush(colorForChar(B),Qt::SolidPattern) ); + + drawCode( P, EditBuffer, CG.base() ); +} + + +void KValueColumn::drawByte( QPainter *P, char Byte, KHEChar /*B*/, const QColor &Color ) const +{ + ByteCodec->encode( CodedByte, 0, Byte ); + drawCode( P, CodedByte, Color ); +} + + +void KValueColumn::drawCode( QPainter *P, const QString &Code, const QColor &Color ) const +{ + P->setPen( Color ); + if( Coding == BinaryCoding ) + { + // leave a gap in the middle + P->drawText( 0, DigitBaseLine, Code.left(4) ); + P->drawText( BinaryHalfOffset, DigitBaseLine, Code.right(4) ); + } + else + P->drawText( 0, DigitBaseLine, Code ); +} diff --git a/khexedit/lib/kvaluecolumn.h b/khexedit/lib/kvaluecolumn.h new file mode 100644 index 0000000..cc25929 --- /dev/null +++ b/khexedit/lib/kvaluecolumn.h @@ -0,0 +1,92 @@ +/*************************************************************************** + kvaluecolumn.h - description + ------------------- + begin : Mit Sep 3 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KVALUECOLUMN_H +#define KHE_KVALUECOLUMN_H + +// lib specific +#include "kbytecodec.h" +#include "kbuffercolumn.h" + + +namespace KHE +{ + +class KBufferRanges; + + +/** buffer column which displays the numerical values of the bytes + * + *@author Friedrich W. H. Kossebau + */ +class KValueColumn : public KBufferColumn +{ + public: + KValueColumn( KColumnsView *CV, KDataBuffer *B, KBufferLayout *L, KBufferRanges *R ); + virtual ~KValueColumn(); + + public: + void paintEditedByte( QPainter *P, char Byte, const QString &EditBuffer ); + + public: // modification access + /** + * returns true if there was a change + */ + bool setCoding( KCoding C ); + /** sets the spacing in the middle of a binary byte in the value column + * @param BinaryGapW spacing in the middle of a binary in pixels + * returns true if there was a change + */ + bool setBinaryGapWidth( KPixelX BGW ); + + + public: // value access + KPixelX binaryGapWidth() const; + KCoding coding() const; + const KByteCodec *byteCodec() const; + + + protected: // KBufferColumn API + virtual void drawByte( QPainter *P, char Byte, KHEChar B, const QColor &Color ) const; + virtual void recalcByteWidth(); + + protected: + void drawCode( QPainter *P, const QString &Code, const QColor &Color ) const; + + protected: // set data + /** */ + KCoding Coding; + /** */ + KByteCodec *ByteCodec; + /** */ + KPixelX BinaryGapWidth; + + protected: // buffered data + /** buffer to hold the formatted coding */ + mutable QString CodedByte; + /** calculated: Offset in pixels of the second half of the binary */ + KPixelX BinaryHalfOffset; +}; + + +inline KPixelX KValueColumn::binaryGapWidth() const { return BinaryGapWidth; } +inline KCoding KValueColumn::coding() const { return Coding; } +inline const KByteCodec *KValueColumn::byteCodec() const { return ByteCodec; } + +} + +#endif diff --git a/khexedit/lib/kwordbufferservice.cpp b/khexedit/lib/kwordbufferservice.cpp new file mode 100644 index 0000000..0489139 --- /dev/null +++ b/khexedit/lib/kwordbufferservice.cpp @@ -0,0 +1,209 @@ +/*************************************************************************** + kwordbufferservice.cpp - description + ------------------- + begin : Di Jan 18 2005 + copyright : (C) 2005 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// lib specific +#include "kdatabuffer.h" +#include "kcharcodec.h" +#include "kwordbufferservice.h" + +using namespace KHE; + + +bool KWordBufferService::isWordChar( unsigned int Index ) const +{ + KHEChar C = CharCodec->decode( Buffer->datum(Index) ); + return !C.isUndefined() && C.isLetterOrNumber(); +} + + +int KWordBufferService::indexOfPreviousWordStart( unsigned int Index ) const +{ + unsigned int Size = Buffer->size(); + // already at the start or can the result only be 0? + if( Index == 0 || Size < 3 ) + return 0; + + // search in two rounds: first for the next char, than for the next nonchar + // after that return the index of the one before + bool LookingForFirstWordChar = false; + for( ; Index>0; --Index ) + { + if( !isWordChar(Index-1) ) + { + if( !LookingForFirstWordChar ) + continue; + return( Index ); + } + else if( !LookingForFirstWordChar ) + LookingForFirstWordChar = true; + } + return 0; +} + + +int KWordBufferService::indexOfNextWordStart( unsigned int Index ) const +{ + unsigned int Size = Buffer->size(); + bool LookingForFirstWordChar = false; + for( ; Index<Size; ++Index ) + { + if( isWordChar(Index) ) + { + if( !LookingForFirstWordChar ) + continue; + return Index; + } + else if( !LookingForFirstWordChar ) + LookingForFirstWordChar = true; + } + // if no more word found, go to the end + return Size; +} + + +int KWordBufferService::indexOfBeforeNextWordStart( unsigned int Index ) const +{ + unsigned int Size = Buffer->size(); + bool LookingForFirstWordChar = false; + for( ; Index<Size; ++Index ) + { + if( isWordChar(Index) ) + { + if( !LookingForFirstWordChar ) + continue; + return Index-1; + } + else if( !LookingForFirstWordChar ) + LookingForFirstWordChar = true; + } + // if no more word found, go to the end + return Size-1; +} + + +int KWordBufferService::indexOfWordStart( unsigned int Index ) const +{ + for( ; Index > 0; --Index ) + { + if( !isWordChar(Index-1) ) + return( Index ); + } + return 0; +} + + +int KWordBufferService::indexOfWordEnd( unsigned int Index ) const +{ + unsigned int Size = Buffer->size(); + for( ++Index; Index<Size; ++Index ) + { + if( !isWordChar(Index) ) + return Index-1; + } + // word reaches the end + return Size-1; +} + + +int KWordBufferService::indexOfLeftWordSelect( unsigned int Index ) const +{ + // word at Index? + if( isWordChar(Index) ) + { + // search for word start to the left + for( ; Index>0; --Index ) + { + if( !isWordChar(Index-1) ) + return Index; + } + // reached start, so return it + return 0; + } + else + { + unsigned int Size = Buffer->size(); + // search for word start to the right + for( ++Index; Index<Size; ++Index ) + { + if( isWordChar(Index) ) + return Index; + } + // word reaches the end, so step behind + return Size; + } +} + + +int KWordBufferService::indexOfRightWordSelect( unsigned int Index ) const +{ + // no word at Index? + if( !isWordChar(Index) ) + { + // search for word end to the left + for( ; Index>0; --Index ) + { + if( isWordChar(Index-1) ) + return Index; + } + // reached start, so return it + return 0; + } + else + { + unsigned int Size = Buffer->size(); + for( ++Index; Index<Size; ++Index ) + { + // search for word end to the right + if( !isWordChar(Index) ) + return Index; + } + // word reaches the end, so step behind + return Size; + } +} + +/* +int KWordBufferService::indexOfBehindWordEnd( unsigned int Index ) const +{ + // no word at Index? + return !::isWordChar(datum(Index)) ? indexOfBehindLeftWordEnd(Index) : indexOfBehindRightWordEnd(Index+1) +} + + +int KWordBufferService::indexOfBehindRightWordEnd( unsigned int Index ) const +{ + for( ; Index<size(); ++Index ) +{ + if( !::isWordChar(datum(Index)) ) + return Index; +} + // word reaches the end, so step behind + return size(); +} + + +int KWordBufferService::indexOfBehindLeftWordEnd( unsigned int Index ) const +{ + for( --Index; Index>=0; --Index ) +{ + if( ::isWordChar(datum(Index)) ) + return Index+1; +} + // word reaches the end, so step behind + return 0; +} +*/ diff --git a/khexedit/lib/kwordbufferservice.h b/khexedit/lib/kwordbufferservice.h new file mode 100644 index 0000000..805f064 --- /dev/null +++ b/khexedit/lib/kwordbufferservice.h @@ -0,0 +1,137 @@ +/*************************************************************************** + kwordbufferservice.h - description + ------------------- + begin : Di Jan 18 2005 + copyright : (C) 2005 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KWORDBUFFERSERVICE_H +#define KHE_KWORDBUFFERSERVICE_H + +// lib specific +#include "ksection.h" + +namespace KHE +{ + +class KDataBuffer; +class KCharCodec; + +/** + * + *@author Friedrich W. H. Kossebau + */ + +class KWordBufferService +{ + public: + KWordBufferService( KDataBuffer *B, KCharCodec *C ); + ~KWordBufferService(); + + + public: + /** searches for the start of the word including the given index. + * if no other nonwordchar preceds this is 0; + * If the byte at the given Index is already a nonword char the given index is returned. + * @param Index index to start with + * @param CharType + * @return index of the first char of the current word or the given index if there is none + */ + int indexOfWordStart( unsigned int Index ) const; + int indexOfLeftWordSelect( unsigned int Index ) const; + /** searches for the end of the word including the given index. + * If the byte at the given Index is already a nonword char the given index is returned. + * if no other nonwordchar follows, that of the last byte; + * @param Index index to start with + * @param CharType + * @return index of the last char of the current word or the given index if there is none + */ + int indexOfWordEnd( unsigned int Index ) const; + /** searches for the first char after the end of the word including the given index. + * If the byte at the given Index is already a nonword char the given index is returned. + * if no other nonwordchar follows that of behind the last byte; + * @param Index index to start with + * @param CharType + * @return index of the first char after the current word or the given index if there is none + */ + int indexOfRightWordSelect( unsigned int Index ) const; + /** searches for the first char after the end of the word including the given index. + * If the byte at the given Index is already a nonword char the given index is returned. + * if no other nonwordchar follows that of behind the last byte; + * @param Index index to start with + * @param CharType + * @return index of the first char after the current word or the given index if there is none + */ +// int indexOfBehindLeftWordEnd( unsigned int Index ) const; + /** searches for the first char after the end of the word including the given index. + * If the byte at the given Index is already a nonword char the given index is returned. + * if no other nonwordchar follows that of behind the last byte; + * @param Index index to start with + * @param CharType + * @return index of the first char after the current word or the given index if there is none + */ +// int indexOfBehindRightWordEnd( unsigned int Index ) const; + /** searches the start of the next previous word that does not include the given index, + * if no further word is found 0 is returned. + * if the index is out of range the behaviour is undefined. + * @param Index + * @param CharType + * @return index of the next previous word start or 0 + */ + int indexOfPreviousWordStart( unsigned int Index ) const; + /** searches for the start of the next word not including the given index. + * if there isn't a next word the index behind end is returned + * @param Index + * @param CharType + * @return index of the start of the next word or behind end + */ + int indexOfNextWordStart( unsigned int Index ) const; + /** searches for the start of the next word not including the given index. + * if there isn't a next word the index of the end is returned + * @param Index index to start with + * @param CharType + * @return index of the last nonword char before the next word or the last index + */ + int indexOfBeforeNextWordStart( unsigned int Index ) const; + + /** if Index is out of range the behaviour is undefined + * @param Index + * @param CharType + * @return @c true if the byte at position i is a char of type CharType + */ + bool isWordChar( unsigned int Index ) const; + + /** returns the section with a word around index. + * if there is no word the section is empty + * @param Index + * @param CharType + * @return the section with a word around index. + */ + KSection wordSection( unsigned int Index ) const; + + protected: + KDataBuffer *Buffer; + KCharCodec *CharCodec; +}; + + +inline KWordBufferService::KWordBufferService( KDataBuffer *B, KCharCodec *C ) + : Buffer( B ), CharCodec( C ) {} +inline KWordBufferService::~KWordBufferService() {} + +inline KSection KWordBufferService::wordSection( unsigned int Index ) const +{ return isWordChar(Index) ? KSection( indexOfWordStart(Index), indexOfWordEnd(Index) ) : KSection(); } + +} + +#endif diff --git a/khexedit/lib/kwrappingrobuffer.cpp b/khexedit/lib/kwrappingrobuffer.cpp new file mode 100644 index 0000000..b913c1a --- /dev/null +++ b/khexedit/lib/kwrappingrobuffer.cpp @@ -0,0 +1,61 @@ +/*************************************************************************** + kwrappingrobuffer.cpp - description + ------------------- + begin : Mit Mai 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#include "kwrappingrobuffer.h" + +using namespace KHE; + +KWrappingROBuffer::KWrappingROBuffer( const char* D, int L ) +{ + Data = D; + Size = L; +} + +KWrappingROBuffer::KWrappingROBuffer() +{ + Data = 0L; + Size = 0; +} + + +KWrappingROBuffer::~KWrappingROBuffer() +{ +} + + +const char *KWrappingROBuffer::dataSet( KSection S ) const +{ + return &Data[S.start()]; +} + + +void KWrappingROBuffer::set( const char* D, int L ) +{ + Data = D; + Size = L; +} + + +int KWrappingROBuffer::find( const char*/*KeyData*/, int /*Length*/, KSection /*Section*/ ) const +{ + return 0; +} + +int KWrappingROBuffer::rfind( const char*, int /*Length*/, int /*Pos*/ ) const +{ + return 0; +} diff --git a/khexedit/lib/kwrappingrobuffer.h b/khexedit/lib/kwrappingrobuffer.h new file mode 100644 index 0000000..51ee7b8 --- /dev/null +++ b/khexedit/lib/kwrappingrobuffer.h @@ -0,0 +1,85 @@ +/*************************************************************************** + kwrappingrobuffer.h - description + ------------------- + begin : Mit Mai 14 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHE_KWRAPPINGROBUFFER_H +#define KHE_KWRAPPINGROBUFFER_H + +#include "kreadonlybuffer.h" + +namespace KHE +{ + +/** + *@author Friedrich W. H. Kossebau + */ + +class KWrappingROBuffer : public KReadOnlyBuffer +{ + public: + static const int NothingFound = -1; + + public: + KWrappingROBuffer(); + KWrappingROBuffer( const char* D, int L ); + virtual ~KWrappingROBuffer(); + + + public: // KDataBuffer API + virtual bool prepareRange( KSection Range ) const; + virtual const char *dataSet( KSection S ) const; + virtual char datum( unsigned int Offset ) const; + virtual int size() const; + virtual bool isModified() const; + + virtual int insert( int Pos, const char*, int Length ); + virtual int remove( KSection S ); + virtual unsigned int replace( KSection S, const char*, unsigned int Length ); + virtual int fill( const char FillChar, int, int ); + virtual void setDatum( unsigned int Offset, const char Char ); + + virtual void setModified( bool M ); + + virtual int find( const char*KeyData, int Length, KSection Section ) const; + virtual int rfind( const char*, int Length, int Pos = -1 ) const; + + + public: // + void set( const char* D, int L ); + + protected: + const char* Data; + int Size; + bool Modified; +}; + +inline int KWrappingROBuffer::size() const { return Size; } + +inline bool KWrappingROBuffer::isModified() const { return Modified; } + +inline bool KWrappingROBuffer::prepareRange( KSection ) const { return true; } +inline char KWrappingROBuffer::datum( unsigned int Offset ) const { return Data[Offset]; } + +inline int KWrappingROBuffer::insert( int, const char*, int ) { return 0; } +inline int KWrappingROBuffer::remove( KSection ) { return 0; } +inline unsigned int KWrappingROBuffer::replace( KSection, const char*, unsigned int ) { return 0; } +inline int KWrappingROBuffer::fill( const char , int, int ) { return 0; } +inline void KWrappingROBuffer::setDatum( unsigned int, const char ) {} + +inline void KWrappingROBuffer::setModified( bool M ) { Modified = M; } +} + +#endif diff --git a/khexedit/listview.cc b/khexedit/listview.cc new file mode 100644 index 0000000..50de78a --- /dev/null +++ b/khexedit/listview.cc @@ -0,0 +1,54 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <qheader.h> + + +#include "listview.h" + + +CListView::CListView( QWidget *parent, const char *name, int visibleItem ) + :KListView( parent, name ), mVisibleItem(QMAX( 1, visibleItem )) +{ + setVisibleItem(visibleItem); +} + +void CListView::setVisibleItem( int visibleItem, bool updateSize ) +{ + mVisibleItem = QMAX( 1, visibleItem ); + if( updateSize == true ) + { + QSize s = sizeHint(); + setMinimumSize( s.width() + verticalScrollBar()->sizeHint().width() + + lineWidth() * 2, s.height() ); + } +} + +QSize CListView::sizeHint( void ) const +{ + QSize s = QListView::sizeHint(); + + int h = fontMetrics().height() + 2*itemMargin(); + if( h % 2 > 0 ) { h++; } + + s.setHeight( h*mVisibleItem + lineWidth()*2 + header()->sizeHint().height()); + return( s ); +} +#include "listview.moc" diff --git a/khexedit/listview.h b/khexedit/listview.h new file mode 100644 index 0000000..253fce9 --- /dev/null +++ b/khexedit/listview.h @@ -0,0 +1,49 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _LISTVIEW_H_ +#define _LISTVIEW_H_ + +#include <klistview.h> + +class CListView : public KListView +{ + Q_OBJECT + + public: + CListView( QWidget *parent=0, const char *name=0, int visibleItem=10 ); + + void setVisibleItem( int visibleItem, bool updateSize=true ); + virtual QSize sizeHint( void ) const; + + private: + int mVisibleItem; +}; + + + + +#endif + + + + + + diff --git a/khexedit/main.cc b/khexedit/main.cc new file mode 100644 index 0000000..525868f --- /dev/null +++ b/khexedit/main.cc @@ -0,0 +1,130 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + + +#include <stdlib.h> + +#include <kapplication.h> +#include <klocale.h> +#include <kcmdlineargs.h> +#include <kaboutdata.h> + +#include "toplevel.h" +#include "version.h" // Contains khexedit name string and version string + + +static const char description[] = + I18N_NOOP("KDE hex editor"); + +static const char version[] = APP_VERSION_STRING; + +static KCmdLineOptions option[] = +{ + { "offset <offset>", I18N_NOOP("Jump to 'offset'"), 0 }, + { "+[file(s)]", I18N_NOOP("File(s) to open"), 0 }, + KCmdLineLastOption +}; + +static uint parseDecimalOrHexadecimal( char *buf ); + +int main( int argc, char **argv ) +{ + KAboutData aboutData("khexedit", I18N_NOOP("KHexEdit"), + version, description, KAboutData::License_GPL_V2, + "(c) 1999-2000, Espen Sand"); + aboutData.addAuthor("Espen Sand",0, "espensa@online.no", + "http://home.online.no/~espensa/khexedit/" ); + aboutData.addCredit("",I18N_NOOP("\n" + "This program uses modified code and techniques from other KDE programs,\n" + "specifically kwrite, kiconedit and ksysv. Credit goes to authors\n" + "and maintainers.\n" + "\n" + "Leon Lessing, leon@lrlabs.com, has made parts of the bit swapping\n" + "functionality.\n" + "\n" + "Craig Graham, c_graham@hinge.mistral.co.uk, has made parts of\n" + "the bit stream functionality of the conversion field.\n" + "\n" + "Dima Rogozin, dima@mercury.co.il, has extended the string dialog\n" + "list capabilities.\n" + "\n" + "Edward Livingston-Blade, sbcs@bigfoot.com, has given me very good\n" + "reports which removed some nasty bugs.\n")); + KCmdLineArgs::init( argc, argv, &aboutData ); + KCmdLineArgs::addCmdLineOptions( option ); + + KApplication app; + + if( app.isRestored() != 0 ) + { + RESTORE( KHexEdit ); + } + else + { + KHexEdit *hexEdit = new KHexEdit; + if( hexEdit == 0 ) + { + std::cerr << "Unable to start - Memory exhausted" << std::endl; + return( 1 ); + } + + hexEdit->show(); + + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + if (args->isSet("offset")) + { + QCString offsetStr = args->getOption("offset"); + uint _offset = parseDecimalOrHexadecimal(offsetStr.data() ); + hexEdit->setStartupOffset( _offset ); + } + + for(int i = 0; i < args->count(); i++) + hexEdit->addStartupFile( args->url(i).url() ); + + args->clear(); + } + + int result = app.exec(); + return( result ); +} + + + +static uint parseDecimalOrHexadecimal( char *buf ) +{ + if( buf == 0 ) { return( 0 ); } + + long int value; + char *end = 0; + + value = strtol( buf, &end, 10 ); + if( *end != 0 ) + { + value = strtol( buf, &end, 16 ); + if( *end != 0 ) + { + value = 0; + } + } + if( value < 0 ) { value = 0; } + return( value ); +} + diff --git a/khexedit/optiondialog.cc b/khexedit/optiondialog.cc new file mode 100644 index 0000000..2038b2d --- /dev/null +++ b/khexedit/optiondialog.cc @@ -0,0 +1,1224 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <limits.h> + +#include <qvbox.h> +#include <qvbuttongroup.h> +#include <qpainter.h> + +#include <qcheckbox.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qradiobutton.h> +#include <qspinbox.h> +#include <qwhatsthis.h> + +#include <kcolordialog.h> +#include <kcolordrag.h> +#include <kfontdialog.h> // For KFontChooser +#include <kiconloader.h> +#include <klocale.h> +#include <kglobalsettings.h> + +#include "optiondialog.h" +#include <qpushbutton.h> +#include <qcombobox.h> + +#if 0 +#include <qobjectlist.h> +static void enableWidget( QWidget *w, bool state ) +{ + if( w->children() ) + { + QObjectList *l = (QObjectList*)w->children(); // silence please + for( uint i=0; i < l->count(); i++ ) + { + QObject *o = l->at(i); + if( o->isWidgetType() ) + { + enableWidget( (QWidget*)o, state ); + } + } + } + w->setEnabled( state ); +} +#endif + + + +COptionDialog::COptionDialog( QWidget *parent, char *name, bool modal ) + :KDialogBase( IconList, i18n("Configure"), Help|Default|Apply|Ok|Cancel, + Ok, parent, name, modal, true ) +{ + setHelp( "khexedit/khexedit.html", QString::null ); + + setupLayoutPage(); + setupCursorPage(); + setupFontPage(); + setupColorPage(); + setupFilePage(); + setupMiscPage(); + enableButton( Apply, false ); + configChanged = false; +} + + +COptionDialog::~COptionDialog( void ) +{ +} + +void COptionDialog::slotChanged() +{ + enableButton( Apply, true ); + configChanged = true; +} + +void COptionDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + showPage(0); + mLayout.lineSizeSpin->setFocus(); +} + + +void COptionDialog::setupLayoutPage( void ) +{ + QString text; + QFrame *page = addPage( i18n("Layout"), i18n("Data Layout in Editor"), + BarIcon("khexedit", KIcon::SizeMedium ) ); + + QGridLayout *gbox = new QGridLayout( page, 15, 2, 0, spacingHint() ); + gbox->setColStretch( 1, 10 ); + + mLayout.formatCombo = new QComboBox( false, page ); + QStringList modeList; + modeList.append( i18n("Hexadecimal Mode") ); + modeList.append( i18n("Decimal Mode") ); + modeList.append( i18n("Octal Mode") ); + modeList.append( i18n("Binary Mode") ); + modeList.append( i18n("Text Only Mode") ); + mLayout.formatCombo->insertStringList( modeList ); + connect( mLayout.formatCombo, SIGNAL(activated(int)), + SLOT(slotModeSelectorChanged(int)) ); + connect( mLayout.formatCombo, SIGNAL(activated(int)), + SLOT(slotChanged()) ); + gbox->addWidget( mLayout.formatCombo, 0, 1 ); + + // + // I am setting the min. width for one widget in the second column + // This widtk will be used by every widget in this column. + // + mLayout.lineSizeSpin = new QSpinBox( page ); + mLayout.lineSizeSpin->setMinimumWidth( fontMetrics().width("M") * 10 ); + mLayout.lineSizeSpin->setRange( 1, 10000 ); + connect( mLayout.lineSizeSpin, SIGNAL(valueChanged(int)), + SLOT(slotLineSizeChanged(int) ) ); + connect( mLayout.lineSizeSpin, SIGNAL(valueChanged(int)), + SLOT(slotChanged()) ); + gbox->addWidget( mLayout.lineSizeSpin, 1, 1 ); + + mLayout.columnSizeSpin = new QSpinBox( page ); + mLayout.columnSizeSpin->setRange( 1, 10000 ); + connect( mLayout.columnSizeSpin, SIGNAL(valueChanged(int)), + SLOT(slotColumnSizeChanged(int) ) ); + connect( mLayout.columnSizeSpin, SIGNAL(valueChanged(int)), + SLOT(slotChanged() ) ); + gbox->addWidget( mLayout.columnSizeSpin, 2, 1 ); + + text = i18n("Default l&ine size [bytes]:"); + QLabel *label = new QLabel( mLayout.lineSizeSpin, text, page ); + gbox->addWidget( label, 1, 0 ); + + text = i18n("Colu&mn size [bytes]:"); + label = new QLabel( mLayout.columnSizeSpin, text, page ); + gbox->addWidget( label, 2, 0 ); + + QFrame *hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + gbox->addMultiCellWidget( hline, 3, 3, 0, 1 ); + + text = i18n("Line size is &fixed (use scrollbar when required)"); + mLayout.lockLineCheck = new QCheckBox( text, page ); + gbox->addMultiCellWidget( mLayout.lockLineCheck, 4, 4, 0, 1, AlignLeft ); + connect( mLayout.lockLineCheck, SIGNAL(toggled(bool)), + SLOT(slotChanged()) ); + + text = i18n("Loc&k column at end of line (when column size>1)"); + mLayout.lockColumnCheck = new QCheckBox( text, page ); + gbox->addMultiCellWidget( mLayout.lockColumnCheck, 5, 5, 0, 1 ); + connect( mLayout.lockColumnCheck, SIGNAL(toggled(bool)), + SLOT(slotChanged()) ); + + hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + gbox->addMultiCellWidget( hline, 6, 6, 0, 1 ); + + QStringList gridList; + gridList.append( i18n("None") ); + gridList.append( i18n("Vertical Only") ); + gridList.append( i18n("Horizontal Only") ); + gridList.append( i18n("Both Directions") ); + + mLayout.gridCombo = new QComboBox( false, page ); + mLayout.gridCombo->insertStringList( gridList ); + connect( mLayout.gridCombo, SIGNAL(activated(int)), + SLOT(slotChanged()) ); + + text = i18n("&Gridlines between text:"); + label = new QLabel( mLayout.gridCombo, text, page ); + + gbox->addWidget( label, 7, 0 ); + gbox->addWidget( mLayout.gridCombo, 7, 1 ); + + mLayout.leftSepWidthSpin = new QSpinBox( page ); + mLayout.leftSepWidthSpin->setRange( 0, 20 ); + gbox->addWidget( mLayout.leftSepWidthSpin, 8, 1 ); + connect( mLayout.leftSepWidthSpin, SIGNAL(valueChanged(int)), + SLOT(slotChanged()) ); + + mLayout.rightSepWidthSpin = new QSpinBox( page ); + mLayout.rightSepWidthSpin->setRange( 0, 20 ); + gbox->addWidget( mLayout.rightSepWidthSpin, 9, 1 ); + connect( mLayout.rightSepWidthSpin, SIGNAL(valueChanged(int)), + SLOT(slotChanged()) ); + + text = i18n("&Left separator width [pixels]:"); + mLayout.leftSepLabel = new QLabel( mLayout.leftSepWidthSpin, text, page ); + gbox->addWidget( mLayout.leftSepLabel, 8, 0 ); + + text = i18n("&Right separator width [pixels]:"); + mLayout.rightSepLabel = new QLabel( mLayout.rightSepWidthSpin, text, page ); + gbox->addWidget( mLayout.rightSepLabel, 9, 0 ); + + mLayout.separatorSpin = new QSpinBox( page ); + mLayout.separatorSpin->setRange( 0, 20 ); + gbox->addWidget( mLayout.separatorSpin, 10, 1 ); + connect( mLayout.separatorSpin, SIGNAL(valueChanged(int)), + SLOT(slotChanged()) ); + + mLayout.edgeSpin = new QSpinBox( page ); + mLayout.edgeSpin->setRange( 0, 20 ); + gbox->addWidget( mLayout.edgeSpin, 11, 1 ); + connect( mLayout.edgeSpin, SIGNAL(valueChanged(int)), + SLOT(slotChanged()) ); + + text = i18n("&Separator margin width [pixels]:"); + label = new QLabel( mLayout.separatorSpin, text, page ); + gbox->addWidget( label, 10, 0 ); + + text = i18n("&Edge margin width [pixels]:"); + label = new QLabel( mLayout.edgeSpin, text, page ); + gbox->addWidget( label, 11, 0 ); + + text = i18n("Column separation is e&qual to one character"); + mLayout.columnCheck = new QCheckBox( text, page ); + gbox->addMultiCellWidget( mLayout.columnCheck, 12, 12, 0, 1, AlignLeft ); + connect( mLayout.columnCheck, SIGNAL(toggled(bool)), + SLOT( slotColumnSepCheck(bool))); + connect( mLayout.columnCheck, SIGNAL(toggled(bool)), + SLOT( slotChanged())); + + mLayout.columnSepSpin = new QSpinBox( page ); + mLayout.columnSepSpin->setRange( 1, 100 ); + connect( mLayout.columnSepSpin, SIGNAL(valueChanged(int)), + SLOT(slotChanged()) ); + + text = i18n("Column separa&tion [pixels]:"); + mLayout.columnSepLabel = new QLabel( mLayout.columnSepSpin, text, page ); + + gbox->addWidget( mLayout.columnSepLabel, 13, 0 ); + gbox->addWidget( mLayout.columnSepSpin, 13, 1 ); + + gbox->setRowStretch( 14, 10 ); +} + + +void COptionDialog::setupCursorPage( void ) +{ + QString text; + QFrame *page = addPage( i18n("Cursor"), + i18n("Cursor Behavior (only valid for editor)"), + BarIcon("mouse", KIcon::SizeMedium ) ); + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + QVButtonGroup *group = new QVButtonGroup( i18n("Blinking"), page ); + group->layout()->setMargin( spacingHint() ); + topLayout->addWidget( group ); + + text = i18n("Do not b&link"); + mCursor.blinkCheck = new QCheckBox( i18n("Do not b&link"), group ); + connect( mCursor.blinkCheck, SIGNAL(toggled(bool)), + SLOT( slotBlinkIntervalCheck(bool))); + connect( mCursor.blinkCheck, SIGNAL(toggled(bool)), + SLOT( slotChanged())); + + QHBox *hbox = new QHBox( group ); + mCursor.blinkLabel = new QLabel( i18n("&Blink interval [ms]:" ), hbox ); + mCursor.blinkSpin = new QSpinBox( hbox ); + mCursor.blinkSpin->setMinimumWidth( fontMetrics().width("M") * 10 ); + mCursor.blinkSpin->setRange( 100, 1000 ); + mCursor.blinkSpin->setSteps( 100, 100 ); + mCursor.blinkSpin->setValue( 500 ); + mCursor.blinkLabel->setBuddy(mCursor.blinkSpin); + connect( mCursor.blinkSpin, SIGNAL(valueChanged(int)), + SLOT( slotChanged())); + + group = new QVButtonGroup( i18n("Shape"), page ); + group->layout()->setMargin( spacingHint() ); + topLayout->addWidget( group ); + + text = i18n("Always &use block (rectangular) cursor"); + mCursor.blockCheck = new QCheckBox( text, group ); + connect( mCursor.blockCheck, SIGNAL(toggled(bool)), + SLOT( slotBlockCursorCheck(bool))); + connect( mCursor.blockCheck, SIGNAL(toggled(bool)), + SLOT( slotChanged())); + text = i18n("Use &thick cursor in insert mode"); + mCursor.thickCheck = new QCheckBox( text, group ); + connect( mCursor.thickCheck, SIGNAL(toggled(bool)), + SLOT( slotChanged())); + + text = i18n("Cursor Behavior When Editor Loses Focus"); + group = new QVButtonGroup( text, page ); + group->layout()->setMargin( spacingHint() ); + topLayout->addWidget( group ); + + text = i18n("&Stop blinking (if blinking is enabled)"); + mCursor.stopRadio = new QRadioButton( text, group, "radio1" ); + mCursor.hideRadio = new QRadioButton( i18n("H&ide"), group, "radio2" ); + text = i18n("Do ¬hing"); + mCursor.nothingRadio = new QRadioButton( text, group, "radio3" ); + connect( mCursor.stopRadio, SIGNAL(toggled(bool)), + SLOT( slotChanged())); + connect( mCursor.hideRadio, SIGNAL(toggled(bool)), + SLOT( slotChanged())); + connect( mCursor.nothingRadio, SIGNAL(toggled(bool)), + SLOT( slotChanged())); + + topLayout->addStretch(10); +} + + +void COptionDialog::setupColorPage( void ) +{ + QString text; + QFrame *page = addPage( i18n("Colors"), + i18n("Editor Colors (system selection color is always used)"), + BarIcon("colorize", KIcon::SizeMedium ) ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + text = i18n("&Use system colors (as chosen in Control Center)"); + mColor.checkSystem = new QCheckBox( text, page ); + connect( mColor.checkSystem, SIGNAL(toggled(bool)), + SLOT( slotColorSystem(bool))); + connect( mColor.checkSystem, SIGNAL(toggled(bool)), + SLOT( slotChanged())); + topLayout->addWidget( mColor.checkSystem ); + + QFrame *hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + topLayout->addWidget( hline ); + + QStringList modeList; + modeList.append( i18n("First, Third ... Line Background") ); + modeList.append( i18n("Second, Fourth ... Line Background") ); + modeList.append( i18n("Offset Background") ); + modeList.append( i18n("Inactive Background") ); + modeList.append( i18n("Even Column Text") ); + modeList.append( i18n("Odd Column Text") ); + modeList.append( i18n("Non Printable Text") ); + modeList.append( i18n("Offset Text") ); + modeList.append( i18n("Secondary Text") ); + modeList.append( i18n("Marked Background") ); + modeList.append( i18n("Marked Text") ); + modeList.append( i18n("Cursor Background") ); + modeList.append( i18n("Cursor Text (block shape)") ); + modeList.append( i18n("Bookmark Background") ); + modeList.append( i18n("Bookmark Text") ); + modeList.append( i18n("Separator") ); + modeList.append( i18n("Grid Lines") ); + + mColor.colorList = new CColorListBox( page ); + topLayout->addWidget( mColor.colorList, 10 ); + for( uint i=0; i<17; i++ ) + { + CColorListItem *listItem = new CColorListItem( modeList[i] ); + mColor.colorList->insertItem( listItem ); + } + mColor.colorList->setCurrentItem(0); + connect( mColor.colorList, SIGNAL( dataChanged() ), this, SLOT( slotChanged() ) ); +} + + +void COptionDialog::setupFontPage( void ) +{ + QString text; + QFrame *page = addPage( i18n("Font"), + i18n("Font Selection (editor can only use a fixed font)"), + BarIcon("fonts", KIcon::SizeMedium ) ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + text = i18n("&Use system font (as chosen in Control Center)"); + mFont.checkSystem = new QCheckBox( text, page ); + connect( mFont.checkSystem, SIGNAL(toggled(bool)), + this, SLOT( slotFontSystem(bool))); + connect( mFont.checkSystem, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + topLayout->addWidget( mFont.checkSystem ); + + QFrame *hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + topLayout->addWidget( hline ); + + mFont.chooser = new KFontChooser( page, "font", true, QStringList(), false, 4 ); + topLayout->addWidget( mFont.chooser ); + QFont fixFont( KGlobalSettings::fixedFont() ); + fixFont.setBold(true); + mFont.chooser->setFont( fixFont, true ); + mFont.chooser->setSampleText( i18n("KHexEdit editor font") ); + connect( mFont.chooser, SIGNAL(fontSelected(const QFont &)), + this, SLOT( slotChanged())); + + hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + topLayout->addWidget( hline ); + + QHBoxLayout *hbox = new QHBoxLayout(); + topLayout->addLayout( hbox ); + + mFont.nonPrintInput = new QLineEdit( page ); + mFont.nonPrintInput->setMaxLength( 1 ); + connect( mFont.nonPrintInput, SIGNAL(textChanged(const QString &)), + this, SLOT( slotChanged())); + + text = i18n("&Map non printable characters to:"); + QLabel *nonPrintLabel = new QLabel( mFont.nonPrintInput, text, page ); + + hbox->addWidget( nonPrintLabel, 0, AlignLeft ); + hbox->addSpacing( spacingHint() ); + hbox->addWidget( mFont.nonPrintInput, 10 ); + + topLayout->addStretch(10); +} + + +void COptionDialog::setupFilePage( void ) +{ + QString text; + QFrame *page = addPage( i18n("Files"), i18n("File Management"), + BarIcon("kmultiple", KIcon::SizeMedium ) ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + QGridLayout *gbox = new QGridLayout( 2, 2, spacingHint() ); + topLayout->addLayout( gbox ); + + mFile.openCombo = new QComboBox( false, page ); + QStringList modeList; + modeList.append( i18n("None") ); + modeList.append( i18n("Most Recent Document") ); + modeList.append( i18n("All Recent Documents") ); + mFile.openCombo->insertStringList( modeList ); + mFile.openCombo->setMinimumWidth( mFile.openCombo->sizeHint().width() ); + connect( mFile.openCombo, SIGNAL(activated(int)), + this, SLOT( slotChanged())); + + text = i18n("Open doc&uments on startup:"); + QLabel *label = new QLabel( mFile.openCombo, text, page ); + + gbox->addWidget( label, 0, 0 ); + gbox->addWidget( mFile.openCombo, 0, 1 ); + + text = i18n("&Jump to previous cursor position on startup"); + mFile.gotoOffsetCheck = new QCheckBox( text, page ); + // ### TODO: this is currently not available. + mFile.gotoOffsetCheck->setChecked( false ); + mFile.gotoOffsetCheck->setEnabled( false ); + // ### END + topLayout->addWidget( mFile.gotoOffsetCheck, 0, AlignLeft ); + connect( mFile.gotoOffsetCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + QFrame *hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + topLayout->addWidget( hline ); + + text = i18n("Open document with &write protection enabled"); + mFile.writeProtectCheck = new QCheckBox( text, page ); + topLayout->addWidget( mFile.writeProtectCheck, 0, AlignLeft ); + connect( mFile.writeProtectCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + text = i18n("&Keep cursor position after reloading document"); + mFile.reloadOffsetCheck = new QCheckBox( text, page ); + topLayout->addWidget( mFile.reloadOffsetCheck, 0, AlignLeft ); + connect( mFile.reloadOffsetCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + text = i18n("&Make a backup when saving document"); + mFile.backupCheck = new QCheckBox( text, page ); + topLayout->addWidget( mFile.backupCheck, 0, AlignLeft ); + connect( mFile.backupCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + topLayout->addWidget( hline ); + + text = i18n("Don't &save \"Recent\" document list on exit"); + mFile.discardRecentCheck = new QCheckBox( text, page ); + topLayout->addWidget( mFile.discardRecentCheck, 0, AlignLeft ); + QWhatsThis::add( mFile.discardRecentCheck, + i18n( "Clicking this check box makes KHexEdit forget his recent document list " + "when the program is closed.\n" + "Note: it will not erase any document of the recent document list " + "created by KDE." ) ); + connect( mFile.discardRecentCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + text = i18n("Cl&ear \"Recent\" Document List"); + QPushButton *discardRecentButton = new QPushButton( page ); + discardRecentButton->setText( text ); + QWhatsThis::add( discardRecentButton, + i18n( "Clicking this button makes KHexEdit forget his recent document list.\n" + "Note: it will not erase any document of the recent document list " + "created by KDE." ) ); + topLayout->addWidget( discardRecentButton, 0, AlignCenter ); + connect( discardRecentButton, SIGNAL(clicked()), + SIGNAL(removeRecentFiles()) ); + + topLayout->addStretch(10); +} + + + +void COptionDialog::setupMiscPage( void ) +{ + QString text; + QLabel *label; + + QFrame *page = addPage( i18n("Miscellaneous"), i18n("Various Properties"), + BarIcon("gear", KIcon::SizeMedium ) ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + + text = i18n("Auto&matic copy to clipboard when selection is ready"); + mMisc.autoCheck = new QCheckBox( text, page ); + topLayout->addWidget( mMisc.autoCheck, 0, AlignLeft ); + connect( mMisc.autoCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + text = i18n("&Editor starts in \"insert\" mode" ); + mMisc.insertCheck = new QCheckBox( text, page ); + topLayout->addWidget( mMisc.insertCheck, 0, AlignLeft ); + connect( mMisc.insertCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + text = i18n("Confirm &wrapping (to beginning or end) during search"); + mMisc.confirmWrapCheck = new QCheckBox( text, page ); + topLayout->addWidget( mMisc.confirmWrapCheck, 0, AlignLeft ); + connect( mMisc.confirmWrapCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + text = i18n("Cursor jumps to &nearest byte when moved"); + mMisc.cursorJumpCheck = new QCheckBox( text, page ); + topLayout->addWidget( mMisc.cursorJumpCheck, 0, AlignLeft ); + connect( mMisc.cursorJumpCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + QVButtonGroup *group = new QVButtonGroup( i18n("Sounds"), page ); + group->layout()->setMargin( spacingHint() ); + topLayout->addWidget( group ); + text = i18n("Make sound on data &input (eg. typing) failure"); + mMisc.inputCheck = new QCheckBox( text, group ); + connect( mMisc.inputCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + text = i18n("Make sound on &fatal failure"); + mMisc.fatalCheck = new QCheckBox( text, group ); + connect( mMisc.fatalCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + group = new QVButtonGroup( i18n("Bookmark Visibility"), page ); + group->layout()->setMargin( spacingHint() ); + topLayout->addWidget( group ); + text = i18n("Use visible bookmarks in the offset column"); + mMisc.bookmarkColumnCheck = new QCheckBox( text, group ); + connect( mMisc.bookmarkColumnCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + text = i18n("Use visible bookmarks in the editor fields"); + mMisc.bookmarkEditorCheck = new QCheckBox( text, group ); + connect( mMisc.bookmarkEditorCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + + text = i18n("Confirm when number of printed pages will e&xceed limit"); + mMisc.thresholdCheck = new QCheckBox( text, page ); + connect( mMisc.thresholdCheck, SIGNAL(clicked()), + SLOT( slotThresholdConfirm())); + connect( mMisc.thresholdCheck, SIGNAL(toggled(bool)), + this, SLOT( slotChanged())); + topLayout->addWidget( mMisc.thresholdCheck, 0, AlignLeft ); + + QGridLayout *glay = new QGridLayout( 3, 3 ); + glay->setColStretch(2,10); + topLayout->addLayout( glay ); + + mMisc.thresholdSpin = new QSpinBox( page ); + mMisc.thresholdSpin->setMinimumWidth( fontMetrics().width("M") * 10 ); + mMisc.thresholdSpin->setRange( 5, INT_MAX ); + mMisc.thresholdSpin->setSteps( 5, 5 ); + mMisc.thresholdSpin->setValue( 5 ); + connect( mMisc.thresholdSpin, SIGNAL(valueChanged(int)), + this, SLOT( slotChanged())); + + text = i18n("&Threshold [pages]:" ); + mMisc.thresholdLabel = new QLabel( mMisc.thresholdSpin, text, page ); + + glay->addWidget( mMisc.thresholdLabel, 0, 0 ); + glay->addWidget( mMisc.thresholdSpin, 0, 1 ); + + QFrame *hline = new QFrame( page ); + hline->setFrameStyle( QFrame::Sunken | QFrame::HLine ); + glay->addMultiCellWidget( hline, 1, 1, 0, 2 ); + + mMisc.undoSpin = new QSpinBox( page ); + mMisc.undoSpin->setRange( 10, 10000 ); + mMisc.undoSpin->setSteps( 5, 5 ); + mMisc.undoSpin->setValue( 50 ); + connect( mMisc.undoSpin, SIGNAL(valueChanged(int)), + this, SLOT( slotChanged())); + + label = new QLabel( mMisc.undoSpin, i18n("&Undo limit:"), page ); + glay->addWidget( label, 2, 0 ); + glay->addWidget( mMisc.undoSpin, 2, 1 ); + + topLayout->addStretch(10); +} + + + +void COptionDialog::slotModeSelectorChanged( int index ) +{ + int lineSize = mDisplayState.line.getLineSize( index ); + int colSize = mDisplayState.line.getColumnSize( index ); + mLayout.lineSizeSpin->setValue( lineSize ); + mLayout.columnSizeSpin->setValue( colSize ); +} + +void COptionDialog::slotLineSizeChanged( int value ) +{ + int index = mLayout.formatCombo->currentItem(); + mDisplayState.line.setLineSize( index, value ); + if( index == SDisplayLine::textOnly ) + { + mLayout.columnSizeSpin->setValue( value ); + } +} + +void COptionDialog::slotColumnSizeChanged( int value ) +{ + int index = mLayout.formatCombo->currentItem(); + mDisplayState.line.setColumnSize( index, value ); + if( index == SDisplayLine::textOnly ) + { + mLayout.lineSizeSpin->setValue( value ); + } +} + +void COptionDialog::slotColumnSepCheck( bool state ) +{ + state = state == true ? false: true; + mLayout.columnSepLabel->setEnabled( state ); + mLayout.columnSepSpin->setEnabled( state ); +} + + +void COptionDialog::slotBlinkIntervalCheck( bool state ) +{ + state = state == true ? false : true; + mCursor.blinkSpin->setEnabled( state ); + mCursor.blinkLabel->setEnabled( state ); +} + +void COptionDialog::slotBlockCursorCheck( bool state ) +{ + state = state == true ? false : true; + mCursor.thickCheck->setEnabled( state ); +} + +void COptionDialog::slotFontSystem( bool state ) +{ + mFont.chooser->setEnabled( state == true ? false : true ); +} + +void COptionDialog::slotColorSystem( bool state ) +{ + state = state == true ? false : true; + mColor.colorList->setEnabled( state ); +} + + + +void COptionDialog::slotThresholdConfirm( void ) +{ + bool state = mMisc.thresholdCheck->isChecked(); + mMisc.thresholdLabel->setEnabled( state ); + mMisc.thresholdSpin->setEnabled( state ); +} + + +void COptionDialog::slotDefault( void ) +{ + // + // We use the constructor settings as default values + // + switch( activePageIndex() ) + { + case page_layout: + { + SDisplayLayout layout; + SDisplayLine line; + setLayout( layout, line ); + } + break; + + case page_cursor: + { + SDisplayCursor cursor; + setCursor( cursor ); + } + break; + + case page_color: + { + SDisplayColor color; + setColor( color ); + } + break; + + case page_font: + { + SDisplayFont font; + setFont( font ); + } + break; + + case page_file: + { + SDisplayMisc misc; + setFile( misc ); + } + break; + + case page_misc: + { + SDisplayMisc misc; + setMisc( misc ); + } + break; + } +} + + +void COptionDialog::slotOk( void ) +{ + if( configChanged ) + slotApply(); + accept(); +} + +void COptionDialog::slotApply( void ) +{ + switch( activePageIndex() ) + { + case page_layout: + { + int index = mLayout.formatCombo->currentItem(); + mDisplayState.line.setLineSize(index, mLayout.lineSizeSpin->value()); + mDisplayState.line.setColumnSize(index, mLayout.columnSizeSpin->value()); + emit lineSizeChoice( mDisplayState.line ); + + SDisplayLayout &l = mDisplayState.layout; + l.lockLine = mLayout.lockLineCheck->isChecked(); + l.lockColumn = mLayout.lockColumnCheck->isChecked(); + l.leftSeparatorWidth = mLayout.leftSepWidthSpin->value(); + l.rightSeparatorWidth = mLayout.rightSepWidthSpin->value(); + l.separatorMarginWidth = mLayout.separatorSpin->value(); + l.edgeMarginWidth = mLayout.edgeSpin->value(); + l.leftSeparatorWidth = mLayout.leftSepWidthSpin->value(); + l.rightSeparatorWidth = mLayout.rightSepWidthSpin->value(); + l.columnCharSpace = mLayout.columnCheck->isChecked(); + l.columnSpacing = mLayout.columnSepSpin->value(); + + if( mLayout.gridCombo->currentItem() == 0 ) + { + l.horzGridWidth = l.vertGridWidth = 0; + } + else if( mLayout.gridCombo->currentItem() == 1 ) + { + l.horzGridWidth = 0; + l.vertGridWidth = 1; + } + else if( mLayout.gridCombo->currentItem() == 2 ) + { + l.horzGridWidth = 1; + l.vertGridWidth = 0; + } + else + { + l.horzGridWidth = l.vertGridWidth = 1; + } + + emit layoutChoice( mDisplayState.layout ); + } + break; + + + case page_cursor: + { + SDisplayCursor &c = mDisplayState.cursor; + c.alwaysVisible = mCursor.blinkCheck->isChecked(); + c.interval = mCursor.blinkSpin->value(); + c.alwaysBlockShape = mCursor.blockCheck->isChecked(); + c.thickInsertShape = mCursor.thickCheck->isChecked(); + c.focusMode = cursorFocusMode(); + emit cursorChoice( mDisplayState.cursor ); + } + break; + + case page_color: + { + SDisplayColor &c = mDisplayState.color; + c.useSystemColor = mColor.checkSystem->isChecked(); + c.textBg = mColor.colorList->color( SColorWidgets::FirstTextBg ); + c.secondTextBg = mColor.colorList->color( SColorWidgets::SecondTextBg ); + c.offsetBg = mColor.colorList->color( SColorWidgets::OffsetBg ); + c.inactiveBg = mColor.colorList->color( SColorWidgets::InactiveBg ); + c.markBg = mColor.colorList->color( SColorWidgets::MarkedBg ); + c.markFg = mColor.colorList->color( SColorWidgets::MarkedFg ); + c.primaryFg[0] = mColor.colorList->color( SColorWidgets::EvenColumnFg ); + c.primaryFg[1] = mColor.colorList->color( SColorWidgets::OddColumnFg ); + c.offsetFg = mColor.colorList->color( SColorWidgets::OffsetFg ); + c.secondaryFg = mColor.colorList->color( SColorWidgets::SecondaryFg ); + c.cursorBg = mColor.colorList->color( SColorWidgets::CursorBg ); + c.cursorFg = mColor.colorList->color( SColorWidgets::CursorFg ); + c.leftSeparatorFg = mColor.colorList->color(SColorWidgets::SeparatorFg); + c.rightSeparatorFg = mColor.colorList->color(SColorWidgets::SeparatorFg); + c.bookmarkBg = mColor.colorList->color( SColorWidgets::BookmarkBg ); + c.bookmarkFg = mColor.colorList->color( SColorWidgets::BookmarkFg ); + c.nonPrintFg = mColor.colorList->color( SColorWidgets::NonPrintFg ); + c.gridFg = mColor.colorList->color( SColorWidgets::GridFg ); + emit colorChoice( mDisplayState.color ); + } + break; + + case page_font: + { + SDisplayFont &f = mDisplayState.font; + f.useSystemFont = mFont.checkSystem->isChecked(); + f.localFont = mFont.chooser->font(); + + QString nonPrintText = mFont.nonPrintInput->text(); + if( nonPrintText.isEmpty() ) + { + f.nonPrintChar = ' '; + } + else + { + f.nonPrintChar = nonPrintText[0]; + } + + emit fontChoice( mDisplayState.font ); + } + break; + + case page_file: + case page_misc: + { + SDisplayMisc &m = mDisplayState.misc; + m.undoLevel = mMisc.undoSpin->value(); + m.autoCopyToClipboard = mMisc.autoCheck->isChecked(); + m.insertMode = mMisc.insertCheck->isChecked(); + m.inputSound = mMisc.inputCheck->isChecked(); + m.confirmWrap = mMisc.confirmWrapCheck->isChecked(); + m.cursorJump = mMisc.cursorJumpCheck->isChecked(); + m.fatalSound = mMisc.fatalCheck->isChecked(); + m.confirmThreshold = mMisc.thresholdCheck->isChecked(); + m.thresholdValue = mMisc.thresholdSpin->value(); + m.bookmarkOffsetColumn = mMisc.bookmarkColumnCheck->isChecked(); + m.bookmarkEditor = mMisc.bookmarkEditorCheck->isChecked(); + + m.openFile = (SDisplayMisc::EOpenFile)mFile.openCombo->currentItem(); + m.gotoOnStartup = mFile.gotoOffsetCheck->isChecked(); + m.writeProtect = mFile.writeProtectCheck->isChecked(); + m.gotoOnReload = mFile.reloadOffsetCheck->isChecked(); + m.makeBackup = mFile.backupCheck->isChecked(); + m.discardRecent = mFile.discardRecentCheck->isChecked(); + + emit miscChoice( mDisplayState.misc ); + } + break; + } + enableButton( Apply, false ); + configChanged = false; +} + +void COptionDialog::setLayout( SDisplayLayout &layout, SDisplayLine &line ) +{ + mDisplayState.line = line; + mDisplayState.layout = layout; + + slotModeSelectorChanged( mLayout.formatCombo->currentItem() ); + mLayout.lockLineCheck->setChecked( layout.lockLine ); + mLayout.lockColumnCheck->setChecked( layout.lockColumn ); + mLayout.leftSepWidthSpin->setValue( layout.leftSeparatorWidth ); + mLayout.rightSepWidthSpin->setValue( layout.rightSeparatorWidth ); + mLayout.separatorSpin->setValue( layout.separatorMarginWidth ); + mLayout.edgeSpin->setValue( layout.edgeMarginWidth ); + mLayout.leftSepWidthSpin->setValue( layout.leftSeparatorWidth ); + mLayout.rightSepWidthSpin->setValue( layout.rightSeparatorWidth ); + mLayout.columnCheck->setChecked( layout.columnCharSpace ); + slotColumnSepCheck( layout.columnCharSpace ); + mLayout.columnSepSpin->setValue( layout.columnSpacing ); + + if( layout.horzGridWidth == 0 && layout.vertGridWidth == 0 ) + { + mLayout.gridCombo->setCurrentItem(0); + } + else if( layout.horzGridWidth != 0 && layout.vertGridWidth != 0 ) + { + mLayout.gridCombo->setCurrentItem(3); + } + else + { + mLayout.gridCombo->setCurrentItem( layout.vertGridWidth != 0 ? 1 : 2 ); + } + +} + + +void COptionDialog::setCursor( SDisplayCursor &cursor ) +{ + mDisplayState.cursor = cursor; + + mCursor.blinkCheck->setChecked( cursor.alwaysVisible ); + mCursor.blinkSpin->setValue( cursor.interval ); + mCursor.blockCheck->setChecked( cursor.alwaysBlockShape ); + mCursor.thickCheck->setChecked( cursor.thickInsertShape ); + bool state = cursor.focusMode == SDisplayCursor::stopBlinking ? true : false; + mCursor.stopRadio->setChecked( state ); + state = cursor.focusMode == SDisplayCursor::hide ? true : false; + mCursor.hideRadio->setChecked( state ); + state = cursor.focusMode == SDisplayCursor::ignore ? true : false; + mCursor.nothingRadio->setChecked( state ); +} + + +void COptionDialog::setColor( SDisplayColor &color ) +{ + mDisplayState.color = color; + + mColor.checkSystem->setChecked( color.useSystemColor ); + mColor.colorList->setColor( SColorWidgets::FirstTextBg, color.textBg ); + mColor.colorList->setColor( SColorWidgets::SecondTextBg, color.secondTextBg); + mColor.colorList->setColor( SColorWidgets::OffsetBg, color.offsetBg ); + mColor.colorList->setColor( SColorWidgets::InactiveBg, color.inactiveBg ); + mColor.colorList->setColor( SColorWidgets::MarkedBg, color.markBg ); + mColor.colorList->setColor( SColorWidgets::MarkedFg, color.markFg ); + mColor.colorList->setColor( SColorWidgets::EvenColumnFg, color.primaryFg[0]); + mColor.colorList->setColor( SColorWidgets::OddColumnFg, color.primaryFg[1] ); + mColor.colorList->setColor( SColorWidgets::OffsetFg, color.offsetFg ); + mColor.colorList->setColor( SColorWidgets::SecondaryFg, color.secondaryFg ); + mColor.colorList->setColor( SColorWidgets::CursorBg, color.cursorBg ); + mColor.colorList->setColor( SColorWidgets::CursorFg, color.cursorFg ); + mColor.colorList->setColor(SColorWidgets::SeparatorFg,color.leftSeparatorFg); + mColor.colorList->setColor( SColorWidgets::BookmarkBg, color.bookmarkBg ); + mColor.colorList->setColor( SColorWidgets::BookmarkFg, color.bookmarkFg ); + mColor.colorList->setColor( SColorWidgets::NonPrintFg, color.nonPrintFg ); + mColor.colorList->setColor( SColorWidgets::GridFg, color.gridFg ); +} + + +void COptionDialog::setFont( SDisplayFont &font ) +{ + mDisplayState.font = font; + + mFont.checkSystem->setChecked( font.useSystemFont ); + mFont.chooser->setFont( font.localFont, true ); + QString buf = font.nonPrintChar; + mFont.nonPrintInput->setText( buf ); +} + + +void COptionDialog::setMisc( SDisplayMisc &misc ) +{ + mDisplayState.misc.undoLevel = misc.undoLevel; + mDisplayState.misc.inputSound = misc.inputSound; + mDisplayState.misc.fatalSound = misc.fatalSound; + mDisplayState.misc.autoCopyToClipboard = misc.autoCopyToClipboard; + mDisplayState.misc.insertMode = misc.insertMode; + mDisplayState.misc.confirmWrap = misc.confirmWrap; + mDisplayState.misc.cursorJump = misc.cursorJump; + mDisplayState.misc.confirmThreshold = misc.confirmThreshold; + mDisplayState.misc.thresholdValue = misc.thresholdValue; + mDisplayState.misc.bookmarkOffsetColumn = misc.bookmarkOffsetColumn; + mDisplayState.misc.bookmarkEditor = misc.bookmarkEditor; + + mMisc.autoCheck->setChecked( misc.autoCopyToClipboard ); + mMisc.insertCheck->setChecked( misc.insertMode ); + mMisc.confirmWrapCheck->setChecked( misc.confirmWrap ); + mMisc.cursorJumpCheck->setChecked( misc.cursorJump ); + + mMisc.inputCheck->setChecked( misc.inputSound ); + mMisc.fatalCheck->setChecked( misc.fatalSound ); + mMisc.bookmarkColumnCheck->setChecked( misc.bookmarkOffsetColumn ); + mMisc.bookmarkEditorCheck->setChecked( misc.bookmarkEditor ); + + mMisc.thresholdCheck->setChecked( misc.confirmThreshold ); + mMisc.thresholdSpin->setValue( misc.thresholdValue ); + slotThresholdConfirm(); + + mMisc.undoSpin->setValue( misc.undoLevel ); +} + +void COptionDialog::setFile( SDisplayMisc &misc ) +{ + mDisplayState.misc.openFile = misc.openFile; + mDisplayState.misc.gotoOnStartup = misc.gotoOnStartup; + mDisplayState.misc.writeProtect = misc.writeProtect; + mDisplayState.misc.gotoOnReload = misc.gotoOnReload; + mDisplayState.misc.discardRecent = misc.discardRecent; + mDisplayState.misc.makeBackup = misc.makeBackup; + + mFile.openCombo->setCurrentItem( (uint)misc.openFile ); + mFile.gotoOffsetCheck->setChecked( misc.gotoOnStartup ); + mFile.writeProtectCheck->setChecked( misc.writeProtect ); + mFile.reloadOffsetCheck->setChecked( misc.gotoOnReload ); + mFile.discardRecentCheck->setChecked( misc.discardRecent ); + mFile.backupCheck->setChecked( misc.makeBackup ); +} + + +void COptionDialog::setState( SDisplayState &state ) +{ + setLayout( state.layout, state.line ); + setCursor( state.cursor ); + setColor( state.color ); + setFont( state.font ); + setFile( state.misc ); + setMisc( state.misc ); + enableButton( Apply, false ); + configChanged = false; +} + + +SDisplayCursor::EFocusMode COptionDialog::cursorFocusMode( void ) +{ + if( mCursor.stopRadio->isChecked() == true ) + { + return( SDisplayCursor::stopBlinking ); + } + else if( mCursor.hideRadio->isChecked() == true ) + { + return( SDisplayCursor::hide ); + } + else + { + return( SDisplayCursor::ignore ); + } +} + + + +CColorListBox::CColorListBox( QWidget *parent, const char *name, WFlags f ) + :KListBox( parent, name, f ), mCurrentOnDragEnter(-1) +{ + connect( this, SIGNAL(selected(int)), this, SLOT(newColor(int)) ); + setAcceptDrops( true); +} + + +void CColorListBox::setEnabled( bool state ) +{ + if( state == isEnabled() ) + { + return; + } + + QListBox::setEnabled( state ); + for( uint i=0; i<count(); i++ ) + { + updateItem( i ); + } +} + + +void CColorListBox::setColor( uint index, const QColor &color ) +{ + if( index < count() ) + { + CColorListItem *colorItem = (CColorListItem*)item(index); + colorItem->setColor(color); + updateItem( colorItem ); + } +} + + +const QColor CColorListBox::color( uint index ) +{ + if( index < count() ) + { + CColorListItem *colorItem = (CColorListItem*)item(index); + return( colorItem->color() ); + } + else + { + return( black ); + } +} + + +void CColorListBox::newColor( int index ) +{ + if( isEnabled() == false ) + { + return; + } + + if( (uint)index < count() ) + { + QColor c = color( index ); + if( KColorDialog::getColor( c, this ) != QDialog::Rejected ) + { + setColor( index, c ); + emit dataChanged(); + } + } +} + + +void CColorListBox::dragEnterEvent( QDragEnterEvent *e ) +{ + if( KColorDrag::canDecode(e) && isEnabled() ) + { + mCurrentOnDragEnter = currentItem(); + e->accept( true ); + } + else + { + mCurrentOnDragEnter = -1; + e->accept( false ); + } +} + + +void CColorListBox::dragLeaveEvent( QDragLeaveEvent * ) +{ + if( mCurrentOnDragEnter != -1 ) + { + setCurrentItem( mCurrentOnDragEnter ); + mCurrentOnDragEnter = -1; + } +} + + +void CColorListBox::dragMoveEvent( QDragMoveEvent *e ) +{ + if( KColorDrag::canDecode(e) && isEnabled() ) + { + CColorListItem *item = (CColorListItem*)itemAt( e->pos() ); + if( item != 0 ) + { + setCurrentItem ( item ); + } + } +} + + +void CColorListBox::dropEvent( QDropEvent *e ) +{ + QColor color; + if( KColorDrag::decode( e, color ) ) + { + int index = currentItem(); + if( index != -1 ) + { + CColorListItem *colorItem = (CColorListItem*)item(index); + colorItem->setColor(color); + triggerUpdate( false ); // Redraw item + } + mCurrentOnDragEnter = -1; + } +} + + + +CColorListItem::CColorListItem( const QString &text, const QColor &color ) + : QListBoxItem(), mColor( color ), mBoxWidth( 30 ) +{ + setText( text ); +} + + +const QColor &CColorListItem::color( void ) +{ + return( mColor ); +} + + +void CColorListItem::setColor( const QColor &color ) +{ + mColor = color; +} + + +void CColorListItem::paint( QPainter *p ) +{ + QFontMetrics fm = p->fontMetrics(); + int h = fm.height(); + + p->drawText( mBoxWidth+3*2, fm.ascent() + fm.leading()/2, text() ); + + p->setPen( Qt::black ); + p->drawRect( 3, 1, mBoxWidth, h-1 ); + p->fillRect( 4, 2, mBoxWidth-2, h-3, mColor ); +} + + +int CColorListItem::height(const QListBox *lb ) const +{ + return( lb->fontMetrics().lineSpacing()+1 ); +} + + +int CColorListItem::width(const QListBox *lb ) const +{ + return( mBoxWidth + lb->fontMetrics().width( text() ) + 6 ); +} + + + + + + +#include "optiondialog.moc" diff --git a/khexedit/optiondialog.h b/khexedit/optiondialog.h new file mode 100644 index 0000000..ba62f62 --- /dev/null +++ b/khexedit/optiondialog.h @@ -0,0 +1,269 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _OPTION_DIALOG_H_ +#define _OPTION_DIALOG_H_ + + +class QComboBox; +class QFrame; +class QCheckBox; +class QLabel; +class QLineEdit; +class QPushbutton; +class QRadioButton; +class QSpinBox; +class QComboBox; +class KFontChooser; + + +#include <kdialogbase.h> +#include <klistbox.h> +#include "hexeditstate.h" + + + +class CColorListBox : public KListBox +{ + Q_OBJECT + + public: + CColorListBox( QWidget *parent=0, const char * name=0, WFlags f=0 ); + void setColor( uint index, const QColor &color ); + const QColor color( uint index ); + + public slots: + virtual void setEnabled( bool state ); + + protected: + void dragEnterEvent( QDragEnterEvent *e ); + void dragLeaveEvent( QDragLeaveEvent *e ); + void dragMoveEvent( QDragMoveEvent *e ); + void dropEvent( QDropEvent *e ); + + private slots: + void newColor( int index ); + + private: + int mCurrentOnDragEnter; + + signals: + void dataChanged(); +}; + + +class CColorListItem : public QListBoxItem +{ + public: + CColorListItem( const QString &text, const QColor &color=Qt::black ); + const QColor &color( void ); + void setColor( const QColor &color ); + + protected: + virtual void paint( QPainter * ); + virtual int height( const QListBox * ) const; + virtual int width( const QListBox * ) const; + + private: + QColor mColor; + int mBoxWidth; +}; + + + + +class COptionDialog : public KDialogBase +{ + Q_OBJECT + + public: + enum EPage + { + page_layout = 0, + page_cursor, + page_font, + page_color, + page_file, + page_misc, + page_max + }; + + COptionDialog( QWidget *parent = 0, char *name = 0, bool modal = false ); + ~COptionDialog( void ); + + void setLayout( SDisplayLayout &layout, SDisplayLine &line ); + void setCursor( SDisplayCursor &cursor ); + void setColor( SDisplayColor &color ); + void setFont( SDisplayFont &font ); + void setFile( SDisplayMisc &misc ); + void setMisc( SDisplayMisc &misc ); + void setState( SDisplayState &state ); + + protected: + virtual void showEvent( QShowEvent *e ); + + protected slots: + void slotModeSelectorChanged( int index ); + void slotLineSizeChanged( int value ); + void slotColumnSizeChanged( int value ); + void slotColumnSepCheck( bool state ); + void slotBlinkIntervalCheck( bool state ); + void slotBlockCursorCheck( bool state ); + void slotFontSystem( bool state ); + void slotColorSystem( bool state ); + void slotThresholdConfirm( void ); + + virtual void slotDefault( void ); + virtual void slotOk( void ); + virtual void slotApply( void ); + void slotChanged(); + + private: + struct SLayoutWidgets + { + QComboBox *formatCombo; + QSpinBox *lineSizeSpin; + QSpinBox *columnSizeSpin; + QCheckBox *lockLineCheck; + QCheckBox *lockColumnCheck; + QCheckBox *columnCheck; + QComboBox *gridCombo; + QLabel *leftSepLabel; + QLabel *rightSepLabel; + QSpinBox *leftSepWidthSpin; + QSpinBox *rightSepWidthSpin; + QSpinBox *separatorSpin; + QSpinBox *edgeSpin; + QLabel *columnSepLabel; + QSpinBox *columnSepSpin; + + }; + struct SCursorWidgets + { + QCheckBox *blinkCheck; + QSpinBox *blinkSpin; + QLabel *blinkLabel; + QCheckBox *blockCheck; + QCheckBox *thickCheck; + QRadioButton *stopRadio; + QRadioButton *hideRadio; + QRadioButton *nothingRadio; + }; + struct SColorWidgets + { + enum colorType + { + FirstTextBg = 0, + SecondTextBg, + OffsetBg, + InactiveBg, + EvenColumnFg, + OddColumnFg, + NonPrintFg, + OffsetFg, + SecondaryFg, + MarkedBg, + MarkedFg, + CursorBg, + CursorFg, + BookmarkBg, + BookmarkFg, + SeparatorFg, + GridFg, + MAX_COLOR + }; + + QCheckBox *checkSystem; + CColorListBox *colorList; + }; + struct SFontWidgets + { + QCheckBox *checkSystem; + KFontChooser *chooser; + QLineEdit *nonPrintInput; + }; + struct SFileWidgets + { + QComboBox *openCombo; + QCheckBox *gotoOffsetCheck; + QCheckBox *reloadOffsetCheck; + QCheckBox *writeProtectCheck; + QCheckBox *backupCheck; + QCheckBox *discardRecentCheck; + }; + struct SMiscWidgets + { + QSpinBox *undoSpin; + QCheckBox *inputCheck; + QCheckBox *fatalCheck; + QCheckBox *autoCheck; + QCheckBox *insertCheck; + QCheckBox *confirmWrapCheck; + QCheckBox *cursorJumpCheck; + QCheckBox *thresholdCheck; + QCheckBox *bookmarkColumnCheck; + QCheckBox *bookmarkEditorCheck; + QLabel *thresholdLabel; + QSpinBox *thresholdSpin; + }; + + private: + void setupLayoutPage( void ); + void setupCursorPage( void ); + void setupColorPage( void ); + void setupFontPage( void ); + void setupFilePage( void ); + void setupMiscPage( void ); + SDisplayCursor::EFocusMode cursorFocusMode( void ); + + + signals: + void lineSizeChoice( const SDisplayLine &lineSize ); + void layoutChoice( const SDisplayLayout &layout ); + void cursorChoice( const SDisplayCursor &cursor ); + void colorChoice( const SDisplayColor &color ); + void fontChoice( const SDisplayFont &font ); + void miscChoice( const SDisplayMisc &misc ); + void removeRecentFiles( void ); + + private: + SDisplayState mDisplayState; + SLayoutWidgets mLayout; + SCursorWidgets mCursor; + SColorWidgets mColor; + SFontWidgets mFont; + SFileWidgets mFile; + SMiscWidgets mMisc; + bool configChanged; + +}; + + + + + +#endif + + + + + + + diff --git a/khexedit/parts/Makefile.am b/khexedit/parts/Makefile.am new file mode 100644 index 0000000..7e2726b --- /dev/null +++ b/khexedit/parts/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = kbytesedit kpart diff --git a/khexedit/parts/README b/khexedit/parts/README new file mode 100644 index 0000000..a484f1e --- /dev/null +++ b/khexedit/parts/README @@ -0,0 +1,3 @@ +hex editor parts +================== +in each subdirectory one part based on the KHexEdit2 library diff --git a/khexedit/parts/kbytesedit/Makefile.am b/khexedit/parts/kbytesedit/Makefile.am new file mode 100644 index 0000000..b8be127 --- /dev/null +++ b/khexedit/parts/kbytesedit/Makefile.am @@ -0,0 +1,15 @@ +kde_module_LTLIBRARIES = libkbyteseditwidget.la + +INCLUDES = -I$(srcdir)/../../lib $(all_includes) + +noinst_HEADERS = kbyteseditwidget.h + +METASOURCES = AUTO + +libkbyteseditwidget_la_SOURCES = kbyteseditwidget.cpp + +libkbyteseditwidget_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module -avoid-version -no-undefined +libkbyteseditwidget_la_LIBADD = ../../lib/libkhexeditcommon.la $(LIB_KPARTS) + +service_DATA = kbyteseditwidget.desktop +servicedir = $(kde_servicesdir) diff --git a/khexedit/parts/kbytesedit/README b/khexedit/parts/kbytesedit/README new file mode 100644 index 0000000..e3aa164 --- /dev/null +++ b/khexedit/parts/kbytesedit/README @@ -0,0 +1,23 @@ +KBytesEdit widget modul +======================= +part of the KHexEdit 2 project (kdenonbeta/khexedit2) +Author/Maintainer: Friedrich W. H. Kossebau <Friedrich.W.H@Kossebau.de> + + +description: +------------ +This module delivers a service for the service type "KHexEdit/KBytesEdit". +It is a hex edit widget that operates on an array of chars given by +the programmer. +It serves right now the interfaces +HexColumnInterface, TextColumnInterface, ZoomInterface, ClipBoardInterface. + + +installing: +----------- +Installs the .desktop file describing the service and the module library. + + +usage: +------ +Only official known usage is by KPilot (kdepim/kpilot) for now.
\ No newline at end of file diff --git a/khexedit/parts/kbytesedit/kbyteseditwidget.cpp b/khexedit/parts/kbytesedit/kbyteseditwidget.cpp new file mode 100644 index 0000000..4cc91ab --- /dev/null +++ b/khexedit/parts/kbytesedit/kbyteseditwidget.cpp @@ -0,0 +1,319 @@ +/*************************************************************************** + kbyteseditwidget.cpp - description + ------------------- + begin : Fri Aug 29 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <qlayout.h> +// kde specific +#include <klocale.h> +#include <kgenericfactory.h> +#include <kapplication.h> +// lib specific +#include "kbytesedit.h" +#include "kbyteseditwidget.h" + + +KBytesEditWidget::KBytesEditWidget( QWidget *parent, const char *name, const QStringList & ) + : QWidget( parent, name) +{ + QHBoxLayout* Layout = new QHBoxLayout( this ); + BytesEdit = new KHE::KBytesEdit( this, "BytesEdit" ); + Layout->addWidget( BytesEdit ); +// connect( _editor, SIGNAL( canUndo(bool) ), this, SIGNAL( canUndo(bool) ) ); + connect( BytesEdit, SIGNAL(copyAvailable( bool )), this, SIGNAL(copyAvailable( bool )) ); +} + + + +void KBytesEditWidget::setData( char *D, int S, int RS, bool KM ) +{ + BytesEdit->setData( D, S, RS, KM ); +} + + +void KBytesEditWidget::setReadOnly( bool RO ) +{ + BytesEdit->setReadOnly( RO ); +} + +void KBytesEditWidget::setMaxDataSize( int MS ) +{ + BytesEdit->setMaxDataSize( MS ); +} + +void KBytesEditWidget::setAutoDelete( bool AD ) +{ + BytesEdit->setAutoDelete( AD ); +} + + +void KBytesEditWidget::setKeepsMemory( bool KM ) +{ + BytesEdit->setKeepsMemory( KM ); +} + + +void KBytesEditWidget::setCursorPosition( int Index ) +{ + BytesEdit->setCursorPosition( Index ); +} + +void KBytesEditWidget::setCoding( KCoding C ) +{ + BytesEdit->setCoding( (KHE::KHexEdit::KCoding) C ); +} + +void KBytesEditWidget::setResizeStyle( KResizeStyle Style ) +{ + BytesEdit->setResizeStyle( (KHE::KHexEdit::KResizeStyle) Style ); +} +int KBytesEditWidget::noOfBytesPerLine() const +{ + return BytesEdit->noOfBytesPerLine(); +} + +KBytesEditWidget::KResizeStyle KBytesEditWidget::resizeStyle() const +{ + return (KResizeStyle)BytesEdit->resizeStyle(); +} +void KBytesEditWidget::setNoOfBytesPerLine( int NoCpL ) +{ + BytesEdit->setNoOfBytesPerLine( NoCpL ); +} + + + +void KBytesEditWidget::setOverwriteOnly( bool b ) +{ + BytesEdit->setOverwriteOnly( b ); +} + + +void KBytesEditWidget::setOverwriteMode( bool b ) +{ + BytesEdit->setOverwriteMode( b ); +} + + +void KBytesEditWidget::setModified( bool b ) +{ + BytesEdit->setModified( b ); +} + + +void KBytesEditWidget::setByteSpacingWidth( int BSW ) +{ + BytesEdit->setByteSpacingWidth( BSW ); +} + +void KBytesEditWidget::setNoOfGroupedBytes( int NoGB ) +{ + BytesEdit->setNoOfGroupedBytes( NoGB ); +} + +void KBytesEditWidget::setGroupSpacingWidth( int GSW ) +{ + BytesEdit->setGroupSpacingWidth( GSW ); +} + +void KBytesEditWidget::setBinaryGapWidth( int BGW ) +{ + BytesEdit->setBinaryGapWidth( BGW ); +} + +void KBytesEditWidget::setEncoding( KEncoding C ) +{ + BytesEdit->setEncoding( (KHE::KHexEdit::KEncoding)C ); +} + +void KBytesEditWidget::setShowUnprintable( bool SU ) +{ + BytesEdit->setShowUnprintable( SU ); +} + +void KBytesEditWidget::setSubstituteChar( QChar SC ) +{ + BytesEdit->setSubstituteChar( SC ); +} + + +char *KBytesEditWidget::data() const +{ + return BytesEdit->data(); +} + +int KBytesEditWidget::dataSize() const +{ + return BytesEdit->dataSize(); +} +int KBytesEditWidget::maxDataSize () const +{ + return BytesEdit->maxDataSize(); +} +bool KBytesEditWidget::isAutoDelete() const +{ + return BytesEdit->isAutoDelete(); +} + +bool KBytesEditWidget::keepsMemory() const +{ + return BytesEdit->keepsMemory(); +} + +bool KBytesEditWidget::isOverwriteMode() const +{ + return BytesEdit->isOverwriteMode(); +} + +bool KBytesEditWidget::isOverwriteOnly() const +{ + return BytesEdit->isOverwriteOnly(); +} + +bool KBytesEditWidget::isModified() const +{ + return BytesEdit->isModified(); +} + +bool KBytesEditWidget::isReadOnly() const +{ + return BytesEdit->isReadOnly(); +} + + +// bool KBytesEditWidget::tabChangesFocus() const +// { +// } + + + +KBytesEditWidget::KCoding KBytesEditWidget::coding() const +{ + return (KCoding)BytesEdit->coding(); +} + +int KBytesEditWidget::byteSpacingWidth() const +{ + return BytesEdit->byteSpacingWidth(); +} + +int KBytesEditWidget::noOfGroupedBytes() const +{ + return BytesEdit->noOfGroupedBytes(); +} + +int KBytesEditWidget::groupSpacingWidth() const +{ + return BytesEdit->groupSpacingWidth(); +} + +int KBytesEditWidget::binaryGapWidth() const +{ + return BytesEdit->binaryGapWidth(); +} + +bool KBytesEditWidget::showUnprintable() const +{ + return BytesEdit->showUnprintable(); +} + +QChar KBytesEditWidget::substituteChar() const +{ + return BytesEdit->substituteChar(); +} + +KBytesEditWidget::KEncoding KBytesEditWidget::encoding() const +{ + return (KEncoding)BytesEdit->encoding(); +} + + +bool KBytesEditWidget::hasSelectedData() const +{ + return BytesEdit->hasSelectedData(); +} + + +void KBytesEditWidget::repaintRange( int i1, int i2 ) +{ + BytesEdit->repaintRange( i1, i2 ); +} + + +void KBytesEditWidget::insert( const QByteArray &D ) +{ + BytesEdit->insert( D ); +} + + +void KBytesEditWidget::selectAll( bool Select ) +{ + BytesEdit->selectAll( Select ); +} + + // clipboard interface +void KBytesEditWidget::copy() +{ + BytesEdit->copy(); +} + +void KBytesEditWidget::cut() +{ + BytesEdit->cut(); +} + +void KBytesEditWidget::paste() +{ + BytesEdit->paste(); +} + +// zooming interface +void KBytesEditWidget::zoomIn( int PointInc ) +{ + BytesEdit->zoomIn( PointInc ); +} + +void KBytesEditWidget::zoomIn() +{ + BytesEdit->zoomIn(); +} + +void KBytesEditWidget::zoomOut( int PointDec ) +{ + BytesEdit->zoomOut( PointDec ); +} + +void KBytesEditWidget::zoomOut() +{ + BytesEdit->zoomOut(); +} + +void KBytesEditWidget::zoomTo( int PointSize ) +{ + BytesEdit->zoomTo( PointSize ); +} + +void KBytesEditWidget::unZoom() +{ + BytesEdit->unZoom(); +} + + +typedef K_TYPELIST_1( KBytesEditWidget ) Product; +K_EXPORT_COMPONENT_FACTORY( libkbyteseditwidget, KGenericFactory<Product>( "kbytesedit" ) ) +//K_EXPORT_COMPONENT_FACTORY( libkbyteseditwidget, KGenericFactory<MyPlugin> ) + +#include "kbyteseditwidget.moc" diff --git a/khexedit/parts/kbytesedit/kbyteseditwidget.desktop b/khexedit/parts/kbytesedit/kbyteseditwidget.desktop new file mode 100644 index 0000000..4a050a6 --- /dev/null +++ b/khexedit/parts/kbytesedit/kbyteseditwidget.desktop @@ -0,0 +1,52 @@ +[Desktop Entry] +Type=Service +Name=BytesEdit Widget +Name[ar]=كائن BytesEdit +Name[bg]=Модул за двоично редактиране на файлове +Name[bs]=BytesEdit grafiÄki element +Name[ca]=Estri BytesEdit +Name[cy]=Celfigyn GolyguBeit +Name[de]=BytesEdit-Bedienelement +Name[el]=ΓÏαφικό συστατικό BytesEdit +Name[eo]=BytesEdit-fenestraĵo +Name[es]=Ventana de edición de bytes +Name[et]=Baitide redigeerimise komponent +Name[eu]=Byteak Editatzeko Widget-a +Name[fa]=عنصر ویرایش بایت +Name[fi]=BytesEdit käyttöliittymäkomponentti +Name[fr]=Composant éditeur binaire +Name[ga]=Giuirléid BytesEdit +Name[he]=פריט עורך ×”×‘×™×˜×•×™×™× ×”×¡×“×™×¨×™× +Name[hi]=बाइटà¥à¤¸-à¤à¤¡à¤¿à¤Ÿ विजेट +Name[hu]=BytesEdit grafikus elem +Name[is]=Græja til að sýsla með bætaskrár +Name[it]=Elemento grafico editor di byte +Name[ja]=ãƒã‚¤ãƒˆã‚¨ãƒ‡ã‚£ãƒƒãƒˆã‚¦ã‚£ã‚¸ã‚§ãƒƒãƒˆ +Name[kk]=Бинарлы деректерді өңдеу бөлшегі +Name[km]=ážœážáŸ’ážáž»áž˜áž¾áž›ážƒáž¾áž‰ BytesEdit +Name[lt]=BytesEdit valdiklis +Name[mk]=BytesEdit - графичка контрола +Name[nb]=BytesEdit skjermelement +Name[nds]=BytesEdit-Bedeenelement +Name[ne]=बाइट समà¥à¤ªà¤¾à¤¦à¤¨ विजेट +Name[nn]=BytesEdit-skjermelement +Name[pa]=ਬਾਈਟ ਸੋਧ ਸਹਾਇਕ +Name[pl]=Okienko BytesEdit +Name[pt]=Editor de Bytes +Name[pt_BR]=Widget do Editor de Bytes +Name[ro]=Componentă de editare octeÅ£i +Name[ru]=Виджет Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð²Ð¾Ð¸Ñ‡Ð½Ñ‹Ñ… данных +Name[sk]=Prvok BytesEdit +Name[sl]=Gradnik BytesEdit +Name[sr]=Контрола за бинарно уређивање +Name[sr@Latn]=Kontrola za binarno ureÄ‘ivanje +Name[sv]=Grafisk komponent för att redigera binärdata +Name[ta]= பைடà¯à®¸à¯à®¤à¯Šà®•à¯à®ªà¯à®ªà¯ சாளரம௠+Name[tg]=Ðлементи Таҳрири Додаҳои Дуӣ +Name[uk]=Віджет побайтового Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ +Name[zh_CN]=å—节编辑部件 +Name[zh_TW]=ä½å…ƒç·¨è¼¯å™¨å…ƒä»¶ +X-KDE-Library=libkbyteseditwidget +InitialPreference=2 +ServiceTypes=KHexEdit/KBytesEdit + diff --git a/khexedit/parts/kbytesedit/kbyteseditwidget.h b/khexedit/parts/kbytesedit/kbyteseditwidget.h new file mode 100644 index 0000000..78e4dba --- /dev/null +++ b/khexedit/parts/kbytesedit/kbyteseditwidget.h @@ -0,0 +1,185 @@ +/*************************************************************************** + kbyteseditwidget.h - description + ------------------- + begin : Fri Aug 29 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KBYTESEDITWIDGET_H +#define KBYTESEDITWIDGET_H + +// qt specific +#include <qwidget.h> +// kde specific +#include <khexedit/byteseditinterface.h> +#include <khexedit/valuecolumninterface.h> +#include <khexedit/charcolumninterface.h> +#include <khexedit/zoominterface.h> +#include <khexedit/clipboardinterface.h> + + +namespace KHE { +class KBytesEdit; +} + +/** + hex editor/viewer. + + @author Friedrich W. H. Kossebau <Friedrich.W.H@Kossebau.de> + @version 0.1 + **/ +class KBytesEditWidget : public QWidget, public KHE::BytesEditInterface, + public KHE::ValueColumnInterface, public KHE::CharColumnInterface, + public KHE::ZoomInterface, public KHE::ClipboardInterface +{ + Q_OBJECT + + public: + /** constructor API as demanded by KGenericFactory */ + KBytesEditWidget( QWidget *parent, const char *name, const QStringList & = QStringList() ); + + public: // bytesedit interface + /** hands over to the editor a new byte array. + * If there exists an old one and autodelete is set the old one gets deleted. + * @param D pointer to memory + * @param DS_ size of used memory + * @param RS_ real size of the memory + * @param KM keep the memory on resize (RS_ is the maximum size) + */ + virtual void setData( char *D, int DS_, int RS_ = -1, bool KM = true ); + + /** sets the maximal size of the actual byte array. If the actual array is already larger + * it will not be modified but there can be only done non-inserting actions + * until the array's is below the limit + */ + virtual void setMaxDataSize( int MS ); + /** sets whether the array should be deleted on the widget's end or if a new array is set. + * Default is false + */ + virtual void setAutoDelete( bool AD = true ); + /** sets whether the memory given by setData or in the constructor should be kept on resize + */ + virtual void setKeepsMemory( bool KM = true ); + /** */ + virtual char *data() const; + /** returns the size of the actual byte array */ + virtual int dataSize() const; + /** returns the maximal allowed size for the byte array */ + virtual int maxDataSize () const; + /** returns whether autodelete is set for the byte array */ + virtual bool isAutoDelete() const; + /** returns whether the memory of the byte array is kept */ + virtual bool keepsMemory() const; + /** */ + virtual bool isOverwriteMode() const; + virtual bool isOverwriteOnly() const; + virtual bool isReadOnly() const; + virtual bool isModified() const; + /** repaint the indizes from i1 to i2 */ + virtual void repaintRange( int i1, int i2 ); + + public: // cursor interface + /** */ + virtual void setCursorPosition( int Index ); +// virtual bool tabChangesFocus() const; + + public: // layout interface ?? + /** sets the resizestyle for the value column. Default is KHE::FullSizeUsage */ + virtual void setResizeStyle( KResizeStyle Style ); + /** sets the number of bytes per line, switching the resize style to KHE::NoResize */ + virtual void setNoOfBytesPerLine( int NoCpL ); + + virtual int noOfBytesPerLine() const; + virtual KResizeStyle resizeStyle() const; + + public: // value column + /** sets the format of the value column. Default is KHE::HexadecimalCoding */ + virtual void setCoding( KCoding C ); + /** sets the spacing between the bytes in pixels */ + virtual void setByteSpacingWidth( int BSW ); + /** sets the numbers of grouped bytes, 0 means no grouping, Default is 4 */ + virtual void setNoOfGroupedBytes( int NoGB ); + /** sets the spacing between the groups in pixels */ + virtual void setGroupSpacingWidth( int GSW ); + /** sets the spacing in the middle of a binary byte in the value column + * @param BGW spacing in the middle of a binary in pixels + */ + virtual void setBinaryGapWidth( int BGW ); + + virtual KCoding coding() const; + virtual int byteSpacingWidth() const; + + virtual int noOfGroupedBytes() const; + virtual int groupSpacingWidth() const; + virtual int binaryGapWidth() const; + + public: // char column + /** sets whether "unprintable" chars (>32) should be displayed in the char column + * with their corresponding character. + * @param SU + * returns true if there was a change + */ + virtual void setShowUnprintable( bool SU = true ); + /** sets the substitute character for "unprintable" chars + * returns true if there was a change + */ + virtual void setSubstituteChar( QChar SC ); + /** sets the encoding of the char column. Default is KHE::LocalEncoding. + * If the encoding is not available the format will not be changed. */ + virtual void setEncoding( KEncoding C ); + /** returns true if "unprintable" chars (>32) are displayed in the char column + * with their corresponding character, default is false + */ + virtual bool showUnprintable() const; + /** returns the actually used substitute character for "unprintable" chars, default is '.' */ + virtual QChar substituteChar() const; + /** */ + virtual KEncoding encoding() const; + + public: // edit interface + /** */ + virtual void insert( const QByteArray &D ); + /** de-/selects all data */ + virtual void selectAll( bool select ); + /** returns true if there is a selected range in the array */ + virtual bool hasSelectedData() const; + + public slots: + // bytesedit interface + virtual void setReadOnly( bool RO = true ); + virtual void setOverwriteOnly( bool b ); + virtual void setOverwriteMode( bool b ); + virtual void setModified( bool b ); + + // clipboard interface + virtual void copy(); + virtual void cut(); + virtual void paste(); + + // zooming interface + virtual void zoomIn( int PointInc ); + virtual void zoomIn(); + virtual void zoomOut( int PointDec ); + virtual void zoomOut(); + virtual void zoomTo( int PointSize ); + virtual void unZoom(); + + signals: + // clipboard interface + virtual void copyAvailable( bool Really ); + + protected: + KHE::KBytesEdit* BytesEdit; +}; + +#endif diff --git a/khexedit/parts/kpart/Makefile.am b/khexedit/parts/kpart/Makefile.am new file mode 100644 index 0000000..42d9c77 --- /dev/null +++ b/khexedit/parts/kpart/Makefile.am @@ -0,0 +1,21 @@ +kde_module_LTLIBRARIES = libkhexedit2part.la + +INCLUDES = -I$(srcdir)/../../lib $(all_includes) + +noinst_HEADERS = khepart.h khebrowserextension.h khepartfactory.h + +METASOURCES = AUTO + +libkhexedit2part_la_SOURCES = khepart.cpp khebrowserextension.cpp khepartfactory.cpp + +libkhexedit2part_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module -no-undefined +libkhexedit2part_la_LIBADD = ../../lib/libkhexeditcommon.la $(LIB_KPARTS) $(LIB_KIO) + +partdesktop_DATA = khexedit2part.desktop +partdesktopdir = $(kde_servicesdir) + +partrc_DATA = khexedit2partui.rc +partrcdir = $(kde_datadir)/khexedit2part + +messages: rc.cpp + $(XGETTEXT) *.cpp -o $(podir)/khexedit2part.pot diff --git a/khexedit/parts/kpart/khebrowserextension.cpp b/khexedit/parts/kpart/khebrowserextension.cpp new file mode 100644 index 0000000..d4fc3f3 --- /dev/null +++ b/khexedit/parts/kpart/khebrowserextension.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + khebrowserextension.cpp - description + ------------------- + begin : Di Nov 16 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// qt specific +#include <kaction.h> +// app specific +#include "khexedit.h" +#include "khepart.h" +#include "khebrowserextension.h" + +using namespace KHE; + + +KHexEditBrowserExtension::KHexEditBrowserExtension( KHexEditPart *P ) + : KParts::BrowserExtension( P, "khexeditpartbrowserextension" ), + HexEditPart( P ) +{ + connect( HexEditPart->HexEdit, SIGNAL( selectionChanged() ), this, SLOT( slotSelectionChanged() ) ); +} + +void KHexEditBrowserExtension::copy() +{ + HexEditPart->HexEdit->copy(); +} + + +void KHexEditBrowserExtension::slotSelectionChanged() +{ + emit enableAction( "copy", HexEditPart->HexEdit->hasSelectedData() ); +} + + +void KHexEditBrowserExtension::saveState( QDataStream &stream ) +{ + KParts::BrowserExtension::saveState( stream ); + + KHexEdit *HexEdit = HexEditPart->HexEdit; + + stream << (int)HexEdit->offsetColumnVisible() << HexEdit->visibleBufferColumns() + << (int)HexEdit->resizeStyle() << (int)HexEdit->coding() + << HexEdit->encodingName() << (int)HexEdit->showUnprintable() + << HexEdit->contentsX() << HexEdit->contentsY() + << HexEdit->cursorPosition() << (int)HexEdit->isCursorBehind() + << HexEdit->cursorColumn(); +} + + +void KHexEditBrowserExtension::restoreState( QDataStream &stream ) +{ + KParts::BrowserExtension::restoreState( stream ); + + int OffsetColumnVisible; + int VisibleBufferColumns; + int ResizeStyle; + int Coding; + QString EncodingName; + int ShowUnprintable; + int x, y; + int Position; + int CursorBehind; + int CursorColumn; + + stream >> OffsetColumnVisible >> VisibleBufferColumns >> ResizeStyle >> Coding >> EncodingName >> ShowUnprintable + >> x >> y >> Position >> CursorBehind >> CursorColumn; + + KHexEdit *HexEdit = HexEditPart->HexEdit; + + HexEdit->toggleOffsetColumn( OffsetColumnVisible ); + HexEdit->showBufferColumns( VisibleBufferColumns ); + HexEdit->setResizeStyle( (KHexEdit::KResizeStyle)ResizeStyle ); + HexEdit->setCoding( (KHexEdit::KCoding)Coding ); + HexEdit->setEncoding( EncodingName ); + HexEdit->setShowUnprintable( ShowUnprintable ); + HexEdit->setContentsPos( x, y ); + HexEdit->setCursorPosition( Position, CursorBehind ); + HexEdit->setCursorColumn( (KHexEdit::KBufferColumnId)CursorColumn ); + + HexEditPart->fitActionSettings(); +} + +#include "khebrowserextension.moc" diff --git a/khexedit/parts/kpart/khebrowserextension.h b/khexedit/parts/kpart/khebrowserextension.h new file mode 100644 index 0000000..4638944 --- /dev/null +++ b/khexedit/parts/kpart/khebrowserextension.h @@ -0,0 +1,58 @@ +/*************************************************************************** + khebrowserextension.h - description + ------------------- + begin : Di Nov 16 2004 + copyright : (C) 2004 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHEBROWSEREXTENSION_H +#define KHEBROWSEREXTENSION_H + +// kde specific +#include <kparts/browserextension.h> + +namespace KHE +{ + +// forward declaration +class KHexEditPart; + +/** + * @short Extension for better support for embedding in browsers + * @author Friedrich W. H. Kossebau <Friedrich.W.H@Kossebau.de> + */ +class KHexEditBrowserExtension : public KParts::BrowserExtension +{ + Q_OBJECT + + public: + KHexEditBrowserExtension( KHexEditPart *P ); + + public: // KParts::BrowserExtension API + virtual void saveState( QDataStream &stream ); + virtual void restoreState( QDataStream &stream ); + + public slots: + /** copy text to clipboard */ + void copy(); + + /** selection has changed */ + void slotSelectionChanged(); + + protected: + KHexEditPart *HexEditPart; +}; + +} + +#endif diff --git a/khexedit/parts/kpart/khepart.cpp b/khexedit/parts/kpart/khepart.cpp new file mode 100644 index 0000000..e9b9ed5 --- /dev/null +++ b/khexedit/parts/kpart/khepart.cpp @@ -0,0 +1,213 @@ +/*************************************************************************** + khepart.cpp - description + ------------------- + begin : Don Jun 19 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// kde specific +#include <klocale.h> +//#include <kinstance.h> +#include <kaction.h> +#include <kstdaction.h> +//#include <kglobalsettings.h> +// app specific +#include "khexedit.h" +#include "kcharcodec.h" +#include "khepartfactory.h" +#include "khebrowserextension.h" +#include "khepart.h" + +using namespace KHE; + +static const char RCFileName[] = "khexedit2partui.rc"; + +KHexEditPart::KHexEditPart( QWidget *ParentWidget, const char *WidgetName, + QObject *Parent, const char *Name, + bool BrowserViewWanted ) + : KParts::ReadOnlyPart( Parent, Name ) +{ + setInstance( KHexEditPartFactory::instance() ); + + HexEdit = new KHexEdit( &Wrapping, ParentWidget, WidgetName ); + HexEdit->setNoOfBytesPerLine( 16 ); + HexEdit->setBufferSpacing( 3, 4, 10 ); + HexEdit->setShowUnprintable( false ); + + // notify the part that this is our internal widget + setWidget( HexEdit ); + + setupActions( BrowserViewWanted ); + + if( CopyAction ) + { + connect( HexEdit, SIGNAL(copyAvailable(bool)), CopyAction,SLOT(setEnabled(bool)) ); + connect( HexEdit, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()) ); + CopyAction->setEnabled( false ); + } + + // plugin to browsers + if( BrowserViewWanted ) + new KHexEditBrowserExtension( this ); +} + + +KHexEditPart::~KHexEditPart() +{ +} + +/* +void KHexEditPart::setupTools( bool BrowserViewWanted ) +{ + if( !BrowserViewWanted ) new KClipboardTool( this ); + + new KZoomToolet( this ); + new KSelectToolet( this ); + new KHEValueCodingToolet( this ); + new KHECharEncodingToolet( this ); + new KHEResizeStyleToolet( this ); + new KHEColumnToggleToolet( this ); +} +*/ +void KHexEditPart::setupActions( bool BrowserViewWanted ) +{ + KActionCollection *AC = actionCollection(); + // create our actions + CopyAction = BrowserViewWanted ? 0 : KStdAction::copy( HexEdit, SLOT(copy()), AC ); + + KStdAction::selectAll( this, SLOT(slotSelectAll()), AC ); + KStdAction::deselect( this, SLOT(slotUnselect()), AC ); + + // value encoding + CodingAction = new KSelectAction( i18n("&Value Coding"), 0, AC, "view_valuecoding" ); + QStringList List; + List.append( i18n("&Hexadecimal") ); + List.append( i18n("&Decimal") ); + List.append( i18n("&Octal") ); + List.append( i18n("&Binary") ); + CodingAction->setItems( List ); + connect( CodingAction, SIGNAL(activated(int)), this, SLOT(slotSetCoding(int)) ); + + // document encoding + EncodingAction = new KSelectAction( i18n("&Char Encoding"), 0, AC, "view_charencoding" ); + EncodingAction->setItems( KCharCodec::codecNames() ); + connect( EncodingAction, SIGNAL(activated(int)), this, SLOT(slotSetEncoding(int)) ); + + ShowUnprintableAction = new KToggleAction( i18n("Show &Unprintable Chars (<32)"), 0, this, SLOT(slotSetShowUnprintable()), actionCollection(), "view_showunprintable" ); + + KStdAction::zoomIn( HexEdit, SLOT(zoomIn()), actionCollection() ); + KStdAction::zoomOut( HexEdit, SLOT(zoomOut()), actionCollection() ); + + // resize style + ResizeStyleAction = new KSelectAction( i18n("&Resize Style"), 0, AC, "resizestyle" ); + List.clear(); + List.append( i18n("&No Resize") ); + List.append( i18n("&Lock Groups") ); + List.append( i18n("&Full Size Usage") ); + ResizeStyleAction->setItems( List ); + connect( ResizeStyleAction, SIGNAL(activated(int)), this, SLOT(slotSetResizeStyle(int)) ); + + ShowOffsetColumnAction = new KToggleAction( i18n("&Line Offset"), Key_F11, this, SLOT(slotToggleOffsetColumn()), AC, "view_lineoffset" ); + + // show buffer columns + ToggleColumnsAction = new KSelectAction( i18n("&Columns"), 0, AC, "togglecolumns" ); + List.clear(); + List.append( i18n("&Values Column") ); + List.append( i18n("&Chars Column") ); + List.append( i18n("&Both Columns") ); + ToggleColumnsAction->setItems( List ); + connect( ToggleColumnsAction, SIGNAL(activated(int)), this, SLOT(slotToggleValueCharColumns(int)) ); + + fitActionSettings(); + + // set our XML-UI resource file + setXMLFile( RCFileName ); +} + + +void KHexEditPart::fitActionSettings() +{ + ShowOffsetColumnAction->setChecked( HexEdit->offsetColumnVisible() ); + ShowUnprintableAction->setChecked( HexEdit->showUnprintable() ); + + CodingAction->setCurrentItem( (int)HexEdit->coding() ); + EncodingAction->setCurrentItem( KCharCodec::codecNames().findIndex(HexEdit->encodingName()) ); + + ResizeStyleAction->setCurrentItem( (int)HexEdit->resizeStyle() ); + + ToggleColumnsAction->setCurrentItem( (int)HexEdit->visibleBufferColumns()-1 ); +} + + +bool KHexEditPart::openFile() +{ + Wrapping.open( m_file ); + HexEdit->setDataBuffer( &Wrapping ); + HexEdit->setCursorPosition( 0 ); + HexEdit->selectAll( false ); + + return true; +} + + + +void KHexEditPart::slotSelectionChanged() +{ + bool State = HexEdit->hasSelectedData(); + CopyAction->setEnabled( State ); +} + + +void KHexEditPart::slotSelectAll() +{ + HexEdit->selectAll( true ); +} + + +void KHexEditPart::slotUnselect() +{ + HexEdit->selectAll( false ); +} + + +void KHexEditPart::slotSetCoding( int Coding ) +{ + HexEdit->setCoding( (KHexEdit::KCoding)Coding ); +} + +void KHexEditPart::slotSetShowUnprintable() +{ + HexEdit->setShowUnprintable( ShowUnprintableAction->isChecked() ); +} + +void KHexEditPart::slotToggleOffsetColumn() +{ + HexEdit->toggleOffsetColumn( ShowOffsetColumnAction->isChecked() ); +} + +void KHexEditPart::slotSetResizeStyle( int ResizeStyle ) +{ + HexEdit->setResizeStyle( (KHexEdit::KResizeStyle)ResizeStyle ); +} + +void KHexEditPart::slotSetEncoding( int Encoding ) +{ + HexEdit->setEncoding( KCharCodec::codecNames()[Encoding] ); +} + +void KHexEditPart::slotToggleValueCharColumns( int VisibleColumns) +{ + HexEdit->showBufferColumns( VisibleColumns+1 ); +} + +#include "khepart.moc" diff --git a/khexedit/parts/kpart/khepart.h b/khexedit/parts/kpart/khepart.h new file mode 100644 index 0000000..54befa0 --- /dev/null +++ b/khexedit/parts/kpart/khepart.h @@ -0,0 +1,95 @@ +/*************************************************************************** + khepart.h - description + ------------------- + begin : Don Jun 19 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHEPART_H +#define KHEPART_H + +// kde specific +#include <kparts/part.h> +// app specific +#include "kbigbuffer.h" + +// forward declarations +class KRadioAction; +class KToggleAction; +class KSelectAction; + +namespace KHE +{ + +// forward declarations +class KHexEdit; + +/** + * This is a "Part". It that does all the real work in a KPart + * application. + * + * @short Main Part + * @author Friedrich W. H. Kossebau <Friedrich.W.H@Kossebau.de> + * @version 0.1.0 + */ +class KHexEditPart : public KParts::ReadOnlyPart +{ + Q_OBJECT + + friend class KHexEditBrowserExtension; + + public: + KHexEditPart( QWidget *ParentWidget, const char *WidgetName, QObject *Parent, const char *Name, + bool BrowserViewWanted ); + virtual ~KHexEditPart(); + + + protected: // KParts::ReadOnlyPart API + virtual bool openFile(); + + protected: + void setupActions( bool BrowserViewWanted ); + void fitActionSettings(); + + protected slots: + // used to catch changes in the HexEdit widget + void slotSelectionChanged(); + protected slots: // action slots + void slotSelectAll(); + void slotUnselect(); + void slotSetCoding( int Coding ); + void slotSetEncoding( int Encoding ); + void slotSetShowUnprintable(); + void slotSetResizeStyle( int Style ); + void slotToggleOffsetColumn(); + void slotToggleValueCharColumns( int VisibleColunms ); + + private: + KHexEdit *HexEdit; + KBigBuffer Wrapping; + + // edit menu + KAction *CopyAction; + // view menu + KSelectAction *CodingAction; + KSelectAction *EncodingAction; + KToggleAction *ShowUnprintableAction; + // settings menu + KSelectAction *ResizeStyleAction; + KToggleAction *ShowOffsetColumnAction; + KSelectAction *ToggleColumnsAction; +}; + +} + +#endif diff --git a/khexedit/parts/kpart/khepartfactory.cpp b/khexedit/parts/kpart/khepartfactory.cpp new file mode 100644 index 0000000..f85d8a9 --- /dev/null +++ b/khexedit/parts/kpart/khepartfactory.cpp @@ -0,0 +1,90 @@ +/*************************************************************************** + khepartfactory.h - description + ------------------- + begin : Don Jun 19 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +// kde specific +#include <kinstance.h> +#include <kaboutdata.h> +#include <klocale.h> +// app specific +#include "khepart.h" +#include "khepartfactory.h" + +using namespace KHE; + +// Part +static const char PartId[] = "khexedit2part"; +static const char PartName[] = I18N_NOOP("KHexEdit2Part"); +static const char PartDescription[] = I18N_NOOP("Embedded hex editor"); +static const char PartVersion[] = "0.2.0"; +static const char PartCopyright[] = "(C) 2003-2004 Friedrich W. H. Kossebau"; +// Author +static const char FWHKName[] = "Friedrich W. H. Kossebau"; +static const char FWHKTask[] = I18N_NOOP("Author"); +static const char FWHKEmailAddress[] = "Friedrich.W.H@Kossebau.de"; +// static const char FWHKWebAddress[] = "http://www.kossebau.de"; + + +KInstance* KHexEditPartFactory::s_instance = 0L; +KAboutData* KHexEditPartFactory::s_about = 0L; + + +KHexEditPartFactory::KHexEditPartFactory() + : KParts::Factory() +{ +} + + +KHexEditPartFactory::~KHexEditPartFactory() +{ + delete s_instance; + delete s_about; + + s_instance = 0; +} + + +KParts::Part* KHexEditPartFactory::createPartObject( QWidget *ParentWidget, const char *WidgetName, + QObject *Parent, const char *Name, + const char *CN, const QStringList &/*args*/ ) +{ + QCString Classname( CN ); + bool BrowserViewWanted = ( Classname == "Browser/View" ); + //bool ReadOnlyWanted = (BrowserViewWanted || ( Classname == "KParts::ReadOnlyPart" )); + + // Create an instance of our Part + KHexEditPart* HexEditPart = new KHexEditPart( ParentWidget, WidgetName, Parent, Name, BrowserViewWanted ); + + return HexEditPart; +} + + +KInstance* KHexEditPartFactory::instance() +{ + if( !s_instance ) + { + s_about = new KAboutData( PartId, PartName, PartVersion, PartDescription, + KAboutData::License_GPL_V2, PartCopyright, 0, 0, FWHKEmailAddress ); + s_about->addAuthor( FWHKName, FWHKTask, FWHKEmailAddress ); + s_instance = new KInstance( s_about ); + } + return s_instance; +} + + +K_EXPORT_COMPONENT_FACTORY( libkhexedit2part, KHexEditPartFactory ) + +#include "khepartfactory.moc" diff --git a/khexedit/parts/kpart/khepartfactory.h b/khexedit/parts/kpart/khepartfactory.h new file mode 100644 index 0000000..7cd6c7e --- /dev/null +++ b/khexedit/parts/kpart/khepartfactory.h @@ -0,0 +1,47 @@ +/*************************************************************************** + khepartfactory.h - description + ------------------- + begin : Don Jun 19 2003 + copyright : (C) 2003 by Friedrich W. H. Kossebau + email : Friedrich.W.H@Kossebau.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License version 2 as published by the Free Software Foundation. * + * * + ***************************************************************************/ + + +#ifndef KHEPARTFACTORY_H +#define KHEPARTFACTORY_H + +#include <kparts/factory.h> + +class KInstance; +class KAboutData; + + +class KHexEditPartFactory : public KParts::Factory +{ + Q_OBJECT + + public: + KHexEditPartFactory(); + virtual ~KHexEditPartFactory(); + + public: + virtual KParts::Part* createPartObject( QWidget *parentWidget, const char *widgetName, + QObject *parent, const char *name, + const char *classname, const QStringList &args ); + static KInstance* instance(); + + + private: + static KInstance* s_instance; + static KAboutData* s_about; +}; + +#endif diff --git a/khexedit/parts/kpart/khexedit2part.desktop b/khexedit/parts/kpart/khexedit2part.desktop new file mode 100644 index 0000000..60f4132 --- /dev/null +++ b/khexedit/parts/kpart/khexedit2part.desktop @@ -0,0 +1,101 @@ +[Desktop Entry] +Type=Service +Icon=khexedit +Name=Embedded Binary Viewer +Name[ar]=عارض ثنائى مدمج +Name[bg]=Вграден двоичен преглед +Name[br]=Gweler HTML enframmus +Name[bs]=UgraÄ‘eni preglednik binarnih datoteka +Name[ca]=Visor binari encastat +Name[cs]=Zabudovaný binárnà prohlÞeÄ +Name[da]=Indlejret binær fremviser +Name[de]=Eingebettetes Anzeigeprogramm für Binärdateien +Name[el]=ΕνσωματωμÎνος Ï€ÏοβολÎας δυαδικών αÏχείων +Name[eo]=Enkonstruita duum-rigardilo +Name[es]=Visor binario empotrado +Name[et]=Põimitud binaarfailide näitaja +Name[eu]=Ikusgailu binario txertagarria +Name[fa]=مشاهده‌گر دوگانی نهÙته +Name[fi]=Sulautettu binääritiedostojen näytin +Name[fr]=Afficheur de binaires intégré +Name[ga]=Amharcán Leabaithe Dénártha +Name[he]=עורך הקס×דצימלי משובץ +Name[hu]=Beágyazott nézegetÅ‘ bináris fájlokhoz +Name[is]=Innbyggður tvÃundakerfisskoðari +Name[it]=Visore binario integrabile +Name[ja]=埋ã‚è¾¼ã¿ãƒã‚¤ãƒŠãƒªãƒ“ューア +Name[kk]=Ендірілетін бинарлық қарау құралы +Name[km]=កម្មវិធី​មើល​គោលពីរ​ដែល​បាន​បង្កប់ +Name[lt]=Ä®dedama dvejetainių duomenų žiÅ«ryklÄ— +Name[nb]=Innebygget Binærfremviser +Name[nds]=Inbett Bineerdaten-Kieker +Name[ne]=समà¥à¤®à¤¿à¤²à¤¿à¤¤ बाइनरी दरà¥à¤¶à¤• +Name[nl]=Ingebedde binaire viewer +Name[nn]=Innebygd binærframvisar +Name[pa]=ਸ਼ਾਮਲ ਬਾਈਨਰੀ ਦਰਸ਼ਕ +Name[pl]=Wbudowana przeglÄ…darka binarna +Name[pt]=Visualizador Binário Incorporado +Name[pt_BR]=Visualizador Binário Embutido +Name[ru]=Компонент проÑмотра двоичных данных +Name[sk]=Vložený binárny prezeraÄ +Name[sl]=Vgrajen binarni pregledovalnik +Name[sr]=Уградиви приказивач бинарног +Name[sr@Latn]=Ugradivi prikazivaÄ binarnog +Name[sv]=Inbäddad binärvisning +Name[ta]=உடà¯à®ªà¯Šà®¤à®¿à®¨à¯à®¤ இரà¯à®¨à®¿à®²à¯ˆ காடà¯à®šà®¿à®¯à®¾à®³à®©à¯ +Name[tr]=Gömülü Ä°kili dosya Görüntüleyici +Name[uk]=Вбудований переглÑдач Ð´Ð»Ñ Ð´Ð²Ñ–Ð¹ÐºÐ¾Ð²Ð¸Ñ… даних +Name[zh_CN]=嵌入å¼äºŒè¿›åˆ¶æŸ¥çœ‹å™¨ +Name[zh_TW]=嵌入å¼äºŒé€²ä½é¡¯ç¤ºå™¨ +Comment=Embedded Binary Viewer +Comment[ar]=عارض ثنائى مدمج +Comment[bg]=Вградена програма за преглед на двоични файлове +Comment[br]=Gweler HTML enframmus +Comment[bs]=UgraÄ‘eni preglednik binarnih datoteka +Comment[ca]=Visor binari encastat +Comment[cs]=Zabudovaný binárnà prohlÞeÄ +Comment[da]=Indlejret binær fremviser +Comment[de]=Eingebettetes Anzeigeprogramm für Binärdateien +Comment[el]=ΕνσωματωμÎνος Ï€ÏοβολÎας δυαδικών αÏχείων +Comment[eo]=Enkonstruita duum-rigardilo +Comment[es]=Visor binario empotrado +Comment[et]=Põimitud binaarfailide näitaja +Comment[eu]=Ikusgailu binario txertagarria +Comment[fa]=مشاهده‌گر دوگانی نهÙته +Comment[fi]=Sulautettu binääritiedostojen näytin +Comment[fr]=Afficheur de binaires intégré +Comment[ga]=Amharcán Leabaithe Dénártha +Comment[he]=עורך הקס×דצימלי משובץ +Comment[hu]=Beágyazott fájlmegjelenÃtÅ‘ bináris fájlokhoz +Comment[is]=Innbyggður tvÃundakerfisskoðari +Comment[it]=Visore binario integrabile +Comment[ja]=埋ã‚è¾¼ã¿ãƒã‚¤ãƒŠãƒªãƒ“ューア +Comment[ka]=ჩáƒáƒ¨áƒ”ნებული ბინáƒáƒ ული დáƒáƒ›áƒ—ვáƒáƒšáƒ˜áƒ”რებელი +Comment[kk]=Ендірілетін бинарлық қарау құралы +Comment[km]=កម្មវិធី​មើល​គោលពីរ​ដែល​បាន​បង្កប់ +Comment[lt]=Ä®dedama dvejetainių duomenų žiÅ«ryklÄ— +Comment[nb]=Innebygget Binærfremviser +Comment[nds]=Inbett Bineerdaten-Kieker +Comment[ne]=समà¥à¤®à¤¿à¤²à¤¿à¤¤ बाइनरी दरà¥à¤¶à¤• +Comment[nl]=Ingebedde binaire viewer +Comment[nn]=Innebygd binærframvisar +Comment[pa]=ਸ਼ਾਮਲ ਬਾਈਨਰੀ ਦਰਸ਼ਕ +Comment[pl]=Wbudowana przeglÄ…darka binarna +Comment[pt]=Visualizador Binário Incorporado +Comment[pt_BR]=Visualizador Binário Embutido +Comment[ru]=Компонент проÑмотра двоичных данных +Comment[sk]=Vložený binárny prezeraÄ +Comment[sl]=Vgrajen binarni pregledovalnik +Comment[sr]=Уградиви приказивач бинарног +Comment[sr@Latn]=Ugradivi prikazivaÄ binarnog +Comment[sv]=Inbäddad binärvisning +Comment[ta]=உடà¯à®ªà¯Šà®¤à®¿à®¨à¯à®¤ இரà¯à®¨à®¿à®²à¯ˆ காடà¯à®šà®¿à®¯à®¾à®³à®©à¯ +Comment[tr]=Gömülü Ä°kili dosya Görüntüleyici +Comment[uk]=Вбудований переглÑдач Ð´Ð»Ñ Ð´Ð²Ñ–Ð¹ÐºÐ¾Ð²Ð¸Ñ… даних +Comment[zh_CN]=嵌入å¼äºŒè¿›åˆ¶æŸ¥çœ‹å™¨ +Comment[zh_TW]=嵌入å¼äºŒé€²ä½é¡¯ç¤ºå™¨ +#MimeType=all/allfiles +MimeType=application/octet-stream +ServiceTypes=KParts/ReadOnlyPart,Browser/View +#,KParts/ReadWritePart +X-KDE-Library=libkhexedit2part diff --git a/khexedit/parts/kpart/khexedit2partui.rc b/khexedit/parts/kpart/khexedit2partui.rc new file mode 100644 index 0000000..82b40eb --- /dev/null +++ b/khexedit/parts/kpart/khexedit2partui.rc @@ -0,0 +1,42 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="khexedit2part" version="1"> +<MenuBar> + <Menu name="edit"><text>&Edit</text> + <Action name="edit_copy" group="edit_paste_merge" /> + <Action name="edit_select_all" group="edit_select_merge" /> + <Action name="edit_deselect" group="edit_select_merge" /> + </Menu> + <Menu name="view"><text>&View</text> + <Separator/> + <Action name="view_zoom_in" /> + <Action name="view_zoom_out" /> + <Separator/> + <Action name="view_showunprintable" /> + <Action name="view_lineoffset" /> + <Separator/> + <Action name="view_valuecoding" /> + <Action name="view_charencoding" /> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Separator/> + <Action name="resizestyle" group="show_merge" /> + <Action name="togglecolumns" group="show_merge" /> + </Menu> +</MenuBar> + +<ToolBar name="mainToolBar"><text>Main Toolbar</text> + <Action name="edit_copy" /> + <Action name="view_zoom_in" /> + <Action name="view_zoom_out" /> +</ToolBar> + +<!-- Editor popup menu //--> +<Menu name="editor_popup"> + <Action name="view_hexcoding" /> + <Action name="view_deccoding" /> + <Action name="view_octcoding" /> + <Action name="view_bincoding" /> + <Separator/> + <Action name="resize_lock" /> +</Menu> +</kpartgui> diff --git a/khexedit/pics/Makefile.am b/khexedit/pics/Makefile.am new file mode 100644 index 0000000..0dd7a3f --- /dev/null +++ b/khexedit/pics/Makefile.am @@ -0,0 +1,3 @@ +toolbar_DATA = hexwrite.png hexdrag.png hexmask.png +toolbardir = $(kde_datadir)/khexedit/pics + diff --git a/khexedit/pics/hexdrag.png b/khexedit/pics/hexdrag.png Binary files differnew file mode 100644 index 0000000..1459f4f --- /dev/null +++ b/khexedit/pics/hexdrag.png diff --git a/khexedit/pics/hexmask.png b/khexedit/pics/hexmask.png Binary files differnew file mode 100644 index 0000000..69e71e5 --- /dev/null +++ b/khexedit/pics/hexmask.png diff --git a/khexedit/pics/hexwrite.png b/khexedit/pics/hexwrite.png Binary files differnew file mode 100644 index 0000000..a408a03 --- /dev/null +++ b/khexedit/pics/hexwrite.png diff --git a/khexedit/printdialogpage.cc b/khexedit/printdialogpage.cc new file mode 100644 index 0000000..ecc0a90 --- /dev/null +++ b/khexedit/printdialogpage.cc @@ -0,0 +1,386 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <qlayout.h> +#include <qbuttongroup.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qcheckbox.h> +#include <qstringlist.h> +#include <qcombobox.h> + +#include <klocale.h> + + +#include "printdialogpage.h" + +LayoutDialogPage::LayoutDialogPage( QWidget *parent, const char *name ) + : KPrintDialogPage( parent, name ) +{ + mConfig = 0; + setTitle( i18n( "Page Layout" ) ); + setupLayoutPage(); + + readConfiguration(); +} + + +LayoutDialogPage::~LayoutDialogPage( void ) +{ + writeConfiguration(); + + delete mConfig; mConfig = 0; +} + + +void LayoutDialogPage::setupLayoutPage( void ) +{ + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( this, 0, 6 /*KDialog::mSpacingSize*/ ); + if( topLayout == 0 ) { return; } + + text = i18n("Margins [millimeter]"); + QButtonGroup *group = new QButtonGroup( text, this ); + if( group == 0 ) { return; } + topLayout->addWidget( group ); + + QGridLayout *gbox = new QGridLayout( group, 3, 6, 6 /*KDialog::mSpacingSize*/ ); + if( gbox == 0 ) { return; } + gbox->addRowSpacing( 0, group->fontMetrics().height() ); + gbox->setColStretch( 5, 10 ); + + QString name[4]; + int i; + + name[0] = i18n("&Top:"); + name[1] = i18n("&Bottom:"); + name[2] = i18n("&Left:"); + name[3] = i18n("&Right:"); + + for( i=0; i<4; i++ ) + { + mLayout.marginSpin[i] = new QSpinBox( group ); + mLayout.marginSpin[i]->setFixedHeight( + mLayout.marginSpin[i]->sizeHint().height() ); + mLayout.marginSpin[i]->setMinimumWidth( + mLayout.marginSpin[i]->fontMetrics().width("M")*10 ); + mLayout.marginSpin[i]->setRange( 0, INT_MAX ); + + QLabel *label = new QLabel( mLayout.marginSpin[i], name[i], group ); + label->setFixedHeight( mLayout.marginSpin[i]->sizeHint().height() ); + label->setFixedWidth( label->sizeHint().width() ); + + if( i < 2 ) + { + gbox->addWidget( label, i+1, 0, AlignLeft ); + gbox->addWidget( mLayout.marginSpin[i], i+1, 1, AlignLeft ); + } + else + { + gbox->addWidget( label, i-1, 3, AlignLeft ); + gbox->addWidget( mLayout.marginSpin[i], i-1, 4, AlignLeft ); + } + } + + text = i18n("Draw h&eader above text"); + mLayout.headerCheck = new QCheckBox( text, this ); + mLayout.headerCheck->setFixedSize( mLayout.headerCheck->sizeHint() ); + connect( mLayout.headerCheck, SIGNAL( toggled(bool)), + SLOT( slotDrawHeader(bool))); + topLayout->addWidget( mLayout.headerCheck, 0, AlignLeft ); + + gbox = new QGridLayout( 5, 6, 0 ); + if( gbox == 0 ) { return; } + topLayout->addLayout( gbox ); + + gbox->setColStretch ( 5, 10 ); + gbox->addColSpacing( 1, 6 /*KDialog::mSpacingSize*/ ); + gbox->addColSpacing( 3, 6 /*KDialog::mSpacingSize*/ ); + gbox->addRowSpacing( 2, 6 /*KDialog::mSpacingSize*/ ); + + name[0] = i18n("Left:"); + name[1] = i18n("Center:"); + name[2] = i18n("Right:"); + name[3] = i18n("Border:"); + + QStringList textList; + textList.append(i18n("None")); + textList.append(i18n("Date & Time")); + textList.append(i18n("Page Number")); + textList.append(i18n("Filename")); + + QStringList lineList; + lineList.append(i18n("None")); + lineList.append(i18n("Single Line")); + lineList.append(i18n("Rectangle")); + + for( i=0; i<4; i++ ) + { + mLayout.headerCombo[i] = new QComboBox( false, this ); + mLayout.headerCombo[i]->setFixedHeight( + mLayout.headerCombo[i]->sizeHint().height() ); + mLayout.headerCombo[i]->setMinimumWidth( + mLayout.headerCombo[i]->fontMetrics().width("M")*10 ); + + mLayout.headerLabel[i] = new QLabel( mLayout.headerCombo[i], name[i], + this ); + mLayout.headerLabel[i]->setFixedHeight( + mLayout.headerLabel[i]->sizeHint().height() ); + mLayout.headerLabel[i]->setFixedWidth( + mLayout.headerLabel[i]->sizeHint().width() ); + + if( i<3 ) + { + mLayout.headerCombo[i]->insertStringList( textList ); + gbox->addWidget( mLayout.headerLabel[i], 0, i*2, AlignLeft ); + gbox->addWidget( mLayout.headerCombo[i], 1, i*2, AlignLeft ); + } + else + { + mLayout.headerCombo[i]->insertStringList( lineList ); + gbox->addWidget( mLayout.headerLabel[i], 3, 0, AlignLeft ); + gbox->addWidget( mLayout.headerCombo[i], 4, 0, AlignLeft ); + } + } + + + text = i18n("Draw &footer below text"); + mLayout.footerCheck = new QCheckBox( text, this ); + mLayout.footerCheck->setFixedSize( mLayout.footerCheck->sizeHint() ); + connect( mLayout.footerCheck, SIGNAL( toggled(bool)), + SLOT( slotDrawFooter(bool))); + topLayout->addWidget( mLayout.footerCheck, 0, AlignLeft ); + + gbox = new QGridLayout( 5, 6, 0 ); + if( gbox == 0 ) { return; } + topLayout->addLayout( gbox ); + + gbox->setColStretch ( 5, 10 ); + gbox->addColSpacing( 1, 6 /*KDialog::mSpacingSize*/ ); + gbox->addColSpacing( 3, 6 /*KDialog::mSpacingSize*/ ); + gbox->addRowSpacing( 2, 6 /*KDialog::mSpacingSize*/ ); + + for( i=0; i<4; i++ ) + { + mLayout.footerCombo[i] = new QComboBox( false, this ); + mLayout.footerCombo[i]->setFixedHeight( + mLayout.footerCombo[i]->sizeHint().height() ); + mLayout.footerCombo[i]->setMinimumWidth( + mLayout.footerCombo[i]->fontMetrics().width("M")*10 ); + + mLayout.footerLabel[i] = new QLabel( mLayout.footerCombo[i], name[i], + this ); + mLayout.footerLabel[i]->setFixedHeight( + mLayout.footerLabel[i]->sizeHint().height() ); + mLayout.footerLabel[i]->setFixedWidth( + mLayout.footerLabel[i]->sizeHint().width() ); + + if( i<3 ) + { + mLayout.footerCombo[i]->insertStringList( textList ); + gbox->addWidget( mLayout.footerLabel[i], 0, i*2, AlignLeft ); + gbox->addWidget( mLayout.footerCombo[i], 1, i*2, AlignLeft ); + } + else + { + mLayout.footerCombo[i]->insertStringList( lineList ); + gbox->addWidget( mLayout.footerLabel[i], 3, 0, AlignLeft ); + gbox->addWidget( mLayout.footerCombo[i], 4, 0, AlignLeft ); + } + } + + for( i=0; i<4; i++ ) + { + mLayout.marginSpin[i]->setValue( 15 ); + } + mLayout.headerCheck->setChecked( true ); + slotDrawHeader( true ); + mLayout.footerCheck->setChecked( true ); + slotDrawFooter( true ); + + topLayout->addStretch(10); +} + + +void LayoutDialogPage::readConfiguration( void ) +{ + if( mConfig != 0 ) { return; } + + mConfig = new KSimpleConfig( QString("hexprinter") ); + if( mConfig == 0 ) { return; } + + mConfig->setGroup( "PageLayout" ); + int val = mConfig->readNumEntry( "MarginTop", 15 ); + mLayout.marginSpin[0]->setValue( val ); + val = mConfig->readNumEntry( "MarginBottom", 15 ); + mLayout.marginSpin[1]->setValue( val ); + val = mConfig->readNumEntry( "MarginLeft", 15 ); + mLayout.marginSpin[2]->setValue( val ); + val = mConfig->readNumEntry( "MarginRight", 15 ); + mLayout.marginSpin[3]->setValue( val ); + bool state = mConfig->readBoolEntry( "DrawHeader", true ); + mLayout.headerCheck->setChecked( state ); + slotDrawHeader( state ); + state = mConfig->readBoolEntry( "DrawFooter", true ); + mLayout.footerCheck->setChecked( state ); + slotDrawFooter( state ); + + mLayout.headerCombo[0]->setCurrentItem( + headerTextIndex( mConfig->readEntry("HeaderLeft","DateTime"))); + mLayout.headerCombo[1]->setCurrentItem( + headerTextIndex( mConfig->readEntry("HeaderCenter"))); + mLayout.headerCombo[2]->setCurrentItem( + headerTextIndex( mConfig->readEntry("HeaderRight","FileName"))); + mLayout.headerCombo[3]->setCurrentItem( + headerLineIndex( mConfig->readEntry("HeaderLine","SingleLine"))); + + mLayout.footerCombo[0]->setCurrentItem( + headerTextIndex( mConfig->readEntry("FooterLeft"))); + mLayout.footerCombo[1]->setCurrentItem( + headerTextIndex( mConfig->readEntry("FooterCenter","PageNumber"))); + mLayout.footerCombo[2]->setCurrentItem( + headerTextIndex( mConfig->readEntry("FooterRight"))); + mLayout.footerCombo[3]->setCurrentItem( + headerLineIndex( mConfig->readEntry("FooterLine","SingleLine"))); + +} + + +void LayoutDialogPage::writeConfiguration( void ) +{ + if( mConfig == 0 ) + { + return; + } + + mConfig->setGroup( "PageLayout" ); + mConfig->writeEntry( "MarginTop", mLayout.marginSpin[0]->value() ); + mConfig->writeEntry( "MarginBottom", mLayout.marginSpin[1]->value() ); + mConfig->writeEntry( "MarginLeft", mLayout.marginSpin[2]->value() ); + mConfig->writeEntry( "MarginRight", mLayout.marginSpin[3]->value() ); + mConfig->writeEntry( "DrawHeader", mLayout.headerCheck->isChecked() ); + mConfig->writeEntry( "DrawFooter", mLayout.footerCheck->isChecked() ); + + mConfig->writeEntry( "HeaderLeft", + headerText( mLayout.headerCombo[0]->currentItem() ) ); + mConfig->writeEntry( "HeaderCenter", + headerText( mLayout.headerCombo[1]->currentItem() ) ); + mConfig->writeEntry( "HeaderRight", + headerText( mLayout.headerCombo[2]->currentItem() ) ); + mConfig->writeEntry( "HeaderLine", + headerLine( mLayout.headerCombo[3]->currentItem() ) ); + + mConfig->writeEntry( "FooterLeft", + headerText( mLayout.footerCombo[0]->currentItem() ) ); + mConfig->writeEntry( "FooterCenter", + headerText( mLayout.footerCombo[1]->currentItem() ) ); + mConfig->writeEntry( "FooterRight", + headerText( mLayout.footerCombo[2]->currentItem() ) ); + mConfig->writeEntry( "FooterLine", + headerLine( mLayout.footerCombo[3]->currentItem() ) ); + + mConfig->sync(); +} + + +QString LayoutDialogPage::headerText( uint index ) +{ + static const QString text[4] = {"None","DateTime","PageNumber","FileName"}; + return( text[ index > 3 ? 0 : index ] ); +} + + +int LayoutDialogPage::headerTextIndex( const QString & headerText ) +{ + static const QString text[4] = {"None","DateTime","PageNumber","FileName"}; + if( headerText != 0 ) + { + for( int i=0; i<4; i++ ) + { + if( headerText == text[i] ) { return( i ); } + } + } + return( 0 ); +} + + +QString LayoutDialogPage::headerLine( uint index ) +{ + static const QString text[3] = {"None","SingleLine","Rectangle"}; + return( text[ index > 2 ? 0 : index ] ); +} + + +int LayoutDialogPage::headerLineIndex( const QString & headerLine ) +{ + static const QString text[3] = {"None","SingleLine","Rectangle"}; + if( headerLine != 0 ) + { + for( int i=0; i<3; i++ ) + { + if( headerLine == text[i] ) { return( i ); } + } + } + return( 0 ); +} + + +void LayoutDialogPage::slotDrawHeader( bool state ) +{ + for( int i=0; i<4; i++ ) + { + mLayout.headerLabel[i]->setEnabled( state ); + mLayout.headerCombo[i]->setEnabled( state ); + } +} + + +void LayoutDialogPage::slotDrawFooter( bool state ) +{ + for( int i=0; i<4; i++ ) + { + mLayout.footerLabel[i]->setEnabled( state ); + mLayout.footerCombo[i]->setEnabled( state ); + } +} + + +void LayoutDialogPage::getOptions( QMap<QString,QString>& opts, bool /*incldef*/ ) +{ + opts[ "kde-khexedit-topmarginmm" ] = QString::number( mLayout.marginSpin[0]->value() ); + opts[ "kde-khexedit-bottommarginmm" ] = QString::number( mLayout.marginSpin[1]->value() ); + opts[ "kde-khexedit-leftmarginmm" ] = QString::number( mLayout.marginSpin[2]->value() ); + opts[ "kde-khexedit-rightmarginmm" ] = QString::number( mLayout.marginSpin[3]->value() ); + + opts[ "kde-khexedit-headercheck" ] = (mLayout.headerCheck->isChecked() ? "true" : "false"); + opts[ "kde-khexedit-headercombo0" ] = QString::number( mLayout.headerCombo[0]->currentItem() ); + opts[ "kde-khexedit-headercombo1" ] = QString::number( mLayout.headerCombo[1]->currentItem() ); + opts[ "kde-khexedit-headercombo2" ] = QString::number( mLayout.headerCombo[2]->currentItem() ); + opts[ "kde-khexedit-headercombo3" ] = QString::number( mLayout.headerCombo[3]->currentItem() ); + + opts[ "kde-khexedit-footercheck" ] = (mLayout.footerCheck->isChecked() ? "true" : "false"); + opts[ "kde-khexedit-footercombo0" ] = QString::number( mLayout.footerCombo[0]->currentItem() ); + opts[ "kde-khexedit-footercombo1" ] = QString::number( mLayout.footerCombo[1]->currentItem() ); + opts[ "kde-khexedit-footercombo2" ] = QString::number( mLayout.footerCombo[2]->currentItem() ); + opts[ "kde-khexedit-footercombo3" ] = QString::number( mLayout.footerCombo[3]->currentItem() ); +} + + +#include "printdialogpage.moc" diff --git a/khexedit/printdialogpage.h b/khexedit/printdialogpage.h new file mode 100644 index 0000000..bdc58f6 --- /dev/null +++ b/khexedit/printdialogpage.h @@ -0,0 +1,73 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * This file is based on the work by F. Zigterman, fzr@dds.nl + * + * 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 _PRINT_DIALOG_PAGE_H_ +#define _PRINT_DIALOG_PAGE_H_ + +class QCheckBox; +class QComboBox; +class QLabel; +class QSpinBox; + +#include <kdeprint/kprintdialogpage.h> +#include <ksimpleconfig.h> + +class LayoutDialogPage : public KPrintDialogPage +{ + Q_OBJECT + + public: + LayoutDialogPage( QWidget *parent = 0, const char *name = 0 ); + ~LayoutDialogPage( void ); + + void getOptions( QMap<QString,QString>& opts, bool incldef = false ); + + private slots: + void slotDrawHeader( bool state ); + void slotDrawFooter( bool state ); + + private: + void setupLayoutPage( void ); + + void readConfiguration( void ); + void writeConfiguration( void ); + + QString headerText( uint index ); + QString headerLine( uint index ); + int headerTextIndex( const QString & headerText ); + int headerLineIndex( const QString & headerLine ); + + struct SLayoutWidgets + { + QSpinBox *marginSpin[4]; + QCheckBox *headerCheck; + QCheckBox *footerCheck; + QLabel *headerLabel[4]; + QComboBox *headerCombo[4]; + QLabel *footerLabel[4]; + QComboBox *footerCombo[4]; + }; + + KSimpleConfig *mConfig; + SLayoutWidgets mLayout; +}; + +#endif diff --git a/khexedit/progress.h b/khexedit/progress.h new file mode 100644 index 0000000..fa6e8a3 --- /dev/null +++ b/khexedit/progress.h @@ -0,0 +1,130 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * This file is based on the work by F. Zigterman, fzr@dds.nl + * + * 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 _PROGRESS_H_ +#define _PROGRESS_H_ + +#include <qdatetime.h> +#include "hexerror.h" + + +struct SProgressData +{ + SProgressData( float f ) + { + useFraction = 1; + fraction = f; + } + + SProgressData( int cPage, int mPage ) + { + useFraction = 0; + curPage = cPage; + maxPage = mPage; + } + + int valid( void ) const + { + return( (useFraction == 1 && fraction >= 0) || + (useFraction == 0 && curPage >= 0) ? 1 : 0 ); + } + + int useFraction; + float fraction; + int curPage; + int maxPage; +}; + + + +typedef int (*ProgressFunc)( void *clientData, SProgressData &pd ); + +class CProgress +{ + public: + CProgress( void ) + { + define( 0, 0 ); + mInterruptTimer.start(); + } + + CProgress( ProgressFunc progressFunc, void *clientData ) + { + define( progressFunc, clientData ); + mInterruptTimer.start(); + } + + void define( ProgressFunc progressFunc, void *clientData ) + { + mProgressFunc = progressFunc; + mClientData = clientData; + } + + void finish( void ) const + { + if( mProgressFunc == 0 ) + { + return; + } + SProgressData pd( -1.0 ); + mProgressFunc( mClientData, pd ); + } + + bool expired( void ) + { + return( mInterruptTimer.elapsed() > 200 ); + } + + int step( float fraction ) + { + mInterruptTimer.start(); + + if( mProgressFunc == 0 ) + { + return( Err_Success ); + } + SProgressData pd( fraction ); + int errCode = mProgressFunc( mClientData, pd ); + return( errCode ); + } + + int step( int curPage, int maxPage ) + { + mInterruptTimer.start(); + + if( mProgressFunc == 0 ) + { + return( Err_Success ); + } + SProgressData pd( curPage, maxPage ); + int errCode = mProgressFunc( mClientData, pd ); + return( errCode ); + } + + private: + ProgressFunc mProgressFunc; + void *mClientData; + QTime mInterruptTimer; +}; + +#endif + + diff --git a/khexedit/searchbar.cc b/khexedit/searchbar.cc new file mode 100644 index 0000000..44d4944 --- /dev/null +++ b/khexedit/searchbar.cc @@ -0,0 +1,188 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 2000 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + + +#include <klocale.h> + +#include "dialog.h" +#include "hexvalidator.h" +#include "searchbar.h" +#include <qpushbutton.h> + +// crappy X11 headers +#undef KeyPress + +static const char * close_xpm[] = { +"16 16 3 1", +" s None c None", +". c #ffffff", +"X c #707070", +" ", +" ", +" .X .X ", +" .XX .XX ", +" .XX .XX ", +" .XX .XX ", +" .XX.XX ", +" .XXX ", +" .XXX ", +" .XX.XX ", +" .XX .XX ", +" .XX .XX ", +" .XX .XX ", +" .X .X ", +" ", +" "}; + +CSearchBar::CSearchBar( QWidget *parent, const char *name, WFlags f ) + :QFrame( parent, name, f ) +{ + setFrameStyle( QFrame::Panel | QFrame::Raised ); + setLineWidth( 1 ); + + mTypeCombo = new QComboBox( this ); + connect( mTypeCombo, SIGNAL(activated(int)), SLOT(selectorChanged(int)) ); + QStringList list; + list << i18n("Hex") << i18n("Dec") << i18n("Oct") << i18n("Bin") + << i18n("Txt"); + mTypeCombo->insertStringList( list ); + + mInputEdit = new QLineEdit( this ); + connect( mInputEdit, SIGNAL(textChanged(const QString&)), + SLOT(textChanged(const QString&)) ); + mValidator = new CHexValidator( this, CHexValidator::regularText ); + mInputEdit->setValidator( mValidator ); + + mFindButton = new QPushButton( i18n("Find"), this ); + mFindButton->setAutoDefault(false); + connect( mFindButton, SIGNAL(clicked()), this, SLOT(start()) ); + connect(mInputEdit,SIGNAL(returnPressed()),mFindButton,SLOT(animateClick())); + mFindButton->setFixedHeight( mTypeCombo->sizeHint().height() ); + + mBackwards = new QCheckBox( i18n("Backwards"), this ); + mIgnoreCase = new QCheckBox( i18n("Ignore case"), this ); + + mCloseButton = new QPushButton( this ); + mCloseButton->setAutoDefault(false); + mCloseButton->setPixmap( QPixmap( close_xpm ) ); + connect( mCloseButton, SIGNAL(clicked()), this, SLOT(hideWidget()) ); + + // + // Make layout + // + QHBoxLayout *hlay = new QHBoxLayout( this, 4, 6 ); + hlay->addWidget( mTypeCombo ); + hlay->addWidget( mInputEdit ); + hlay->addWidget( mFindButton ); + hlay->addWidget( mBackwards ); + hlay->addWidget( mIgnoreCase ); + hlay->addWidget( mCloseButton ); + + // + // Read below why I do this. + // + mInputEdit->installEventFilter( this ); + selectorChanged(0); +} + + +// +// Espen 2000-04-21 +// Qt 2.1: Seems like the QLineEdit::returnPressed() does not work when +// I install a validator. So I catch the event manually +// +bool CSearchBar::eventFilter( QObject *o, QEvent *e ) +{ + if( o == mInputEdit && e->type() == QEvent::KeyPress ) + { + QKeyEvent *ke = (QKeyEvent*)e; + if( ke->key() == Key_Return ) + { + mFindButton->animateClick(); + return true; + } + } + return QFrame::eventFilter( o, e ); +} + +// +// Seach for te first item each time the curso has moved. Note: The cursor +// will move when we search and get a match, but (in start() below) the +// mSearchMode is set to Find_Next after this slot has been called so it +// will work. +// +void CSearchBar::cursorMoved() +{ + mSearchMode = Find_First; +} + + +void CSearchBar::selectorChanged( int index ) +{ + mValidator->setState( (CHexValidator::EState)index ); + mInputEdit->setText( mFindString[ index ] ); + mIgnoreCase->setEnabled( index == 4 ? true : false ); + mSearchMode = Find_First; +} + + +void CSearchBar::textChanged( const QString &text ) +{ + mFindString[ mTypeCombo->currentItem() ] = text; + mValidator->convert( mFindData, mFindString[ mTypeCombo->currentItem() ] ); + mSearchMode = Find_First; +} + + +void CSearchBar::hideWidget() +{ + hide(); + emit hidden(); +} + + +void CSearchBar::start( void ) +{ + if( mFindData.isEmpty() == true ) + { + showEntryFailure( this, QString("") ); + return; + } + + SSearchControl sc; + sc.key = mFindData; + sc.keyType = mTypeCombo->currentItem(); + sc.fromCursor = true; + sc.inSelection = false; + sc.forward = !mBackwards->isChecked(); + sc.ignoreCase = mIgnoreCase->isEnabled() && mIgnoreCase->isChecked(); + emit findData( sc, mSearchMode, false ); + mSearchMode = Find_Next; +} + + +void CSearchBar::showEvent( QShowEvent *e ) +{ + QFrame::showEvent(e); + mInputEdit->setFocus(); +} + + +#include "searchbar.moc" diff --git a/khexedit/searchbar.h b/khexedit/searchbar.h new file mode 100644 index 0000000..c11f652 --- /dev/null +++ b/khexedit/searchbar.h @@ -0,0 +1,73 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 2000 Espen Sand, espensa@online.no + * + * 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 _SEARCHBAR_H_ +#define _SEARCHBAR_H_ + +#include <qframe.h> + +#include "hexbuffer.h" + +class QComboBox; +class QLineEdit; +class QPushButton; +class QCheckBox; +class CHexValidator; + +class CSearchBar : public QFrame +{ + Q_OBJECT + + public: + CSearchBar( QWidget *parent=0, const char *name=0, WFlags f=0 ); + virtual bool eventFilter( QObject *o, QEvent *e ); + + public slots: + void cursorMoved(); + + protected: + virtual void showEvent( QShowEvent * ); + + private slots: + void hideWidget(); + void selectorChanged( int index ); + void textChanged( const QString &text ); + void start(); + + signals: + void hidden(); + void findData( SSearchControl &sc, uint mode, bool navigator ); + + private: + QPushButton *mCloseButton; + QPushButton *mFindButton; + QComboBox *mTypeCombo; + QLineEdit *mInputEdit; + QCheckBox *mBackwards; + QCheckBox *mIgnoreCase; + + QString mFindString[5]; + QByteArray mFindData; + CHexValidator *mValidator; + uint mSearchMode; +}; + +#endif + + diff --git a/khexedit/statusbarprogress.cc b/khexedit/statusbarprogress.cc new file mode 100644 index 0000000..6e45cf2 --- /dev/null +++ b/khexedit/statusbarprogress.cc @@ -0,0 +1,374 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * This file is based on the work by Martynas Kunigelis (KProgress) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "statusbarprogress.h" + +#include <qpainter.h> + +#include <kapplication.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <qstyle.h> + +CStatusBarProgress::CStatusBarProgress( QWidget *parent, const char *name ) + : QFrame(parent, name), QRangeControl(0, 100, 1, 10, 0), + mOrientation( Horizontal ) +{ + initialize(); +} + +CStatusBarProgress::CStatusBarProgress( Orientation orientation, + QWidget *parent, const char *name ) + : QFrame(parent, name), QRangeControl(0, 100, 1, 10, 0), + mOrientation( orientation ) +{ + initialize(); +} + +CStatusBarProgress::CStatusBarProgress( int minValue, int maxValue, int value, + Orientation orientation, + QWidget *parent, const char *name ) + : QFrame(parent, name), QRangeControl(minValue, maxValue, 1, 10, value), + mOrientation(orientation) +{ + initialize(); +} + +CStatusBarProgress::~CStatusBarProgress() +{ + delete mBarPixmap; +} + +void CStatusBarProgress::advance( int offset ) +{ + setValue(value() + offset); +} + +void CStatusBarProgress::initialize( void ) +{ + mBarPixmap = 0; + mBarStyle = Solid; + + mBarColor = palette().active().highlight(); + mBarTextColor = palette().active().highlightedText(); + mTextColor = palette().active().text(); + setBackgroundColor( palette().active().background() ); + + QFont font( KGlobalSettings::generalFont() ); + font.setBold( true ); + setFont( font ); + + mTextEnabled = false; + adjustStyle(); +} + + +void CStatusBarProgress::setBarPixmap( const QPixmap &pixmap ) +{ + if( pixmap.isNull() == true ) + { + return; + } + + delete mBarPixmap; + mBarPixmap = new QPixmap( pixmap ); +} + +void CStatusBarProgress::setBarColor( const QColor &color ) +{ + mBarColor = color; + delete mBarPixmap; + mBarPixmap = 0; +} + +void CStatusBarProgress::setBarStyle( BarStyle style ) +{ + if( mBarStyle != style ) + { + mBarStyle = style; + update(); + } +} + +void CStatusBarProgress::setOrientation( Orientation orientation ) +{ + if( mOrientation != orientation ) + { + mOrientation = orientation; + update(); + } +} + +void CStatusBarProgress::setValue(int value) +{ + mCurPage = mMaxPage = -1; + QRangeControl::setValue(value); +} + +void CStatusBarProgress::setValue( int curPage, int maxPage ) +{ + if( curPage <= 0 || maxPage <= 0 || curPage > maxPage ) + { + mCurPage = mMaxPage = -1; + QRangeControl::setValue(0); + } + else + { + mCurPage = curPage; + mMaxPage = maxPage; + float fraction = (float)curPage/(float)maxPage; + QRangeControl::setValue( (int)(fraction*100.0) ); + } +} + + +void CStatusBarProgress::setTextEnabled( bool state ) +{ + if( mTextEnabled != state ) + { + mTextEnabled = state; + update(); + } +} + +void CStatusBarProgress::setText( const QString &msg ) +{ + mMsg = msg; + if( mTextEnabled == true ) + { + update(); + } +} + + + + +const QColor & CStatusBarProgress::barColor( void ) const +{ + return( mBarColor ); +} + +const QPixmap * CStatusBarProgress::barPixmap( void ) const +{ + return( mBarPixmap ); +} + +bool CStatusBarProgress::textEnabled( void ) const +{ + return( mTextEnabled ); +} + +QSize CStatusBarProgress::sizeHint( void ) const +{ + QSize s( size() ); + + if( orientation() == CStatusBarProgress::Vertical ) + { + s.setWidth( fontMetrics().lineSpacing() ); + } + else + { + s.setHeight( fontMetrics().lineSpacing() ); + } + + return( s ); +} + + +CStatusBarProgress::Orientation CStatusBarProgress::orientation( void ) const +{ + return( mOrientation ); +} + +CStatusBarProgress::BarStyle CStatusBarProgress::barStyle() const +{ + return( mBarStyle ); +} + +int CStatusBarProgress::recalcValue(int range) +{ + int abs_value = value() - minValue(); + int abs_range = maxValue() - minValue(); + return range * abs_value / abs_range; +} + +void CStatusBarProgress::valueChange() +{ + repaint(contentsRect(), FALSE); + emit percentageChanged(recalcValue(100)); +} + +void CStatusBarProgress::rangeChange() +{ + repaint(contentsRect(), FALSE); + emit percentageChanged(recalcValue(100)); +} + +void CStatusBarProgress::styleChange( GUIStyle ) +{ + adjustStyle(); +} + +void CStatusBarProgress::adjustStyle( void ) +{ + switch( style().SH_GUIStyle) + { + case WindowsStyle: + setFrameStyle( QFrame::NoFrame ); + break; + + case MotifStyle: + default: + setFrameStyle( QFrame::Panel|QFrame::Sunken ); + setLineWidth( 1 ); + break; + } + update(); +} + +void CStatusBarProgress::paletteChange( const QPalette & ) +{ + mBarColor = palette().active().highlight(); + mBarTextColor = palette().active().highlightedText(); + mTextColor = palette().active().text(); + setBackgroundColor( palette().active().background() ); +} + +void CStatusBarProgress::drawText( QPainter *p ) +{ + QRect r(contentsRect()); + QString s; + + if( mMsg.isEmpty() == true ) + { + s = QString("%1%").arg(recalcValue(100)); + } + else + { + if( mCurPage > 0 ) + { + s = i18n("%1... %2 of %3").arg(mMsg).arg(mCurPage).arg(mMaxPage); + } + else + { + s = i18n("%1... %2%").arg(mMsg).arg(recalcValue(100)); + } + } + + p->setPen( mTextColor ); + p->drawText( r, AlignCenter, s ); + p->setClipRegion( fr ); + p->setPen( mBarTextColor ); + p->drawText( r, AlignCenter, s ); +} + +void CStatusBarProgress::drawContents(QPainter *p) +{ + QRect cr = contentsRect(), er = cr; + fr = cr; + QBrush fb(mBarColor), eb(backgroundColor() ); + + if( mBarPixmap != 0 ) + { + fb.setPixmap( *mBarPixmap ); + } + + if (backgroundPixmap()) + eb.setPixmap(*backgroundPixmap()); + + switch( mBarStyle ) + { + case Solid: + if( mOrientation == Horizontal ) + { + fr.setWidth(recalcValue(cr.width())); + er.setLeft(fr.right() + 1); + } + else + { + fr.setTop(cr.bottom() - recalcValue(cr.height())); + er.setBottom(fr.top() - 1); + } + + p->setBrushOrigin(cr.topLeft()); + p->fillRect(fr, fb); + p->fillRect(er, eb); + + if( mTextEnabled == true ) + drawText(p); + break; + + case Blocked: + const int margin = 2; + int max, num, dx, dy; + if( mOrientation == Horizontal ) + { + fr.setHeight(cr.height() - 2 * margin); + fr.setWidth((int)(0.67 * fr.height())); + fr.moveTopLeft(QPoint(cr.left() + margin, cr.top() + margin)); + dx = fr.width() + margin; + dy = 0; + max = (cr.width() - margin) / (fr.width() + margin) + 1; + num = recalcValue(max); + } + else + { + fr.setWidth(cr.width() - 2 * margin); + fr.setHeight((int)(0.67 * fr.width())); + fr.moveBottomLeft(QPoint(cr.left() + margin, cr.bottom() - margin)); + dx = 0; + dy = - (fr.height() + margin); + max = (cr.height() - margin) / (fr.height() + margin) + 1; + num = recalcValue(max); + } + p->setClipRect(cr.x() + margin, cr.y() + margin, + cr.width() - margin, cr.height() - margin); + for (int i = 0; i < num; i++) + { + p->setBrushOrigin(fr.topLeft()); + p->fillRect(fr, fb); + fr.moveBy(dx, dy); + } + + if (num != max) + { + if( mOrientation == Horizontal ) + er.setLeft(fr.right() + 1); + else + er.setBottom(fr.bottom() + 1); + if (!er.isNull()) + { + p->setBrushOrigin(cr.topLeft()); + p->fillRect(er, eb); + } + } + break; + } + +} + + +void CStatusBarProgress::mousePressEvent( QMouseEvent */*e*/ ) +{ + emit pressed(); +} + +#include "statusbarprogress.moc" diff --git a/khexedit/statusbarprogress.h b/khexedit/statusbarprogress.h new file mode 100644 index 0000000..ca605f3 --- /dev/null +++ b/khexedit/statusbarprogress.h @@ -0,0 +1,159 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * This file is based on the work by Martynas Kunigelis (KProgress) + * + * 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 _STATUSBAR_PROGRESS_H_ +#define _STATUSBAR_PROGRESS_H_ + +#include <qframe.h> +#include <qrangecontrol.h> + +class CStatusBarProgress : public QFrame, public QRangeControl +{ + Q_OBJECT + + public: + /** + * Possible values for orientation + */ + enum Orientation { Horizontal, Vertical }; + + /** + * Possible values for bar style. + * + * Solid means one continuous progress bar, Blocked means a + * progress bar made up of several blocks. + */ + enum BarStyle { Solid, Blocked }; + + /** + * Construct a default progress bar. Orientation is horizontal. + */ + CStatusBarProgress(QWidget *parent=0, const char *name=0); + + /** + * Construct a KProgress bar with an orientation. + */ + CStatusBarProgress(Orientation, QWidget *parent=0, const char *name=0); + + /** + * Construct a KProgress bar with minimum, maximum and initial value. + */ + CStatusBarProgress(int minValue, int maxValue, int value, Orientation, + QWidget *parent=0, const char *name=0); + + /** + * Destructor + */ + ~CStatusBarProgress( void ); + + /** + * Set the progress bar style. Allowed values are Solid and Blocked. + */ + void setBarStyle(BarStyle style); + + /** + * Set the color of the progress bar. + */ + void setBarColor(const QColor &); + + /** + * Set a pixmap to be shown in the progress bar. + */ + void setBarPixmap(const QPixmap &); + + /** + * Set the orientation of the progress bar. + * Allowed values are Horizonzal and Vertical. + */ + void setOrientation(Orientation); + + /** + * Retrieve the bar style. + */ + BarStyle barStyle() const; + + /** + * Retrieve the bar color. + */ + const QColor &barColor() const; + + /** + * Retrieve the bar pixmap. + */ + const QPixmap *barPixmap() const; + + /** + * Retrieve the orientation. + */ + Orientation orientation() const; + + /** + * Returns TRUE if progress text will be displayed, FALSE otherwise. + */ + bool textEnabled() const; + + /** + * Returns the recommended width for vertical progress bars or + * the recommended height for vertical progress bars + */ + virtual QSize sizeHint() const; + + + public slots: + void setValue( int ); + void setValue( int, int); + void advance( int ); + void setTextEnabled( bool state ); + void setText( const QString &msg ); + + signals: + void percentageChanged(int); + void pressed( void ); + + protected: + void valueChange(); + void rangeChange(); + void styleChange( GUIStyle ); + void paletteChange( const QPalette & ); + void drawContents( QPainter * ); + void mousePressEvent( QMouseEvent *e ); + + private: + QPixmap *mBarPixmap; + QColor mBarColor; + QColor mBarTextColor; + QColor mTextColor; + QRect fr; + BarStyle mBarStyle; + Orientation mOrientation; + bool mTextEnabled; + QString mMsg; + int mCurPage; + int mMaxPage; + + void initialize( void ); + int recalcValue( int ); + void drawText( QPainter * ); + void adjustStyle( void ); +}; + + +#endif diff --git a/khexedit/stringdialog.cc b/khexedit/stringdialog.cc new file mode 100644 index 0000000..dff774c --- /dev/null +++ b/khexedit/stringdialog.cc @@ -0,0 +1,412 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlineedit.h> +#include <qspinbox.h> + +#include <kconfig.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <kmessagebox.h> + +#include "listview.h" +#include "stringdialog.h" +#include <qpushbutton.h> + + +CStringDialog::CStringDialog( QWidget *parent, const char *name, bool modal ) + : KDialogBase( Plain, i18n("Extract Strings"), Help|User1|Cancel, User1, + parent, name, modal, true, i18n("&Update") ), + mMaxLength(0), mBusy(false), mDirty(false) +{ + setHelp( "khexedit/khexedit.html", QString::null ); + + QString text; + QVBoxLayout *topLayout = new QVBoxLayout( plainPage(), 0, spacingHint() ); + + QGridLayout *glay = new QGridLayout( 3, 3, spacingHint() ); + topLayout->addLayout( glay ); + glay->setColStretch( 1, 10 ); + + mLengthSpin = new QSpinBox( plainPage() ); + mLengthSpin->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mLengthSpin->setRange( 1, 1000000 ); + mLengthSpin->setValue( 4 ); + glay->addMultiCellWidget( mLengthSpin, 0, 0, 1, 2 ); + + text = i18n("&Minimum length:"); + QLabel *label = new QLabel( mLengthSpin, text, plainPage() ); + glay->addWidget( label, 0, 0, AlignRight ); + + mFilter = new QLineEdit( plainPage() ); + mFilter->setMinimumWidth( fontMetrics().maxWidth()*17 ); + mFilter->setText("*"); + glay->addWidget( mFilter, 1, 1 ); + + text = i18n("&Filter:"); + label = new QLabel( mFilter, text, plainPage() ); + glay->addWidget( label, 1, 0, AlignRight ); + + QPushButton *useButton = new QPushButton( plainPage(), "use" ); + useButton->setText( i18n("&Use") ); + useButton->setAutoDefault( false ); + connect( useButton, SIGNAL(clicked()),this,SLOT(slotUser1()) ); + glay->addWidget( useButton, 1, 2 ); + + QWidget *helper = new QWidget( plainPage() ); + glay->addMultiCellWidget( helper, 2, 2, 1, 2 ); + QHBoxLayout *hlay = new QHBoxLayout( helper, 0, spacingHint() ); + + text = i18n("&Ignore case"); + mIgnoreCaseCheck = new QCheckBox( text, helper ); + hlay->addWidget( mIgnoreCaseCheck ); + + text = i18n("Show offset as &decimal"); + mOffsetDecimalCheck = new QCheckBox( text, helper ); + hlay->addWidget( mOffsetDecimalCheck ); + + hlay->addStretch(10); + + // + // Using listview as suggested by Dima Rogozin <dima@mercury.co.il> + // + mStringList = new CListView( plainPage(), "stringList" ); + mStringList->setFont( KGlobalSettings::fixedFont() ); + mStringList->addColumn( i18n("Offset") ); + mStringList->addColumn( i18n("String") ); + mStringList->setAllColumnsShowFocus( true ); + mStringList->setFrameStyle( QFrame::WinPanel + QFrame::Sunken ); + + connect( mStringList, SIGNAL(selectionChanged()), + SLOT(selectionChanged())); + topLayout->addWidget( mStringList, 10 ); + + hlay = new QHBoxLayout( topLayout ); + + text = i18n("Number of strings:"); + label = new QLabel( text, plainPage() ); + hlay->addWidget( label, AlignLeft ); + + mListSizeLabel = new QLabel( QString(), plainPage() ); + mListSizeLabel->setFixedWidth( fontMetrics().maxWidth()*10 ); + hlay->addWidget( mListSizeLabel, AlignLeft|AlignHCenter ); + + text = i18n("Displayed:"); + label = new QLabel( text, plainPage() ); + hlay->addWidget( label, AlignLeft ); + + mDisplaySizeLabel = new QLabel( QString(""), plainPage() ); + mDisplaySizeLabel->setFixedWidth( fontMetrics().maxWidth()*10 ); + hlay->addWidget( mDisplaySizeLabel, AlignLeft|AlignHCenter); + + hlay->addStretch( 10 ); + + mDirtyLabel = new QLabel( plainPage() ); + topLayout->addWidget( mDirtyLabel ); + + readConfiguration(); + + // + // The initial width of the columns are set in updateListInfo() + // + updateListInfo(); + mStringList->setVisibleItem( 15 ); + startTimer(100); +} + + +CStringDialog::~CStringDialog( void ) +{ + writeConfiguration(); +} + + +void CStringDialog::showEvent( QShowEvent *e ) +{ + KDialogBase::showEvent(e); + mLengthSpin->setFocus(); +} + + +void CStringDialog::readConfiguration( void ) +{ + KConfig &config = *kapp->config(); + config.setGroup( "String Dialog" ); + + mLengthSpin->setValue( config.readNumEntry("MinimumLength", 4) ); + mFilter->setText( config.readEntry("FilterText", "*") ); + mIgnoreCaseCheck->setChecked( config.readBoolEntry("IgnoreCase", false) ); + mOffsetDecimalCheck->setChecked( + config.readBoolEntry("OffsetAsDecimal", false ) ); +} + + +void CStringDialog::writeConfiguration( void ) +{ + KConfig &config = *kapp->config(); + config.setGroup( "String Dialog" ); + + config.writeEntry( "MinimumLength", mLengthSpin->value() ); + config.writeEntry( "FilterText", mFilter->text() ); + config.writeEntry( "IgnoreCase", mIgnoreCaseCheck->isChecked() ); + config.writeEntry( "OffsetAsDecimal", mOffsetDecimalCheck->isChecked() ); + config.sync(); +} + + +void CStringDialog::slotUser1( void ) // Start +{ + if( mBusy == true ) + { + return; + } + + mRegExp.setCaseSensitive( mIgnoreCaseCheck->isChecked() == false ); + mRegExp.setWildcard( true ); + if( mFilter->text().isEmpty() == true ) + { + mRegExp.setPattern("*"); + } + else + { + mRegExp.setPattern(mFilter->text()); + } + + if( mRegExp.isValid() == false ) + { + QString msg = i18n("" + "The filter expression you have specified is illegal. " + "You must specify a valid regular expression.\n" + "Continue without filter?"); + int reply = KMessageBox::warningContinueCancel( this, msg, i18n("Extract Strings")); + if( reply != KMessageBox::Continue ) + { + return; + } + mRegExp.setPattern( "*"); + } + + + mStringData.minLength = mLengthSpin->value(); + mStringData.decimalOffset = mOffsetDecimalCheck->isChecked(); + + removeList(); + + mBusy = true; + emit collect(); + mBusy = false; +} + + +void CStringDialog::startGoto( QListViewItem *item ) +{ + QString str_offset = item->text(0); + QString string = item->text(1); + + uint offset; + if( stringData().decimalOffset == true ) + { + // sscanf( str_offset.ascii(), "%u", &offset ); + offset = str_offset.toInt(); + } + else + { + uint val1,val2; + // #### Rewrite it do it doesn't need the .ascii() call + sscanf( str_offset.ascii(), "%X:%X", &val1, &val2 ); + offset = (val1<<16) + val2; + } + + uint size = string.length(); + + emit markText( offset, size, true ); +} + + +void CStringDialog::setDirty( void ) +{ + if( mDirty == true ) + { + return; + } + + mDirtyLabel->setText( + i18n("Warning: Document has been modified since last update")); + mDirty = true; +} + + +void CStringDialog::setClean( void ) +{ + if( mDirty == false ) + { + return; + } + + mDirtyLabel->setText(""); + mDirty = false; +} + + +void CStringDialog::selectionChanged() +{ + killTimers(); + startTimer( 200 ); +} + + +void CStringDialog::timerEvent( QTimerEvent * ) +{ + killTimers(); + + QListViewItem *item = mStringList->currentItem(); + if( item == 0 ) + { + slotUser1(); + return; + } + startGoto( item ); +} + + +void CStringDialog::resizeEvent( QResizeEvent * ) +{ + setColumnWidth(); +} + + + +int CStringDialog::updateList( CProgress &p ) +{ + clearList(); + enableList( false ); + + int offsetLen = stringData().offsetLen(); + + QPtrList<QString> &list = stringData().list(); + for( const QString *str = list.first(); str != 0; str = list.next() ) + { + appendListItem( *str, offsetLen ); + mMaxLength = QMAX( mMaxLength, str->length() ); + + if( p.expired() == true ) + { + int errCode = p.step( (float)list.at()/(float)list.count() ); + if( errCode == Err_Stop ) + { + p.finish(); + return( Err_Success ); + } + } + } + + p.finish(); + updateListInfo(); + enableList( true ); + + return( Err_Success ); +} + + + + +void CStringDialog::clearList( void ) +{ + if( mStringList->childCount() > 0 ) + { + mStringList->clear(); + mStringList->update(); + } + mMaxLength = 0; + + updateListInfo(); + setClean(); +} + + +void CStringDialog::removeList( void ) +{ + mStringData.clear(); + clearList(); +} + + +void CStringDialog::enableList( bool state ) +{ + mStringList->setEnabled( state ); + if( state == true ) + { + mStringList->update(); + } +} + + +void CStringDialog::appendListItem( const QString &str, uint offsetLen ) +{ + if( mRegExp.search ( str, offsetLen ) != -1 ) + { + new QListViewItem( mStringList, str.left(offsetLen), str.mid(offsetLen) ); + } +} + + +void CStringDialog::updateListInfo( void ) +{ + mListSizeLabel->setText( QString("%1").arg(mStringData.count()) ); + mDisplaySizeLabel->setText( QString("%1").arg(mStringList->childCount()) ); + setColumnWidth(); +} + + + +void CStringDialog::setColumnWidth( void ) +{ + const QFontMetrics &fm = mStringList->fontMetrics(); + + if( mStringData.count() == 0 ) + { + int w1 = fm.maxWidth() * (stringData().offsetLen() + 2); + int w2 = mStringList->viewport()->width() - w1; + mStringList->setColumnWidth( 0, w1 ); + mStringList->setColumnWidth( 1, w2 ); + } + else + { + int w1 = fm.maxWidth() * (stringData().offsetLen() + 2); + int w2 = fm.maxWidth() * mMaxLength - w1; + if( w2 < 0 ) + { + w2 = mStringList->viewport()->width() - w1; + } + + mStringList->setColumnWidth( 0, w1 ); + mStringList->setColumnWidth( 1, w2 ); + } +} + + + + + + +#include "stringdialog.moc" diff --git a/khexedit/stringdialog.h b/khexedit/stringdialog.h new file mode 100644 index 0000000..ec731e4 --- /dev/null +++ b/khexedit/stringdialog.h @@ -0,0 +1,110 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * 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 _STRING_DIALOG_H_ +#define _STRING_DIALOG_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +class QCheckBox; +class QLabel; +class QLineEdit; +class QListView; +class QSpinBox; + +#include <qregexp.h> +#include <kdialogbase.h> + +class CListView; +#include "hexbuffer.h" +#include "progress.h" + +class CStringDialog : public KDialogBase +{ + Q_OBJECT + + public: + CStringDialog( QWidget *parent=0, const char *name = 0, bool modal=false ); + ~CStringDialog( void ); + + int updateList( CProgress &p ); + inline CStringCollectControl &stringData( void ); + + signals: + void markText( uint offset, uint size, bool moveCursor ); + void collect( void ); + + public slots: + void clearList( void ); // Removes list entries + void removeList( void ); // Removes list entries and the string list. + void setDirty( void ); + void setClean( void ); + + protected slots: + virtual void slotUser1( void ); + virtual void startGoto( QListViewItem * ); + virtual void selectionChanged( ); + + protected: + virtual void timerEvent( QTimerEvent *e ); + virtual void resizeEvent( QResizeEvent *e ); + virtual void showEvent( QShowEvent *e ); + + private: + void enableList( bool state ); + void appendListItem( const QString &str, uint offsetSize ); + void updateListInfo( void ); + void setColumnWidth( void ); + void readConfiguration( void ); + void writeConfiguration( void ); + + private: + CStringCollectControl mStringData; + QRegExp mRegExp; + uint mMaxLength; + bool mBusy; + bool mDirty; + + QSpinBox *mLengthSpin; + QLineEdit *mFilter; + QCheckBox *mIgnoreCaseCheck; + QCheckBox *mOffsetDecimalCheck; + CListView *mStringList; + QLabel *mListSizeLabel; + QLabel *mDisplaySizeLabel; + QLabel *mDirtyLabel; +}; + + +CStringCollectControl &CStringDialog::stringData( void ) +{ + return( mStringData ); +} + +#endif + + + + + + + diff --git a/khexedit/toplevel.cc b/khexedit/toplevel.cc new file mode 100644 index 0000000..733173e --- /dev/null +++ b/khexedit/toplevel.cc @@ -0,0 +1,1366 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * 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. + * + */ + +// kate: space-indent on; indent-width 2; replace-tabs on; + +#include <qptrlist.h> +#include <qsignalmapper.h> +#include <qtimer.h> +#include <qtooltip.h> + +#include <kaction.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstatusbar.h> +#include <kpopupmenu.h> +#include <kstdaction.h> +#include <ktoolbarbutton.h> +#include <kdebug.h> +#include <kurl.h> +#include <kurldrag.h> + +#include "dialog.h" +#include "draglabel.h" +#include "hexerror.h" +#include "toplevel.h" + + +QPtrList<KHexEdit> KHexEdit::mWindowList; + +KHexEdit::KHexEdit( void ) + : KMainWindow(0, "toplevel"), mStartupOffset(0), + mIsModified(0) +{ + mWindowList.append( this ); + + // + // Create main widget and register it. + // + mManager = new CHexManagerWidget( this, "manager" ); + setCentralWidget( mManager ); + + // + // I use an eventfilter to catch all drag/drop events for the + // area outside the editor window. It will only accept KURLDrag. + // (The editor window will catch KURLDrag, QTextDrag and CHexDrag) + // + installEventFilter( this ); + setAcceptDrops(true); + + // + // Prepare menus and status bar + // + mAction.bookmarkMapper = new QSignalMapper(this); + connect(mAction.bookmarkMapper, SIGNAL(mapped(int)), editor(), SLOT(gotoBookmark(int))); + setupActions(); + setupStatusBar(); + + connect( hexView(), SIGNAL( cursorChanged( SCursorState & ) ), + this, SLOT( cursorChanged( SCursorState & ) ) ); + connect( hexView(), SIGNAL( editMode( CHexBuffer::EEditMode ) ), + this, SLOT( editMode( CHexBuffer::EEditMode ) ) ); + connect( hexView(), SIGNAL( encodingChanged( const SEncodeState &)), + this, SLOT( encodingChanged( const SEncodeState & )) ); + connect( hexView(), SIGNAL( textWidth( uint ) ), + this, SLOT( textWidth( uint ) ) ); + connect( hexView(), SIGNAL( fileState( SFileState & ) ), + this, SLOT( fileState( SFileState & ) ) ); + connect( hexView(), SIGNAL( layoutChanged( const SDisplayLayout & ) ), + this, SLOT( layoutChanged( const SDisplayLayout & ) ) ); + connect( hexView(), SIGNAL( inputModeChanged( const SDisplayInputMode & ) ), + this, SLOT( inputModeChanged( const SDisplayInputMode & ) ) ); + connect( hexView(), SIGNAL( bookmarkChanged( QPtrList<SCursorOffset> &)), + this, SLOT( bookmarkChanged( QPtrList<SCursorOffset> & ) ) ); + connect( hexView(), SIGNAL( fileName( const QString &, bool ) ), + this, SLOT( fileActive( const QString &, bool ) ) ); + connect( hexView(), SIGNAL( fileRename( const QString &, const QString & )), + this, SLOT( fileRename( const QString &, const QString & ) ) ); + connect( hexView(), SIGNAL( fileClosed( const QString & ) ), + this, SLOT( fileClosed( const QString & ) ) ); + connect( editor(), SIGNAL( errorLoadFile( const QString & ) ), + this, SLOT( removeRecentFile( const QString & ) ) ); + connect( editor(), SIGNAL( operationChanged( bool ) ), + this, SLOT( operationChanged( bool ) ) ); + connect( editor(), SIGNAL( removeRecentFiles() ), + this, SLOT( removeRecentFiles() ) ); + connect( mManager, SIGNAL( conversionClosed() ), + this, SLOT(conversionClosed()) ); + connect( mManager, SIGNAL( searchBarClosed() ), + this, SLOT(searchBarClosed()) ); + + // + // Read configuration from file and set the default editor size. + // Open files if this is the first toplevel window. + // + readConfiguration(); + initialize( mWindowList.count() == 1 ? true : false ); + setAutoSaveSettings(); +} + + +KHexEdit::~KHexEdit( void ) +{ + delete mAction.bookmarkMapper; + delete mManager; +} + + +void KHexEdit::setupActions( void ) +{ + KStdAction::openNew( editor(), SLOT(newFile()), actionCollection() ); + KStdAction::open( editor(), SLOT(open()), actionCollection() ); + KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), +actionCollection()); + + mAction.insert = new KAction( i18n("&Insert..."), CTRL+Key_I, + editor(), SLOT(insertFile()), actionCollection(), "insert_file" ); + mAction.openRecent = KStdAction::openRecent( this, SLOT( slotFileOpenRecent( const KURL& ) ), actionCollection() ); + mAction.save = KStdAction::save( editor(), SLOT(save()), actionCollection() ); + mAction.saveAs = KStdAction::saveAs( editor(), SLOT(saveAs()), actionCollection() ); + mAction.revert = KStdAction::revert( editor(), SLOT(reload()), actionCollection() ); + //mAction.revert = KStdAction::revert( this, SLOT(resizeTest()), actionCollection() ); + + mAction.close = KStdAction::close( editor(), SLOT(close()), actionCollection() ); + mAction.print = KStdAction::print( editor(), SLOT(print()), actionCollection() ); + mAction.exportData = new KAction( i18n("E&xport..."), 0, + editor(), SLOT(exportDialog()), actionCollection(), "export" ); + mAction.cancel = new KAction( i18n("&Cancel Operation"), + "stop", 0, editor(), SLOT(stop()), actionCollection(), "cancel" ); + mAction.readOnly = new KToggleAction( i18n("&Read Only"), + 0, editor(), SLOT(toggleWriteProtection()),actionCollection(), "read_only" ); + mAction.resizeLock = new KToggleAction( i18n("&Allow Resize"), + 0, editor(), SLOT(toggleResizeLock()),actionCollection(), "resize_lock" ); + mAction.newWindow = new KAction( i18n("N&ew Window"), + 0, this, SLOT(newWindow()),actionCollection(), "new_window" ); + mAction.closeWindow= new KAction( i18n("Close &Window"), + 0, this, SLOT(closeWindow()),actionCollection(), "close_window" ); + mAction.quit = KStdAction::quit( this, SLOT(closeProgram()), actionCollection() ); + + mAction.undo = KStdAction::undo( editor(), SLOT(undo()), actionCollection() ); + mAction.redo = KStdAction::redo( editor(), SLOT(redo()), actionCollection() ); + mAction.cut = KStdAction::cut( editor(), SLOT(cut()), actionCollection() ); + mAction.copy = KStdAction::copy( editor(), SLOT(copy()), actionCollection() ); + mAction.paste = KStdAction::paste( editor(), SLOT(paste()), actionCollection() ); + mAction.selectAll = KStdAction::selectAll(editor(), SLOT(selectAll()),actionCollection() ); + mAction.unselect = KStdAction::deselect(editor(), SLOT(unselect()), actionCollection()); + mAction.find = KStdAction::find( editor(), SLOT(find()), actionCollection() ); + mAction.findNext = KStdAction::findNext(editor(), SLOT(findNext()), actionCollection() ); + mAction.findPrev = KStdAction::findPrev(editor(),SLOT(findPrevious()),actionCollection() ); + mAction.replace = KStdAction::replace( editor(), SLOT(replace()), actionCollection() ); + mAction.gotoOffset = new KAction( i18n("&Goto Offset..."), CTRL+Key_G, + editor(), SLOT(gotoOffset()),actionCollection(), "goto_offset" ); + mAction.insertPattern = new KAction( i18n("&Insert Pattern..."), CTRL+Key_Insert, + editor(), SLOT(insertPattern()), actionCollection(), "insert_pattern" ); + + mAction.copyAsText = new KAction( i18n("Copy as &Text"), 0, + editor(), SLOT(copyText()), actionCollection(), "copy_as_text" ); + mAction.pasteToNewFile = new KAction( i18n("Paste into New &File"), 0, + editor(), SLOT(pasteNewFile()), actionCollection(), "paste_into_new_file" ); + mAction.pasteToNewWindow = new KAction( i18n("Paste into New &Window"), 0, + this, SLOT(pasteNewWindow()), actionCollection(), "paste_into_new_window" ); + + mAction.hexadecimal = new KRadioAction( i18n("&Hexadecimal"), + 0, this, SLOT(setDisplayMode()), actionCollection(), "mode_hex" ); + mAction.decimal = new KRadioAction( i18n("&Decimal"), + 0, this, SLOT(setDisplayMode()), actionCollection(), "mode_dec" ); + mAction.octal = new KRadioAction( i18n("&Octal"), + 0, this, SLOT(setDisplayMode()), actionCollection(), "mode_oct" ); + mAction.binary = new KRadioAction( i18n("&Binary"), + 0, this, SLOT(setDisplayMode()), actionCollection(), "mode_bin" ); + mAction.textOnly = new KRadioAction( i18n("&Text"), + 0, this, SLOT(setDisplayMode()), actionCollection(), "mode_text" ); + mAction.hexadecimal->setExclusiveGroup( "displayMode" ); + mAction.decimal->setExclusiveGroup( "displayMode" ); + mAction.octal->setExclusiveGroup( "displayMode" ); + mAction.binary->setExclusiveGroup( "displayMode" ); + mAction.textOnly->setExclusiveGroup( "displayMode" ); + + mAction.showOffsetColumn = new KToggleAction( i18n("Show O&ffset Column"), + 0, editor(), SLOT(toggleOffsetColumnVisibility()),actionCollection(), "show_offset_column" ); + mAction.showTextColumn = new KToggleAction( i18n("Show Te&xt Field"), + 0, editor(), SLOT(toggleTextColumnVisibility()),actionCollection(), "show_text_field" ); + mAction.offsetAsDecimal = new KToggleAction( i18n("Off&set as Decimal"), + 0, editor(), SLOT(toggleOffsetAsDecimal()),actionCollection(), "offset_as_decimal" ); + mAction.dataUppercase = new KToggleAction( i18n("&Upper Case (Data)"), + 0, editor(), SLOT(toggleDataUppercase()),actionCollection(), "upper_case_data" ); + mAction.offsetUppercase = new KToggleAction( i18n("Upper &Case (Offset)"), + 0, editor(), SLOT(toggleOffsetUppercase()),actionCollection(), "upper_case_offset" ); + + mAction.defaultEncoding = new KRadioAction( i18n("&Default encoding", "&Default"), + 0, this, SLOT( setEncoding()), actionCollection(), "enc_default" ); + mAction.usAsciiEncoding = new KRadioAction( i18n("US-&ASCII (7 bit)"), + 0, this, SLOT( setEncoding()), actionCollection(), "enc_ascii"); + mAction.ebcdicEncoding = new KRadioAction( i18n("&EBCDIC"), + 0, this, SLOT( setEncoding()), actionCollection(), "enc_ebcdic" ); +// mAction.customEncoding = new KAction( i18n("&Custom..."), +// 0, editor(), SLOT( encoding()), actionCollection(), "enc_custom" ); + mAction.defaultEncoding->setExclusiveGroup( "encodingMode" ); + mAction.usAsciiEncoding->setExclusiveGroup( "encodingMode" ); + mAction.ebcdicEncoding->setExclusiveGroup( "encodingMode" ); + + mAction.strings = new KAction( i18n("&Extract Strings..."), 0, + editor(), SLOT(strings()), actionCollection(), "extract_strings" ); +// mAction.recordViewer = new KAction( i18n("&Record Viewer"), 0, +// editor(), SLOT(recordView()), actionCollection(), "record_viewer" ); + mAction.filter = new KAction( i18n("&Binary Filter..."), 0, + editor(), SLOT(filter()), actionCollection(), "binary_filter" ); + mAction.characterTable = new KAction( i18n("&Character Table"), 0, + editor(), SLOT(chart()), actionCollection(), "char_table" ); + mAction.converter = new KAction( i18n("C&onverter"), 0, + editor(), SLOT(converter()), actionCollection(), "converter" ); + mAction.statistics = new KAction( i18n("&Statistics"), 0, + editor(), SLOT(statistics()), actionCollection(), "statistics" ); + + mAction.addBookmark = KStdAction::addBookmark( editor(), + SLOT(addBookmark()), actionCollection() ); + mAction.replaceBookmark = new KAction( i18n("&Replace Bookmark"), CTRL+Key_E, + editor(), SLOT(replaceBookmark()), actionCollection(), "replace_bookmark"); + mAction.removeBookmark = new KAction( i18n("R&emove Bookmark"), CTRL+Key_U, + editor(), SLOT(removeBookmark()), actionCollection(), "remove_bookmark" ); + mAction.removeAllBookmark = new KAction( i18n("Re&move All"), 0, + editor(), SLOT(removeAllBookmark()), actionCollection(), "remove_all_bookmarks" ); + mAction.nextBookmark = new KAction( i18n("Goto &Next Bookmark"), + ALT+Key_Down, editor(), + SLOT(gotoNextBookmark()), actionCollection(), "next_bookmark" ); + mAction.prevBookmark = new KAction( i18n("Goto &Previous Bookmark"), + ALT+Key_Up, editor(), + SLOT(gotoPrevBookmark()), actionCollection(), "prev_bookmark" ); + + createStandardStatusBarAction(); + setStandardToolBarMenuEnabled(true); + mAction.showFullPath = new KToggleAction( i18n("Show F&ull Path"), + 0, this, SLOT(showFullPath()), actionCollection(), "show_full_path" ); + + mAction.tabHide = new KRadioAction( i18n("&Hide"), + 0, this, SLOT(showDocumentTabs()), actionCollection(), "doctab_hide" ); + mAction.tabShowAboveEditor = new KRadioAction( i18n("&Above Editor"), + 0, this, SLOT(showDocumentTabs()), actionCollection(), "doctab_above" ); + mAction.tabShowBelowEditor = new KRadioAction( i18n("&Below Editor"), + 0, this, SLOT(showDocumentTabs()), actionCollection(), "doctab_below" ); + mAction.tabHide->setExclusiveGroup( "editorTab" ); + mAction.tabShowAboveEditor->setExclusiveGroup( "editorTab" ); + mAction.tabShowBelowEditor->setExclusiveGroup( "editorTab" ); + + mAction.conversionHide = new KRadioAction( i18n("&Hide"), + 0, this, SLOT(showConversionField()), actionCollection(), "conversion_field_hide"); + mAction.conversionFloat = new KRadioAction( i18n("&Floating"), + 0, this, SLOT(showConversionField()), actionCollection(), "conversion_field_float"); + mAction.conversionEmbed = new KRadioAction( i18n("&Embed in Main Window"), + 0, this, SLOT(showConversionField()), actionCollection(), "conversion_field_embed"); + mAction.conversionHide->setExclusiveGroup( "conversionField" ); + mAction.conversionFloat->setExclusiveGroup( "conversionField" ); + mAction.conversionEmbed->setExclusiveGroup( "conversionField" ); + + mAction.searchHide = new KRadioAction( i18n("&Hide"), + 0, this, SLOT(showSearchBar()), actionCollection(), "searchbar_hide" ); + mAction.searchShowAboveEditor = new KRadioAction( i18n("&Above Editor"), + Key_F5, this, SLOT(showSearchBar()), actionCollection(), "searchbar_above" ); + mAction.searchShowBelowEditor = new KRadioAction( i18n("&Below Editor"), + Key_F6, this, SLOT(showSearchBar()), actionCollection(), "searchbar_below" ); + mAction.searchHide->setExclusiveGroup( "searchBar" ); + mAction.searchShowAboveEditor->setExclusiveGroup( "searchBar" ); + mAction.searchShowBelowEditor->setExclusiveGroup( "searchBar" ); + + KStdAction::saveOptions(this, SLOT(writeConfiguration()), actionCollection()); + KStdAction::preferences(editor(),SLOT(options()),actionCollection() ); +// mAction.favorites = new KAction( i18n("P&rofiles..."), 0, +// editor(), SLOT(favorites()), actionCollection(), "favorites" ); + + KStdAction::help( this, SLOT(appHelpActivated()), actionCollection() ); + + mDragLabel = new CDragLabel(this); + mDragLabel->setPixmap( UserIcon( "hexdrag" ) ); + mDragLabel->setDragMask( UserIcon( "hexmask" ) ); + mDragLabel->setEnabled( false ); // Enabled once we open a document + QToolTip::add( mDragLabel, i18n("Drag document") ); + (void) new KWidgetAction(mDragLabel, i18n("Drag Document"), 0, editor(), SLOT(options()), actionCollection(), "drag_document"); + + createGUI("khexeditui.rc", false); + + QPopupMenu *popup = (QPopupMenu *)factory()->container("editor_popup", this); + hexView()->setPopupMenu( popup ); + + int id = 100; + toolBar(0)->insertButton( MainBarIcon("lock"), id, SIGNAL(clicked()), + editor(), SLOT(toggleWriteProtection()), true, + i18n("Toggle write protection") ); + toolBar(0)->alignItemRight( id ); + mWriteProtectButton = toolBar(0)->getButton(id); + + QPopupMenu *documentMenu = (QPopupMenu *)factory()->container("documents", this); + hexView()->setDocumentMenu(documentMenu); + connect(documentMenu, SIGNAL(activated(int)), SLOT(documentMenuCB(int))); + +} + + +void KHexEdit::setupStatusBar( void ) +{ + CStatusBarProgress *progess = new CStatusBarProgress( statusBar() ); + statusBar()->addWidget( progess, 10 ); + connect( progess, SIGNAL(pressed()), editor(), SLOT(stop()) ); + connect( editor(), SIGNAL( setProgress( int ) ), + progess, SLOT( setValue( int ) ) ); + connect( editor(), SIGNAL( setProgress( int, int ) ), + progess, SLOT( setValue( int, int ) ) ); + connect( editor(), SIGNAL( enableProgressText( bool ) ), + progess, SLOT( setTextEnabled( bool ) ) ); + connect( editor(), SIGNAL( setProgressText( const QString & ) ), + progess, SLOT( setText( const QString & ) ) ); + + statusBar()->insertFixedItem( i18n("Selection: 0000:0000 0000:0000"), + status_Selection ); + statusBar()->insertFixedItem( i18n("M"), status_Modified ); + statusBar()->insertFixedItem( i18n("OVR"), status_Ovr ); + statusBar()->insertFixedItem( i18n("Size: FFFFFFFFFF"), status_Size ); + statusBar()->insertFixedItem( i18n("Offset: FFFFFFFFFF-F"), status_Offset ); + statusBar()->insertFixedItem( i18n("FFF"), status_Layout ); + statusBar()->insertFixedItem( i18n("RW"), status_WriteProtect ); + + statusBar()->setItemAlignment( status_Selection, AlignLeft|AlignVCenter ); + statusBar()->setItemAlignment( status_Size, AlignLeft|AlignVCenter ); + statusBar()->setItemAlignment( status_Offset, AlignLeft|AlignVCenter ); + + // + // Some good default strings we can use after the fields have got + // their fixed width. + // + statusBar()->changeItem( i18n("Offset:"), status_Offset ); + statusBar()->changeItem( i18n("Size:"), status_Size ); + statusBar()->changeItem( "", status_Modified ); + statusBar()->changeItem( "", status_Selection ); + connect( statusBar(),SIGNAL(pressed(int)),this,SLOT(statusBarPressed(int)) ); +} + + +void KHexEdit::removeRecentFiles( void ) +{ + mAction.openRecent->clearURLList(); +} + + +void KHexEdit::initialize( bool openFiles ) +{ + mUndoState = CHexBuffer::UndoOk; // Reset in function below + setUndoState( 0 ); + + mSelectionOffset = 0; + mSelectionSize = 1; + mSelectionAsHexadecimal = true; + setSelectionState( 0, 0 ); + + operationChanged( false ); + + editor()->initialize(); + + mAction.showFullPath->setChecked( mShowFullPath ); + showFullPath(); + + if ( openFiles && editor()->openFile() != SDisplayMisc::none ) + { + // Code modified from kdelibs/kdeui/kactionclasses.cpp KRecentFilesAction::loadEntries + + KConfig* config = kapp->config(); + + const QString oldGroup = config->group(); + + const QString groupname = "RecentFiles"; + config->setGroup( groupname ); + + // read file list + unsigned int maxItems = mAction.openRecent->maxItems(); + if ( editor()->openFile() == SDisplayMisc::mostRecent ) + maxItems = 1; + for( unsigned int i = 1 ; i <= maxItems ; i++ ) + { + const QString key = QString( "File%1" ).arg( i ); + const QString value = config->readPathEntry( key ); + + if (!value.isEmpty()) + { + mStartupFileList.append( value ); + mStartupOffsetList.append( "0" ); // ### TODO find a way to still have kept offsets + } + } + + config->setGroup( oldGroup ); + + } + + // + // Open file(s) after editor has been displayed. + // Main reason: If anything goes wrong and an error dialog box + // is displayed, then the editor will not be visible until the error + // is confirmed and the (modal) dialog is closed. + // + QTimer::singleShot( 100, this, SLOT(delayedStartupOpen()) ); +} + + +void KHexEdit::delayedStartupOpen( void ) +{ + open( mStartupFileList, mStartupOffsetList ); + mStartupFileList.clear(); + mStartupOffsetList.clear(); +} + + +void KHexEdit::statusBarPressed( int id ) +{ + if( id == status_WriteProtect ) + { + editor()->toggleWriteProtection(); + } + else if( id == status_Ovr ) + { + editor()->toggleInsertMode(); + } + else if( id == status_Offset ) + { + editor()->toggleOffsetAsDecimal(); + } + else if( id == status_Selection ) + { + if( mSelectionSize > 0 ) + { + mSelectionAsHexadecimal = mSelectionAsHexadecimal == true ? false : true; + setSelectionText( mSelectionOffset, mSelectionSize ); + } + } + +} + + + +void KHexEdit::open( QStringList &fileList, QStringList &offsetList ) +{ + // + // We load in reverse to allow the first document in + // the list to become the active one. + // + + uint offset; + for( uint i = fileList.count(); i>0; i-- ) + { + if( i <= offsetList.count() ) + { + offset = (*offsetList.at(i-1)).toUInt(0,16); + } + else + { + offset = 0; + } + editor()->open( *fileList.at(i-1), true, offset ); + } +} + +void KHexEdit::addRecentFile( const QString &fileName ) +{ + if( fileName.isEmpty() == true ) + { + return; + } + + if( fileName.contains( i18n( "Untitled" ), false ) ) + { + return; + } + + const KURL url( KURL::fromPathOrURL( fileName ) ); + kdDebug(1501) << k_funcinfo << " adding recent " << fileName << " => " << url.prettyURL() << endl; + mAction.openRecent->addURL( url ); + +} + + +void KHexEdit::removeRecentFile( const QString &fileName ) +{ + if( fileName.isEmpty() == true ) + { + return; + } + + if( fileName.contains( i18n( "Untitled" ), false ) ) + { + return; + } + + const KURL url( KURL::fromPathOrURL( fileName ) ); + mAction.openRecent->removeURL( url ); + +} + + +void KHexEdit::renameRecentFile(const QString &curName, const QString &newName) +{ + if( curName.contains( i18n( "Untitled" ), false ) ) + { + addRecentFile( newName ); + } + else + { + mAction.openRecent->removeURL( KURL::fromPathOrURL( curName ) ); + mAction.openRecent->addURL( KURL::fromPathOrURL( newName ) ); + } +} + + + +void KHexEdit::slotFileOpenRecent( const KURL& url ) +{ + if ( url.isLocalFile() ) + { + editor()->open( url.path(), false, 0 ); + } + else + { + // ### TODO: support network transparency + KMessageBox::error( this, i18n("Non local recent file: %1").arg( url.prettyURL() ) ); + } +} + + +KHexEdit *KHexEdit::newWindow( void ) +{ + KHexEdit *hexEdit = new KHexEdit; + if( hexEdit == 0 ) + { + QString msg = i18n( "Can not create new window.\n" ); + msg += hexError( Err_NoMemory ); + KMessageBox::error( topLevelWidget(), msg ); + return(0); + } + hexEdit->show(); + return(hexEdit); +} + + + +void KHexEdit::pasteNewWindow( void ) +{ + KHexEdit *app = newWindow(); + if( app != 0 ) + { + app->editor()->pasteNewFile(); + } +} + + + +void KHexEdit::closeWindow( void ) +{ + close(); +} + + +void KHexEdit::closeProgram( void ) +{ + if( mWindowList.count() > 1 ) + { + for( KHexEdit *w = mWindowList.first(); w != 0; w = mWindowList.next() ) + { + if( w->editor()->modified() == true ) + { + QString msg = i18n("" + "There are windows with unsaved modified documents. " + "If you quit now, these modifications will be lost."); + int reply = KMessageBox::warningContinueCancel( topLevelWidget(), msg, QString::null, KStdGuiItem::quit() ); + if( reply == KMessageBox::Continue ) + { + break; + } + else + { + return; + } + } + } + + + // + // Ths will write current configuration to disk. + // + queryExit(); + + // + // Make sure every widget is destroyed. The reason why I do this + // (besides it is the clean way to do it) is to make sure any + // configuration updates in the various destructors are triggered. + // + mWindowList.setAutoDelete(true); + while( mWindowList.first() ) + { + mWindowList.removeRef( mWindowList.first() ); + } + + kapp->quit(); + } + else + { + closeWindow(); + } + +} + + +bool KHexEdit::queryClose( void ) +{ + bool success = editor()->closeAll(); + if( success == true ) + { + mWindowList.removeRef( this ); + } + + return( success ); +} + + +// +// We will always return true here. +// +bool KHexEdit::queryExit( void ) +{ + writeConfiguration(); + return( true ); +} + +void KHexEdit::readConfiguration( void ) +{ + KConfig &config = *kapp->config(); + readConfiguration( config ); +} + + +void KHexEdit::writeConfiguration( void ) +{ + KConfig &config = *kapp->config(); + writeConfiguration( config ); +} + + +void KHexEdit::writeConfiguration( KConfig &config ) +{ + saveMainWindowSettings(& config, "General Options"); + config.setGroup("General Options" ); + config.writeEntry("ShowFullPath", mShowFullPath ); + config.writeEntry("ConversionPosition", (int)mManager->conversionPosition()); + config.writeEntry("TabBarPosition", (int)mManager->tabBarPosition()); + config.writeEntry("SearchBarPosition", (int)mManager->searchBarPosition()); + + if ( editor()->discardRecentFiles() ) + mAction.openRecent->clearURLList(); + mAction.openRecent->saveEntries( &config ); + + converter()->writeConfiguration( config ); + editor()->writeConfiguration( config ); + + config.sync(); +} + + +void KHexEdit::readConfiguration( KConfig &config ) +{ + applyMainWindowSettings(& config, "General Options"); + + config.setGroup("General Options"); + mShowFullPath = config.readBoolEntry( "ShowFullPath", true ); + int position = config.readNumEntry( "ConversionPosition", + CHexManagerWidget::Embed ); + + mAction.conversionHide->blockSignals(true); + mAction.conversionFloat->blockSignals(true); + mAction.conversionEmbed->blockSignals(true); + mAction.conversionHide->setChecked( + position == CHexManagerWidget::Hide ); + mAction.conversionFloat->setChecked( + position == CHexManagerWidget::Float ); + mAction.conversionEmbed->setChecked( + position == CHexManagerWidget::Embed ); + mAction.conversionHide->blockSignals(false); + mAction.conversionFloat->blockSignals(false); + mAction.conversionEmbed->blockSignals(false); + showConversionField(); + + position = config.readNumEntry( "TabBarPosition", CHexManagerWidget::Hide ); + mAction.tabHide->blockSignals(true); + mAction.tabShowAboveEditor->blockSignals(true); + mAction.tabShowBelowEditor->blockSignals(true); + mAction.tabHide->setChecked( + position==CHexManagerWidget::Hide ); + mAction.tabShowAboveEditor->setChecked( + position==CHexManagerWidget::AboveEditor ); + mAction.tabShowBelowEditor->setChecked( + position==CHexManagerWidget::BelowEditor ); + mAction.tabHide->blockSignals(false); + mAction.tabShowAboveEditor->blockSignals(false); + mAction.tabShowBelowEditor->blockSignals(false); + showDocumentTabs(); + + position = config.readNumEntry( "SearchBarPosition", + CHexManagerWidget::BelowEditor ); + mAction.searchHide->blockSignals(true); + mAction.searchShowAboveEditor->blockSignals(true); + mAction.searchShowBelowEditor->blockSignals(true); + mAction.searchHide->setChecked( + position==CHexManagerWidget::Hide ); + mAction.searchShowAboveEditor->setChecked( + position==CHexManagerWidget::AboveEditor ); + mAction.searchShowBelowEditor->setChecked( + position==CHexManagerWidget::BelowEditor ); + mAction.searchHide->blockSignals(false); + mAction.searchShowAboveEditor->blockSignals(false); + mAction.searchShowBelowEditor->blockSignals(false); + showSearchBar(); + + mAction.openRecent->loadEntries( &config ); + + converter()->readConfiguration( config ); + editor()->readConfiguration( config ); +} + + + +void KHexEdit::operationChanged( bool state ) +{ + mAction.cancel->setEnabled( state ); +} + + + +void KHexEdit::cursorChanged( SCursorState &state ) +{ + QString offset( i18n("Offset:") ); + + if( state.valid == false ) + { + statusBar()->changeItem( offset, status_Offset ); + } + else + { + SDisplayLayout &layout = editor()->layout(); + + if( layout.offsetMode == SDisplayLayout::hexadecimal ) + { + if( layout.offsetUpperCase == false ) + { + offset += QString().sprintf( " %04x:%04x-%u", state.offset>>16, + state.offset&0x0000FFFF, state.cell ); + } + else + { + offset += QString().sprintf( " %04X:%04X-%u", state.offset>>16, + state.offset&0x0000FFFF, state.cell ); + } + } + else + { + offset += QString().sprintf( " %010u-%u", state.offset, state.cell ); + } + statusBar()->changeItem( offset, status_Offset ); + } + + setUndoState( state.undoState ); + setSelectionState( state.selectionOffset, state.selectionSize ); +} + + + + +void KHexEdit::fileState( SFileState &state ) +{ + if( state.valid == true ) + { + statusBar()->changeItem( i18n("Size: %1").arg( state.size ), status_Size); + statusBar()->changeItem( state.modified ? "!" : "", status_Modified); + + if( mIsModified != state.modified ) + { + mIsModified = state.modified; + setupCaption( hexView()->url() ); + } + + } + else + { + statusBar()->changeItem( "", status_Size ); + statusBar()->changeItem( "", status_Modified ); + } +} + + + +void KHexEdit::layoutChanged( const SDisplayLayout &layout ) +{ + KRadioAction *radioAction; + + if( layout.primaryMode == SDisplayLayout::hexadecimal ) + { + radioAction = mAction.hexadecimal; + } + else if( layout.primaryMode == SDisplayLayout::decimal ) + { + radioAction = mAction.decimal; + } + else if( layout.primaryMode == SDisplayLayout::octal ) + { + radioAction = mAction.octal; + } + else if( layout.primaryMode == SDisplayLayout::binary ) + { + radioAction = mAction.binary; + } + else + { + radioAction = mAction.textOnly; + } + radioAction->blockSignals(true); + radioAction->setChecked( true ); + radioAction->blockSignals(false); + + mAction.showOffsetColumn->blockSignals(true); + mAction.showTextColumn->blockSignals(true); + mAction.offsetAsDecimal->blockSignals(true); + mAction.dataUppercase->blockSignals(true); + mAction.offsetUppercase->blockSignals(true); + + mAction.showOffsetColumn->setChecked( layout.offsetVisible ); + mAction.showTextColumn->setEnabled( + layout.primaryMode != SDisplayLayout::textOnly ); + mAction.showTextColumn->setChecked( + layout.secondaryMode != SDisplayLayout::hide ); + mAction.offsetAsDecimal->setChecked( + layout.offsetMode != SDisplayLayout::hexadecimal); + mAction.dataUppercase->setChecked( layout.primaryUpperCase ); + mAction.offsetUppercase->setChecked( layout.offsetUpperCase ); + + mAction.showOffsetColumn->blockSignals(false); + mAction.showTextColumn->blockSignals(false); + mAction.offsetAsDecimal->blockSignals(false); + mAction.dataUppercase->blockSignals(false); + mAction.offsetUppercase->blockSignals(false); + + if( layout.primaryMode == SDisplayLayout::hexadecimal ) + { + statusBar()->changeItem( i18n("Hex"), status_Layout ); + } + else if( layout.primaryMode == SDisplayLayout::decimal ) + { + statusBar()->changeItem( i18n("Dec"), status_Layout ); + } + else if( layout.primaryMode == SDisplayLayout::octal ) + { + statusBar()->changeItem( i18n("Oct"), status_Layout ); + } + else if( layout.primaryMode == SDisplayLayout::binary ) + { + statusBar()->changeItem( i18n("Bin"), status_Layout ); + } + else if( layout.primaryMode == SDisplayLayout::textOnly ) + { + statusBar()->changeItem( i18n("Txt"), status_Layout ); + } +} + + +void KHexEdit::inputModeChanged( const SDisplayInputMode &mode ) +{ + mAction.readOnly->blockSignals(true); + mAction.resizeLock->blockSignals(true); + mAction.readOnly->setChecked( mode.readOnly ); + mAction.resizeLock->setChecked( mode.allowResize ); + mAction.readOnly->blockSignals(false); + mAction.resizeLock->blockSignals(false); + + statusBar()->changeItem( mode.readOnly == true ? + i18n("R") : i18n("RW"), status_WriteProtect ); + + if( mode.readOnly == false ) + { + mWriteProtectButton->setIcon("edit"); + } + else + { + mWriteProtectButton->setIcon("lock"); + } +} + + +void KHexEdit::bookmarkChanged( QPtrList<SCursorOffset> &list ) +{ + unplugActionList("bookmark_list"); + mAction.bookmarkList.setAutoDelete(true); + mAction.bookmarkList.clear(); + + if( list.count() == 0 ) + { + return; + } + + mAction.bookmarkList.append(new KActionSeparator()); + + QString text, offset; + int i=0; + + for( SCursorOffset *p=list.first(); p!=0; p=list.next(), i++ ) + { + offset.sprintf("%04X:%04X", p->offset>>16, p->offset&0x0000FFFF ); + text = i18n("Offset: %1").arg(offset); + KAction *action = new KAction(text, 0, mAction.bookmarkMapper, SLOT(map()), this, text.latin1()); + int key = acceleratorNumKey( i ); + if( key > 0 ) + { + action->setShortcut(KShortcut(ALT+key)); + } + mAction.bookmarkMapper->setMapping(action, i); + mAction.bookmarkList.append(action); + } + plugActionList("bookmark_list", mAction.bookmarkList); +} + + +void KHexEdit::setupCaption( const QString &url ) +{ + KURL u(url); + if( mShowFullPath == true ) + { + setCaption( u.prettyURL(), hexView()->modified() ); + } + else + { + setCaption( u.fileName(), hexView()->modified() ); + } +} + + +void KHexEdit::fileActive( const QString &url, bool onDisk ) +{ + setupCaption( url ); + mDragLabel->setUrl( url ); + mDragLabel->setEnabled( onDisk ); + + mAction.revert->setEnabled( onDisk ); + + if( url.isNull() == false ) + { + addDocument( url ); + addRecentFile( url ); + setTickedDocument( url ); + } +} + + +void KHexEdit::fileRename( const QString &curName, const QString &newName ) +{ + if( newName.isNull() == true ) + { + return; + } + + renameDocument( curName, newName ); + renameRecentFile( curName, newName ); + setupCaption( newName ); + //setCaption( newName ); +} + + +void KHexEdit::fileClosed( const QString &url ) +{ + removeDocument( url ); +} + + +void KHexEdit::editMode( CHexBuffer::EEditMode editMode ) +{ + statusBar()->changeItem( editMode == CHexBuffer::EditReplace ? + i18n("OVR") : i18n("INS"), status_Ovr ); +} + + +void KHexEdit::encodingChanged( const SEncodeState &encodeState ) +{ + KRadioAction *radioAction; + + if( encodeState.mode == CConversion::cnvDefault ) + { + radioAction = mAction.defaultEncoding; + } + else if( encodeState.mode == CConversion::cnvUsAscii ) + { + radioAction = mAction.usAsciiEncoding; + } + else if( encodeState.mode == CConversion::cnvEbcdic ) + { + radioAction = mAction.ebcdicEncoding; + } + else + { + return; + } + + radioAction->blockSignals(true); + radioAction->setChecked( true ); + radioAction->blockSignals(false); + + if( mSelectionSize == 0 ) + { + statusBar()->changeItem( i18n("Encoding: %1").arg(encodeState.name), + status_Selection ); + } +} + + +void KHexEdit::textWidth( uint ) +{ + resize( mManager->preferredWidth(), height() ); +} + + +void KHexEdit::setDisplayMode( void ) +{ + if( mAction.hexadecimal->isChecked() == true ) + { + editor()->setHexadecimalMode(); + } + else if( mAction.decimal->isChecked() == true ) + { + editor()->setDecimalMode(); + } + else if( mAction.octal->isChecked() == true ) + { + editor()->setOctalMode(); + } + else if( mAction.binary->isChecked() == true ) + { + editor()->setBinaryMode(); + } + else if( mAction.textOnly->isChecked() == true ) + { + editor()->setTextMode(); + } +} + + +void KHexEdit::showFullPath( void ) +{ + mShowFullPath = mAction.showFullPath->isChecked(); + setupCaption( hexView()->url() ); +} + + +void KHexEdit::showDocumentTabs( void ) +{ + if( mAction.tabHide->isChecked() == true ) + { + mManager->setTabBarPosition( CHexManagerWidget::HideItem ); + } + else if( mAction.tabShowAboveEditor->isChecked() == true ) + { + mManager->setTabBarPosition( CHexManagerWidget::AboveEditor ); + } + else if( mAction.tabShowBelowEditor->isChecked() == true ) + { + mManager->setTabBarPosition( CHexManagerWidget::BelowEditor ); + } +} + + +void KHexEdit::showConversionField( void ) +{ + if( mAction.conversionHide->isChecked() == true ) + { + mManager->setConversionVisibility( CHexManagerWidget::Hide ); + } + else if( mAction.conversionFloat->isChecked() == true ) + { + mManager->setConversionVisibility( CHexManagerWidget::Float ); + } + else if( mAction.conversionEmbed->isChecked() == true ) + { + mManager->setConversionVisibility( CHexManagerWidget::Embed ); + if( width() < mManager->preferredWidth() ) + { + resize( mManager->preferredWidth(), height() ); + } + } +} + + +void KHexEdit::showSearchBar( void ) +{ + if( mAction.searchHide->isChecked() == true ) + { + mManager->setSearchBarPosition( CHexManagerWidget::HideItem ); + } + else if( mAction.searchShowAboveEditor->isChecked() == true ) + { + mManager->setSearchBarPosition( CHexManagerWidget::AboveEditor ); + } + else if( mAction.searchShowBelowEditor->isChecked() == true ) + { + mManager->setSearchBarPosition( CHexManagerWidget::BelowEditor ); + } +} + + +void KHexEdit::setEncoding( void ) +{ + if( mAction.defaultEncoding->isChecked() == true ) + { + editor()->encode( CConversion::cnvDefault ); + } + else if( mAction.usAsciiEncoding->isChecked() == true ) + { + editor()->encode( CConversion::cnvUsAscii ); + } + else if( mAction.ebcdicEncoding->isChecked() == true ) + { + editor()->encode( CConversion::cnvEbcdic ); + } +} + + +void KHexEdit::setUndoState( uint undoState ) +{ + if( mUndoState != undoState ) + { + mUndoState = undoState; + mAction.undo->setEnabled( mUndoState & CHexBuffer::UndoOk ); + mAction.redo->setEnabled( mUndoState & CHexBuffer::RedoOk ); + } +} + + +void KHexEdit::setSelectionState( uint selectionOffset, uint selectionSize ) +{ + if( mSelectionSize != selectionSize ) + { + mSelectionOffset = selectionOffset; + mSelectionSize = selectionSize; + + bool valid = mSelectionSize > 0 ? true : false; + mAction.copy->setEnabled( valid ); + mAction.cut->setEnabled( valid ); + mAction.copyAsText->setEnabled( valid ); + + setSelectionText( selectionOffset, selectionSize ); + } +} + + +void KHexEdit::setSelectionText( uint selectionOffset, uint selectionSize ) +{ + if( selectionSize > 0 ) + { + QString selection = i18n("Selection:"); + if( mSelectionAsHexadecimal == true ) + { + selection += QString().sprintf( " %04x:%04x %04x:%04x", + selectionOffset>>16, selectionOffset&0x0000FFFF, + selectionSize>>16, selectionSize&0x0000FFFF ); + } + else + { + selection += QString().sprintf( " %08u %08u", + selectionOffset, selectionSize); + } + statusBar()->changeItem( selection, status_Selection ); + } + else + { + statusBar()->changeItem( + i18n("Encoding: %1").arg(hexView()->encoding().name), status_Selection); + } +} + + +void KHexEdit::documentMenuCB( int index ) +{ + if( (uint)index < mDocumentList.count() ) + { + editor()->open( mDocumentList[index], false, 0 ); + } +} + + +void KHexEdit::addDocument( const QString &fileName ) +{ + uint documentCount = mDocumentList.count(); + for( uint i=0; i < documentCount; i++ ) + { + if( fileName == mDocumentList[i] ) + { + return; + } + } + + mDocumentList.append( fileName ); + + QPopupMenu *documentMenu = (QPopupMenu *)factory()->container("documents", this); + documentMenu->insertItem( fileName, documentCount, documentCount ); + int key = acceleratorNumKey( documentCount ); + if( key > 0 ) + { + documentMenu->setAccel( CTRL+key, documentCount ); + } +} + + +void KHexEdit::removeDocument( const QString &fileName ) +{ + QStringList::Iterator it; + for( it = mDocumentList.begin(); it != mDocumentList.end(); it++ ) + { + if( *it == fileName ) + { + QPopupMenu *documentMenu = (QPopupMenu *)factory()->container("documents", this); + + documentMenu->removeItemAt( mDocumentList.findIndex(*it) ); + mDocumentList.remove( it ); + + for( uint i=0; i < mDocumentList.count(); i++ ) + { + documentMenu->setId( i, i ); + int key = acceleratorNumKey( i ); + if( key > 0 ) + { + documentMenu->setAccel( CTRL+key, i ); + } + } + return; + + } + } +} + + +void KHexEdit::renameDocument( const QString &curName, const QString &newName ) +{ + QStringList::Iterator it; + for( it = mDocumentList.begin(); it != mDocumentList.end(); it++ ) + { + if( *it == curName ) + { + QPopupMenu *documentMenu = (QPopupMenu *)factory()->container("documents", this); + documentMenu->changeItem( newName, mDocumentList.findIndex(*it) ); + mDocumentList.insert( it, newName ); + mDocumentList.remove( it ); + return; + } + } +} + + +void KHexEdit::setTickedDocument( const QString &fileName ) +{ + uint documentCount = mDocumentList.count(); + QPopupMenu *documentMenu = (QPopupMenu *)factory()->container("documents", this); + for( uint i=0; i < documentCount; i++ ) + { + documentMenu->setItemChecked( i, fileName == mDocumentList[i] ); + } +} + + +void KHexEdit::conversionClosed( void ) +{ + mAction.conversionHide->setChecked(true); +} + + +void KHexEdit::searchBarClosed( void ) +{ + mAction.searchHide->setChecked(true); +} + + +bool KHexEdit::eventFilter( QObject *o, QEvent *event ) +{ + if( event->type() == QEvent::DragEnter ) + { + QDragEnterEvent *e = (QDragEnterEvent*)event; + if( KURLDrag::canDecode(e) ) + { + e->accept(); + hexView()->setDropHighlight( true ); + } + return( true ); + } + else if( event->type() == QEvent::Drop ) + { + QMimeSource &m = *(QDropEvent*)event; + hexView()->setDropHighlight( false ); + + KURL::List list; + if( KURLDrag::decode( &m, list ) == true ) + { + QStringList offset; + QStringList urlList = list.toStringList(); + open( urlList, offset ); + return( true ); + } + return( true ); + } + else if( event->type() == QEvent::DragLeave ) + { + hexView()->setDropHighlight( false ); + return( true ); + } + + return KMainWindow::eventFilter( o, event ); +} + + +int KHexEdit::acceleratorNumKey( uint index ) +{ + static int keys[9] = + { + Key_1, Key_2, Key_3, Key_4, Key_5, Key_6, Key_7, Key_8, Key_9 + }; + return( index >= 9 ? -1 : keys[index] ); +} + + +#include <sys/time.h> +#include <unistd.h> + +// +// This function is used to test kwin performance +// +void KHexEdit::resizeTest() +{ + struct timeval t1, t2; + gettimeofday( &t1, 0 ); + + int loop=400; + + for( int i=0; i<loop; i+=4 ) + { + resize( i+400, i+400 ); + //kapp->processOneEvent(); + } + + gettimeofday( &t2, 0 ); + uint last = (t2.tv_sec-t1.tv_sec) * 1000000 + (t2.tv_usec - t1.tv_usec); + + kdDebug(1501) << "Duration: " << (float)last/ 1000000.0 << endl; + kdDebug(1501) << "Duration/loop: " << (float)last/ (1000000.0*(float)loop) << endl; +} +#include "toplevel.moc" diff --git a/khexedit/toplevel.h b/khexedit/toplevel.h new file mode 100644 index 0000000..fbacca1 --- /dev/null +++ b/khexedit/toplevel.h @@ -0,0 +1,279 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999-2000 Espen Sand, espensa@online.no + * + * 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 _TOPLEVEL_H_ +#define _TOPLEVEL_H_ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qptrlist.h> +#include <kapplication.h> +#include <kstdaccel.h> +#include <kmainwindow.h> + +#include "hexbuffer.h" +#include "hexmanagerwidget.h" +#include "statusbarprogress.h" + +class QSignalMapper; +class KAction; +class KRecentFilesAction; +class KRadioAction; +class KSelectAction; +class KToggleAction; +class KToolBarButton; +class KURL; +class CDragLabel; + + +class KHexEdit : public KMainWindow +{ + Q_OBJECT + + enum StatusBarId + { + status_WriteProtect = 0, + status_Layout = 1, + status_Offset = 2, + status_Size = 3, + status_Ovr = 4, + status_Modified = 5, + status_Selection = 6, + status_Progress = 7 + }; + + struct SActionList + { + KAction *insert; + KRecentFilesAction *openRecent; + KAction *save; + KAction *saveAs; + KAction *revert; + KAction *close; + KAction *print; + KAction *exportData; + KAction *cancel; + KToggleAction *readOnly; + KToggleAction *resizeLock; + KAction *newWindow; + KAction *closeWindow; + KAction *quit; + KAction *undo; + KAction *redo; + KAction *cut; + KAction *copy; + KAction *paste; + KAction *selectAll; + KAction *unselect; + KAction *find; + KAction *findNext; + KAction *findPrev; + KAction *replace; + KAction *gotoOffset; + KAction *insertPattern; + KAction *copyAsText; + KAction *pasteToNewFile; + KAction *pasteToNewWindow; + KRadioAction *hexadecimal; + KRadioAction *decimal; + KRadioAction *octal; + KRadioAction *binary; + KRadioAction *textOnly; + KToggleAction *showOffsetColumn; + KToggleAction *showTextColumn; + KToggleAction *offsetAsDecimal; + KToggleAction *dataUppercase; + KToggleAction *offsetUppercase; + KRadioAction *defaultEncoding; + KRadioAction *usAsciiEncoding; + KRadioAction *ebcdicEncoding; +// KAction *customEncoding; + + KAction *strings; +// KAction *recordViewer; + KAction *filter; + KAction *characterTable; + KAction *converter; + KAction *statistics; + + KAction *addBookmark; + KAction *replaceBookmark; + KAction *removeBookmark; + KAction *removeAllBookmark; + KAction *nextBookmark; + KAction *prevBookmark; + + KToggleAction *showFullPath; + KRadioAction *tabHide; + KRadioAction *tabShowBelowEditor; + KRadioAction *tabShowAboveEditor; + KRadioAction *conversionHide; + KRadioAction *conversionFloat; + KRadioAction *conversionEmbed; + KRadioAction *searchHide; + KRadioAction *searchShowAboveEditor; + KRadioAction *searchShowBelowEditor; + +// KAction *favorites; + + QPtrList< KAction > bookmarkList; + QSignalMapper *bookmarkMapper; + }; + + public: + KHexEdit( void ); + ~KHexEdit( void ); + + inline void addStartupFile( const QString &fileName ); + inline void setStartupOffset( uint offset ); + + public slots: + KHexEdit *newWindow( void ); + void pasteNewWindow( void ); + void closeWindow( void ); + void closeProgram( void ); + void statusBarPressed( int id ); + + void operationChanged( bool state ); + void cursorChanged( SCursorState &state ); + void fileState( SFileState &state ); + void layoutChanged( const SDisplayLayout &layout ); + void inputModeChanged( const SDisplayInputMode &mode ); + void bookmarkChanged( QPtrList<SCursorOffset> &list ); + void removeRecentFile( const QString &fileName ); + void renameRecentFile( const QString &curName, const QString &newName ); + + void setupCaption( const QString &url ); + void fileActive( const QString &url, bool onDisk ); + void fileRename( const QString &curName, const QString &newName ); + void fileClosed( const QString &url ); + void readConfiguration( void ); + void writeConfiguration( void ); + void editMode( CHexBuffer::EEditMode editMode ); + void encodingChanged( const SEncodeState &state ); + void textWidth( uint width ); + + void setDisplayMode( void ); + void showFullPath( void ); + void showDocumentTabs( void ); + void showConversionField( void ); + void showSearchBar( void ); + + void setEncoding( void ); + void documentMenuCB( int id ); + + /** + * Slot for opening a file among the recently opened files. + */ + void slotFileOpenRecent( const KURL & ); + +protected: + virtual bool queryExit( void ); + virtual bool queryClose( void ); + + private slots: + void delayedStartupOpen( void ); + void removeRecentFiles( void ); + void conversionClosed( void ); + void searchBarClosed( void ); + void resizeTest(); + + private: + void setupActions( void ); + void setupStatusBar( void ); + void open( QStringList &fileList, QStringList &offsetList ); + void initialize( bool openFiles ); + void addRecentFile( const QString &fileName ); + bool closeAllWindow( void ); + void setUndoState( uint undoState ); + void setSelectionState( uint selectionOffset, uint selectionSize ); + void setSelectionText( uint selectionOffset, uint selectionSize ); + void addDocument( const QString &fileName ); + void removeDocument( const QString &fileName ); + void renameDocument( const QString &curName, const QString &newName ); + void setTickedDocument( const QString &fileName ); + + void writeConfiguration( KConfig &config ); + void readConfiguration( KConfig &config ); + bool eventFilter( QObject *obj, QEvent *event ); + + int acceleratorNumKey( uint index ); + inline CHexEditorWidget *editor( void ); + inline CHexToolWidget *converter( void ); + inline CHexViewWidget *hexView( void ); + + private: + static QPtrList<KHexEdit> mWindowList; + CHexManagerWidget *mManager; + QStringList mDocumentList; + + QStringList mStartupFileList; ///< Files to automatically open on startup + QStringList mStartupOffsetList; ///< Start offset for those files. + uint mStartupOffset; ///< Value read from the command line + + SActionList mAction; + + CDragLabel *mDragLabel; + KToolBarButton *mWriteProtectButton; + + bool mIsModified; + bool mShowFullPath; + bool mSelectionAsHexadecimal; + uint mSelectionOffset; + uint mSelectionSize; + uint mUndoState; + int mRecentFileId; +}; + + +inline void KHexEdit::addStartupFile( const QString &fileName ) +{ + mStartupFileList.prepend( fileName ); + mStartupOffsetList.prepend( QString("%1").arg(mStartupOffset,0,16) ); + mStartupOffset = 0; +} + +inline void KHexEdit::setStartupOffset( uint offset ) +{ + mStartupOffset = offset; +} + +inline CHexEditorWidget *KHexEdit::editor( void ) +{ + return( mManager->editor() ); +} + +inline CHexViewWidget *KHexEdit::hexView( void ) +{ + return( mManager->editor()->view() ); +} + +inline CHexToolWidget *KHexEdit::converter( void ) +{ + return( mManager->converter() ); +} + + + +#endif + + diff --git a/khexedit/version.h b/khexedit/version.h new file mode 100644 index 0000000..536fa35 --- /dev/null +++ b/khexedit/version.h @@ -0,0 +1,32 @@ +/* + * khexedit - Versatile hex editor + * Copyright (C) 1999 Espen Sand, espensa@online.no + * + * 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 _VERSION_H_ +#define _VERSION_H_ + +// +// Just a few replacements for defines in config.h I used when this +// program lived outside CVS +// +#define APP_PACKAGE_STRING "khexedit" +#define APP_VERSION_STRING "0.8.6" + + +#endif |