diff --git a/changelog b/changelog
new file mode 100644
index 0000000..7a07c5c
--- /dev/null
+++ b/changelog
@@ -0,0 +1,26 @@
+---------------
+ 0.2.1
+---------------
+
+---------------
+ 0.2.0
+---------------
+-ported whole application from Qt3 to Qt4
+(better performance, less memory usage, ready for KDE4)
+-improved Mac OS X support
+-added Drag&Drop support
+-multiple seclection mode for entries
+-improved loading performance for large databases
+-faster in-memory encryption
+-search field in toolbar now works
+-mainwindow size, splitter position and column sizes are restored at start-up
+-added option for alternating row colors
+-improved key/password dialog
+-removed language dialog - program now uses system's default language
+-loading translation files for Qt (e.g. file dialogs)
+-added text export function
+-added option "Never" for expire dates.
+-fixed problem with hex. key files
+-fixed problem with damaged file attachments after various entry operations
+-fixed segmentation fault when using new icons with higher index
+-fixed error when saving empty databases
\ No newline at end of file
diff --git a/keepass.spec b/keepass.spec
new file mode 100644
index 0000000..50b9a98
--- /dev/null
+++ b/keepass.spec
@@ -0,0 +1,55 @@
+Name: keepass
+Summary: KeePassX Cross Platform Password Manager
+Version: 0.2.0
+Release: 1
+License: GPL
+Group: Security
+Source: keepass-0.2.0.tar.gz
+
+
+BuildRoot: /home/tarek/Desktop/KeePassX-RPM-Build
+Packager: Tarek Saidi
+Distribution: KeePassX
+Prefix: /usr/local
+Url: http://keepass.berlios.de
+
+Vendor: Tarek Saidi
+
+
+%description
+KeePassX is a free/open-source password manager or safe which helps you to manage your passwords in a secure way. You can put all your passwords in one database, which is locked with one master key or a key-disk. So you only have to remember one single master password or insert the key-disk to unlock the whole database. The databases are encrypted using the best and most secure encryption algorithms currently known (AES and Twofish).
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+%setup -q
+
+%build
+qmake PREFIX=$RPM_BUILD_ROOT%{prefix}
+make
+
+%install
+make install
+
+cd $RPM_BUILD_ROOT
+
+find . -type d -fprint $RPM_BUILD_DIR/file.list.%{name}.dirs
+find . -type f -fprint $RPM_BUILD_DIR/file.list.%{name}.files.tmp
+sed '/\/man\//s/$/.gz/g' $RPM_BUILD_DIR/file.list.%{name}.files.tmp > $RPM_BUILD_DIR/file.list.%{name}.files
+find . -type l -fprint $RPM_BUILD_DIR/file.list.%{name}.libs
+sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' $RPM_BUILD_DIR/file.list.%{name}.dirs > $RPM_BUILD_DIR/file.list.%{name}
+sed 's,^\.,\%attr(-\,root\,root) ,' $RPM_BUILD_DIR/file.list.%{name}.files >> $RPM_BUILD_DIR/file.list.%{name}
+sed 's,^\.,\%attr(-\,root\,root) ,' $RPM_BUILD_DIR/file.list.%{name}.libs >> $RPM_BUILD_DIR/file.list.%{name}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+rm -rf $RPM_BUILD_DIR/file.list.%{name}
+rm -rf $RPM_BUILD_DIR/file.list.%{name}.libs
+rm -rf $RPM_BUILD_DIR/file.list.%{name}.files
+rm -rf $RPM_BUILD_DIR/file.list.%{name}.files.tmp
+rm -rf $RPM_BUILD_DIR/file.list.%{name}.dirs
+
+%files -f ../file.list.%{name}
+
+%defattr(-,root,root,0755)
diff --git a/src/PwManager.cpp b/src/PwManager.cpp
index 8347b7d..38f027c 100755
--- a/src/PwManager.cpp
+++ b/src/PwManager.cpp
@@ -242,8 +242,21 @@ return true;
}
bool PwDatabase::parseMetaStream(const CEntry& entry){
-//return true for known MetaStreams
-return false;
+if(entry.Additional=="KPX_CUSTOM_ICONS")
+ return parseCustomIconsMetaStream(entry.BinaryData);
+
+
+return false; //unknown MetaStreams
+}
+
+bool PwDatabase::parseCustomIconsMetaStream(const QByteArray& dta){
+Q_UINT32 NumIcons,NumEntries,offset;
+memcpyFromLEnd32(&NumIcons,dta.data());
+memcpyFromLEnd32(&NumEntries,dta.data()+4);
+offset+=4;
+
+
+return true;
}
void PwDatabase::transformKey(Q_UINT8* src,Q_UINT8* dst,Q_UINT8* KeySeed,int rounds){
@@ -1137,7 +1150,7 @@ void PwDatabase::setEntry(unsigned long index,CEntry& entry){
int PwDatabase::numEntries(){
return Entries.size();}
-void memcpyFromLEnd32(Q_UINT32* dst,char* src){
+void memcpyFromLEnd32(Q_UINT32* dst,const char* src){
if(QSysInfo::ByteOrder==QSysInfo::BigEndian){
memcpy(((char*)dst)+3,src+0,1);
@@ -1149,7 +1162,7 @@ else
memcpy(dst,src,4);
}
-void memcpyFromLEnd16(Q_UINT16* dst,char* src){
+void memcpyFromLEnd16(Q_UINT16* dst,const char* src){
if(QSysInfo::ByteOrder==QSysInfo::BigEndian){
memcpy(((char*)dst)+1,src+0,1);
@@ -1159,7 +1172,7 @@ else
memcpy(dst,src,2);
}
-void memcpyToLEnd32(char* dst,Q_UINT32* src){
+void memcpyToLEnd32(char* dst,const Q_UINT32* src){
if(QSysInfo::ByteOrder==QSysInfo::BigEndian){
memcpy(dst+0,((char*)src)+3,1);
@@ -1171,7 +1184,7 @@ else
memcpy(dst,src,4);
}
-void memcpyToLEnd16(char* dst,Q_UINT16* src){
+void memcpyToLEnd16(char* dst,const Q_UINT16* src){
if(QSysInfo::ByteOrder==QSysInfo::BigEndian){
memcpy(dst+0,((char*)src)+1,1);
diff --git a/src/PwManager.h b/src/PwManager.h
index 4265341..e21b60f 100755
--- a/src/PwManager.h
+++ b/src/PwManager.h
@@ -84,6 +84,7 @@ public:
private:
bool IsMetaStream(CEntry& Entry);
bool parseMetaStream(const CEntry& Entry);
+ bool parseCustomIconsMetaStream(const QByteArray& data);
void transformKey(Q_UINT8* src,Q_UINT8* dst,Q_UINT8* seed,int rounds);
bool readHeader(char* raw);
bool isGroupIdInUse(Q_UINT32 GroupID);
@@ -98,10 +99,10 @@ private:
extern const QDateTime Date_Never;
- void memcpyFromLEnd32(Q_UINT32* dst,char* src);
- void memcpyFromLEnd16(Q_UINT16* dst,char* src);
- void memcpyToLEnd32(char* src,Q_UINT32* dst);
- void memcpyToLEnd16(char* src,Q_UINT16* dst);
+ void memcpyFromLEnd32(Q_UINT32* dst,const char* src);
+ void memcpyFromLEnd16(Q_UINT16* dst,const char* src);
+ void memcpyToLEnd32(char* src,const Q_UINT32* dst);
+ void memcpyToLEnd16(char* src,const Q_UINT16* dst);
QDateTime dateFromPackedStruct5(const unsigned char* pBytes);
void dateToPackedStruct5(const QDateTime& datetime, unsigned char* dst);
diff --git a/src/dialogs/AboutDlg.cpp b/src/dialogs/AboutDlg.cpp
index ed0151d..7dfae81 100755
--- a/src/dialogs/AboutDlg.cpp
+++ b/src/dialogs/AboutDlg.cpp
@@ -49,6 +49,7 @@ http://keepass.berlios.de/translation-howto.html"));
QString ThanksTemplate=QString("
%1
%2
");
Edit_Thanks->setText(ThanksTemplate.arg(tr("Matthias Miller")).arg(tr("http://www.outofhanwell.com/
Mac OS X Support")));
+Edit_Thanks->setText(Edit_Thanks->text()+ThanksTemplate.arg(tr("Eugen Gorschenin")).arg(tr("geugen@users.berlios.de
New Website")));
//Edit_Thanks->setText(Edit_Thanks->text()+ThanksTemplate.arg(tr(" ")).arg(tr(" ")));
}
diff --git a/src/dialogs/EditGroupDlg.cpp b/src/dialogs/EditGroupDlg.cpp
index bc1a2c9..43054da 100755
--- a/src/dialogs/EditGroupDlg.cpp
+++ b/src/dialogs/EditGroupDlg.cpp
@@ -22,18 +22,20 @@
#include
#include
-//Added by qt3to4:
#include
#include "EditGroupDlg.h"
+#include "SelectIconDlg.h"
-CEditGroupDialog::CEditGroupDialog(QWidget* parent, const char* name, bool modal, Qt::WFlags fl)
+CEditGroupDialog::CEditGroupDialog(Database* database,QWidget* parent, const char* name, bool modal, Qt::WFlags fl)
: QDialog(parent,name, modal,fl)
{
setupUi(this);
+db=database;
IconID=0;
connect( ButtonOK, SIGNAL( clicked() ), this, SLOT( OnOK() ) );
connect( ButtonCancel, SIGNAL( clicked() ), this, SLOT( OnCancel() ) );
+connect( Button_Icon, SIGNAL( clicked() ), this, SLOT( OnIconDlg() ));
}
CEditGroupDialog::~CEditGroupDialog()
@@ -62,10 +64,7 @@ done(0);
}
-
-
-/*$SPECIALIZATION$*/
-
-
-//#include "editgroupdlg.moc"
-
+void CEditGroupDialog::OnIconDlg(){
+CSelectIconDlg dlg(db,this);
+dlg.exec();
+}
diff --git a/src/dialogs/EditGroupDlg.h b/src/dialogs/EditGroupDlg.h
index 84bb4ee..25490e2 100755
--- a/src/dialogs/EditGroupDlg.h
+++ b/src/dialogs/EditGroupDlg.h
@@ -23,33 +23,28 @@
#include "ui_EditGroupDlg.h"
#include
-//Added by qt3to4:
#include
+#include "Database.h"
class CEditGroupDialog : public QDialog, public Ui_EditGroupDialog
{
Q_OBJECT
public:
- CEditGroupDialog(QWidget* parent = 0, const char* name = 0, bool modal = FALSE, Qt::WFlags fl = 0 );
+ CEditGroupDialog(Database*,QWidget* parent = 0, const char* name = 0, bool modal = FALSE, Qt::WFlags fl = 0 );
~CEditGroupDialog();
virtual void showEvent(QShowEvent *event);
- /*$PUBLIC_FUNCTIONS$*/
-
-protected:
- /*$PROTECTED_FUNCTIONS$*/
-
-protected slots:
- /*$PROTECTED_SLOTS$*/
-
-public:
int IconID;
QString GroupName;
+
+private:
+ Database* db;
public slots:
virtual void OnOK();
virtual void OnCancel();
+ virtual void OnIconDlg();
};
#endif
diff --git a/src/dialogs/PasswordGenDlg.cpp b/src/dialogs/PasswordGenDlg.cpp
index 2cff913..701b7dd 100755
--- a/src/dialogs/PasswordGenDlg.cpp
+++ b/src/dialogs/PasswordGenDlg.cpp
@@ -31,7 +31,7 @@ CGenPwDialog::CGenPwDialog(QWidget* parent, const char* name, bool modal, Qt::WF
: QDialog(parent,name, modal,fl)
{
setupUi(this);
-createBanner(Banner,Icon_Key32x32,QString::fromUtf8("Passwort generieren"));
+createBanner(Banner,Icon_Key32x32,QString::fromUtf8("Password Generator"));
Radio_1->setChecked(true);
Edit_chars->setDisabled(true);
connect(ButtonGenerate,SIGNAL(clicked()),this,SLOT(OnGeneratePw()));
diff --git a/src/dialogs/SelectIconDlg.cpp b/src/dialogs/SelectIconDlg.cpp
new file mode 100644
index 0000000..29cc1ac
--- /dev/null
+++ b/src/dialogs/SelectIconDlg.cpp
@@ -0,0 +1,30 @@
+/***************************************************************************
+ * Copyright (C) 2005-2006 by Tarek Saidi *
+ * tarek.saidi@arcor.de *
+ * *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "SelectIconDlg.h"
+
+
+CSelectIconDlg::CSelectIconDlg(Database* database,QWidget* parent,const char* name, bool modal, Qt::WFlags fl):QDialog(parent,name,modal,fl){
+setupUi(this);
+db=database;
+for(int i=0; iaddItem(new QListWidgetItem(QIcon(EntryIcons[i]),QString::number(i)));
+}
+}
\ No newline at end of file
diff --git a/src/dialogs/SelectIconDlg.h b/src/dialogs/SelectIconDlg.h
new file mode 100644
index 0000000..f0134db
--- /dev/null
+++ b/src/dialogs/SelectIconDlg.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * Copyright (C) 2005-2006 by Tarek Saidi *
+ * tarek.saidi@arcor.de *
+ * *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef _SELECT_ICON_DLG_
+#define _SELECT_ICON_DLG_
+
+#include "main.h"
+#include "Database.h"
+#include "ui_SelectIconDlg.h"
+
+class CSelectIconDlg:public QDialog, public Ui_SelectIconDlg{
+ Q_OBJECT
+public:
+ CSelectIconDlg(Database* db,QWidget* parent = 0, const char* name = 0, bool modal = false, Qt::WFlags fl = 0);
+
+private:
+ Database* db;
+
+
+};
+
+
+#endif
\ No newline at end of file
diff --git a/src/forms/EditGroupDlg.ui b/src/forms/EditGroupDlg.ui
index 95a1ace..8fac5e2 100644
--- a/src/forms/EditGroupDlg.ui
+++ b/src/forms/EditGroupDlg.ui
@@ -1,133 +1,151 @@
-
- Tarek Saidi
-
-
- EditGroupDialog
-
-
-
- 0
- 0
- 302
- 105
-
-
-
-
- 200
- 105
-
-
-
-
- 302
- 100
-
-
-
- Group Properties
-
-
-
-
- 10
- 62
- 290
- 16
-
-
-
- QFrame::HLine
-
-
- QFrame::Sunken
-
-
-
-
-
- 70
- 10
- 230
- 21
-
-
-
-
-
-
- 10
- 10
- 27
- 20
-
-
-
- Title:
-
-
-
-
-
- 10
- 40
- 43
- 20
-
-
-
- Icon:
-
-
-
-
-
- 70
- 40
- 50
- 21
-
-
-
-
-
-
- 226
- 80
- 70
- 20
-
-
-
- &Cancel
-
-
- Alt+C
-
-
-
-
-
- 147
- 80
- 70
- 20
-
-
-
- O&K
-
-
- Alt+K
-
-
+
+ Tarek Saidi
+
+
+ EditGroupDialog
+
+
+
+ 0
+ 0
+ 302
+ 105
+
+
+
+
+ 200
+ 105
+
+
+
+
+ 302
+ 100
+
+
+
+ Group Properties
+
+
+
+
+ 70
+ 10
+ 230
+ 21
+
+
-
- qPixmapFromMimeSource
-
- EditTitle
- ComboIconPicker
- ButtonOK
- ButtonCancel
-
+
+
+
+ 10
+ 10
+ 27
+ 20
+
+
+
+ Title:
+
+
+
+
+
+ 10
+ 40
+ 43
+ 20
+
+
+
+ Icon:
+
+
+
+
+
+ 70
+ 40
+ 50
+ 21
+
+
+
+
+
+
+ 227
+ 77
+ 70
+ 24
+
+
+
+ &Cancel
+
+
+ Alt+C
+
+
+
+
+
+ 10
+ 62
+ 290
+ 16
+
+
+
+ QFrame::HLine
+
+
+ QFrame::Sunken
+
+
+ Qt::Horizontal
+
+
+
+
+
+ 147
+ 77
+ 70
+ 24
+
+
+
+ O&K
+
+
+ Alt+K
+
+
+
+
+
+ 123
+ 39
+ 21
+ 24
+
+
+
+ >
+
+
+
+
+ qPixmapFromMimeSource
+
+ EditTitle
+ ComboIconPicker
+ ButtonOK
+ ButtonCancel
+
+
+
diff --git a/src/forms/SelectIconDlg.ui b/src/forms/SelectIconDlg.ui
new file mode 100644
index 0000000..eb3ed9c
--- /dev/null
+++ b/src/forms/SelectIconDlg.ui
@@ -0,0 +1,147 @@
+
+
+
+
+ SelectIconDlg
+
+
+
+ 0
+ 0
+ 468
+ 272
+
+
+
+ Dialog
+
+
+
+
+ 10
+ 10
+ 451
+ 211
+
+
+
+ Qt::ScrollBarAlwaysOff
+
+
+ QAbstractItemView::ExtendedSelection
+
+
+
+ 16
+ 16
+
+
+
+ Qt::ElideRight
+
+
+ QListView::Static
+
+
+ QListView::LeftToRight
+
+
+
+ 32
+ 44
+
+
+
+ QListView::IconMode
+
+
+
+
+
+ 10
+ 230
+ 451
+ 33
+
+
+
+
+ 0
+
+
+ 6
+
+ -
+
+
+ Add Custom Icon...
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 131
+ 31
+
+
+
+
+ -
+
+
+ Pick
+
+
+
+ -
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+
+ Button_Ok
+ clicked()
+ SelectIconDlg
+ accept()
+
+
+ 278
+ 253
+
+
+ 96
+ 254
+
+
+
+
+ Button_Cancel
+ clicked()
+ SelectIconDlg
+ reject()
+
+
+ 369
+ 253
+
+
+ 179
+ 282
+
+
+
+
+
diff --git a/src/main.cpp b/src/main.cpp
index b0fa778..591aec7 100755
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2005 by Tarek Saidi *
+ * Copyright (C) 2005-2006 by Tarek Saidi *
* tarek@linux *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -282,7 +282,7 @@ int i=1;
i++; }
for(i; i
#include
-#define KEEPASS_VERSION "0.2.0"
+#define KEEPASS_VERSION "0.2.1"
#define NUM_CLIENT_ICONS 62
typedef enum tKeyType {PASSWORD=0,KEYFILE=1,BOTH=2};
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 8a9c00c..ab7fcd4 100755
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -278,7 +278,7 @@ StatusBarGeneral->setText(tr("Loading Database..."));
if(db->openDatabase(filename,err)==true){
//SUCCESS
if(config.OpenLast)config.LastFile=filename;
-setCaption(tr("Keepass - %1").arg(filename));
+setCaption(tr("KeePassX - %1").arg(filename));
GroupView->updateItems();
EntryView->updateItems(0);
setStateFileOpen(true);
@@ -764,7 +764,7 @@ if(GroupView->selectedItems().size())
pNew=db->addGroup(static_cast(GroupView->selectedItems()[0])->pGroup);
else
pNew=db->addGroup(NULL);
-CEditGroupDialog dlg(this,"EditGroupDlg",true);
+CEditGroupDialog dlg(db,this,"EditGroupDlg",true);
if(!dlg.exec()){
db->deleteGroup(pNew);
return;
@@ -778,7 +778,7 @@ GroupView->updateItems();
void KeepassMainWindow::OnEditEditGroup(){
Q_ASSERT(GroupView->selectedItems().size());
CGroup *pGroup=static_cast(GroupView->selectedItems()[0])->pGroup;
-CEditGroupDialog dlg(this,"EditGroupDlg",true);
+CEditGroupDialog dlg(db,this,"EditGroupDlg",true);
dlg.GroupName=pGroup->Name;
dlg.IconID=pGroup->ImageID;
if(!dlg.exec())return;
diff --git a/src/src.pro b/src/src.pro
index 0889bc8..6f184d1 100755
--- a/src/src.pro
+++ b/src/src.pro
@@ -3,15 +3,24 @@
# Unterordner relativ zum Projektordner: ./src
# Das Target ist eine Anwendung: ../bin/keepass
-INSTALLS += target \
- Share
-Share.files += ../share/keepass/*
-unix{ target.path = /usr/local/bin
- Share.path = /usr/local/share/keepass
+
+INSTALLS += target data
+data.files += ../share/keepass/*
+TARGET = ../bin/keepass
+
+unix{
+ isEmpty(PREFIX){
+ PREFIX=/usr/local
+ }
+ target.path = $${PREFIX}/bin
+ data.path = $${PREFIX}/share/keepass
}
-macx{ target.path = /Applications
- Share.path = /Applications/keepass.app/Contents/share/keepass
+
+macx{
+ target.path = /Applications
+ data.path = /Applications/keepass.app/Contents/share/keepass
}
+
FORMS += forms/EditGroupDlg.ui \
forms/SearchDlg.ui \
forms/AboutDlg.ui \
@@ -21,7 +30,8 @@ FORMS += forms/EditGroupDlg.ui \
forms/DatabaseSettingsDlg.ui \
forms/PasswordDlg.ui \
forms/EditEntryDlg.ui \
- forms/PasswordGenDlg.ui
+ forms/PasswordGenDlg.ui \
+ forms/SelectIconDlg.ui
TRANSLATIONS += translations/keepass-de_DE.ts \
translations/keepass-ru_RU.ts \
translations/keepass-es_ES.ts \
@@ -50,6 +60,7 @@ HEADERS += lib/IniReader.h \
dialogs/SimplePasswordDlg.h \
dialogs/EditEntryDlg.h \
dialogs/PasswordGenDlg.h \
+ dialogs/SelectIconDlg.h \
lib/random.h \
Database.h \
lib/KdePlugin.h \
@@ -84,6 +95,7 @@ SOURCES += lib/IniReader.cpp \
dialogs/SimplePasswordDlg.cpp \
dialogs/EditEntryDlg.cpp \
dialogs/PasswordGenDlg.cpp \
+ dialogs/SelectIconDlg.cpp \
lib/random.cpp \
Database.cpp \
lib/KdePlugin.cpp \
@@ -96,7 +108,6 @@ QT -= network sql
MOC_DIR = ../build/moc
UI_DIR = ../build/ui
OBJECTS_DIR = ../build/
-TARGET = ../bin/keepass
INCLUDEPATH += ./
CONFIG += debug \
warn_off \
diff --git a/todo b/todo
new file mode 100644
index 0000000..eadbea0
--- /dev/null
+++ b/todo
@@ -0,0 +1,2 @@
+- remember selection states after add/remove actions
+- menu 'View': option for toolbar icons size
\ No newline at end of file