completed drag&drop stuff,

moved column configuration to QSettings,
improved column handling and resizing behavior,
column order is now remembered after a restart,
added group column.

git-svn-id: https://svn.code.sf.net/p/keepassx/code/trunk@127 b624d157-de02-0410-bad0-e51aec6abb33
master
tarek_saidi 17 years ago
parent 11b33969d8
commit 6cae658d24
  1. 129
      src/forms/MainWindow.ui
  2. 432
      src/lib/EntryView.cpp
  3. 14
      src/lib/EntryView.h
  4. 72
      src/lib/GroupView.cpp
  5. 10
      src/lib/GroupView.h
  6. 63
      src/mainwindow.cpp
  7. 2
      src/mainwindow.h

@ -115,6 +115,50 @@
<height>29</height>
</rect>
</property>
<widget class="QMenu" name="menuHilfe" >
<property name="title" >
<string>&amp;Help</string>
</property>
<addaction name="HelpHandbookAction" />
<addaction name="separator" />
<addaction name="HelpAboutAction" />
</widget>
<widget class="QMenu" name="menuExtras" >
<property name="title" >
<string>E&amp;xtras</string>
</property>
<addaction name="ExtrasSettingsAction" />
<addaction name="ExtrasPasswordGenAction" />
</widget>
<widget class="QMenu" name="menuDatei" >
<property name="title" >
<string>&amp;File</string>
</property>
<widget class="QMenu" name="menuExport" >
<property name="title" >
<string>&amp;Export to...</string>
</property>
</widget>
<widget class="QMenu" name="menuImport" >
<property name="title" >
<string>&amp;Import from...</string>
</property>
</widget>
<addaction name="FileNewAction" />
<addaction name="FileOpenAction" />
<addaction name="FileCloseAction" />
<addaction name="separator" />
<addaction name="FileSaveAction" />
<addaction name="FileSaveAsAction" />
<addaction name="separator" />
<addaction name="FileSettingsAction" />
<addaction name="FileChangeKeyAction" />
<addaction name="separator" />
<addaction name="menuImport" />
<addaction name="menuExport" />
<addaction name="separator" />
<addaction name="FileExitAction" />
</widget>
<widget class="QMenu" name="menuBearbeiten" >
<property name="title" >
<string>&amp;Edit</string>
@ -141,10 +185,20 @@
<property name="title" >
<string>&amp;View</string>
</property>
<widget class="QMenu" name="menuSpalten" >
<widget class="QMenu" name="menuTool_Button_Sizes" >
<property name="title" >
<string>Toolbar Icon Size</string>
</property>
<addaction name="ViewToolButtonSize16Action" />
<addaction name="ViewToolButtonSize22Action" />
<addaction name="ViewToolButtonSize28Action" />
</widget>
<widget class="QMenu" name="menuColumns" >
<property name="title" >
<string>Columns</string>
</property>
<addaction name="ViewColumnsGroupAction" />
<addaction name="separator" />
<addaction name="ViewColumnsTitleAction" />
<addaction name="ViewColumnsUsernameAction" />
<addaction name="ViewColumnsUrlAction" />
@ -157,67 +211,15 @@
<addaction name="ViewColumnsLastAccessAction" />
<addaction name="ViewColumnsAttachmentAction" />
</widget>
<widget class="QMenu" name="menuTool_Button_Sizes" >
<property name="title" >
<string>Toolbar Icon Size</string>
</property>
<addaction name="ViewToolButtonSize16Action" />
<addaction name="ViewToolButtonSize22Action" />
<addaction name="ViewToolButtonSize28Action" />
</widget>
<addaction name="ViewShowEntryDetailsAction" />
<addaction name="ViewShowStatusbarAction" />
<addaction name="separator" />
<addaction name="ViewHideUsernamesAction" />
<addaction name="ViewHidePasswordsAction" />
<addaction name="separator" />
<addaction name="menuSpalten" />
<addaction name="menuColumns" />
<addaction name="menuTool_Button_Sizes" />
</widget>
<widget class="QMenu" name="menuHilfe" >
<property name="title" >
<string>&amp;Help</string>
</property>
<addaction name="HelpHandbookAction" />
<addaction name="separator" />
<addaction name="HelpAboutAction" />
</widget>
<widget class="QMenu" name="menuExtras" >
<property name="title" >
<string>E&amp;xtras</string>
</property>
<addaction name="ExtrasSettingsAction" />
<addaction name="ExtrasPasswordGenAction" />
</widget>
<widget class="QMenu" name="menuDatei" >
<property name="title" >
<string>&amp;File</string>
</property>
<widget class="QMenu" name="menuExport" >
<property name="title" >
<string>&amp;Export to...</string>
</property>
</widget>
<widget class="QMenu" name="menuImport" >
<property name="title" >
<string>&amp;Import from...</string>
</property>
</widget>
<addaction name="FileNewAction" />
<addaction name="FileOpenAction" />
<addaction name="FileCloseAction" />
<addaction name="separator" />
<addaction name="FileSaveAction" />
<addaction name="FileSaveAsAction" />
<addaction name="separator" />
<addaction name="FileSettingsAction" />
<addaction name="FileChangeKeyAction" />
<addaction name="separator" />
<addaction name="menuImport" />
<addaction name="menuExport" />
<addaction name="separator" />
<addaction name="FileExitAction" />
</widget>
<addaction name="menuDatei" />
<addaction name="menuBearbeiten" />
<addaction name="ViewMenu" />
@ -505,17 +507,28 @@
<string>Password Generator...</string>
</property>
</action>
<action name="ViewColumnsGroupAction" >
<property name="checkable" >
<bool>true</bool>
</property>
<property name="checked" >
<bool>true</bool>
</property>
<property name="text" >
<string>Group (search results only)</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>KeepassEntryView</class>
<class>KeepassGroupView</class>
<extends>QTreeWidget</extends>
<header>../../src/lib/EntryView.h</header>
<header>../../src/lib/GroupView.h</header>
</customwidget>
<customwidget>
<class>KeepassGroupView</class>
<class>KeepassEntryView</class>
<extends>QTreeWidget</extends>
<header>../../src/lib/GroupView.h</header>
<header>../../src/lib/EntryView.h</header>
</customwidget>
</customwidgets>
<resources/>

@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2005-2006 by Tarek Saidi *
* Copyright (C) 2005-2007 by Tarek Saidi *
* tarek.saidi@arcor.de *
* *
* This program is free software; you can redistribute it and/or modify *
@ -36,31 +36,71 @@
#include "lib/AutoType.h"
// just for the lessThan funtion
QList<EntryViewItem*>* pItems;
KeepassEntryView* pEntryView;
KeepassEntryView::KeepassEntryView(QWidget* parent):QTreeWidget(parent){
AutoResizeColumns=true;
int sum=0;
for(int i=0;i<NUM_COLUMNS;i++)
sum+=config.ColumnSizes[i];
for(int i=0;i<NUM_COLUMNS;i++)
ColumnSizes << (float)config.ColumnSizes[i]/(float)sum;
updateColumns();
AutoResizeColumns=true;
header()->setResizeMode(QHeaderView::Interactive);
header()->setStretchLastSection(false);
header()->setClickable(true);
header()->setCascadingSectionResizes(true);
ColumnSizes.resize(NUM_COLUMNS);
QStringList ColumnSizeConfig=settings->value("Ui/ColumnSizes",QStringList()<<"1"<<"1"<<"1"<<"1"<<"1"<<"1"<<"1"<<"1"<<"1"<<"1"<<"1").toStringList();
for(int i=0;i<NUM_COLUMNS;i++)
ColumnSizes[i]=(float)ColumnSizeConfig[i].toInt();
QStringList DefaultColumnConfig=QStringList()<<"1"<<"1"<<"1"<<"1"<<"1"<<"0"<<"0"<<"0"<<"0"<<"0"<<"1";
QStringList ColumnConfig=settings->value("Ui/ShowColumns",DefaultColumnConfig).toStringList();
Columns.resize(NUM_COLUMNS);
if(ColumnConfig.size()<NUM_COLUMNS)ColumnConfig=DefaultColumnConfig;
for(int i=0;i<ColumnConfig.size();i++){
Columns[i]=(bool)ColumnConfig[i].toInt();
}
ColumnOrder.resize(NUM_COLUMNS);
QStringList ColumnOrderConfig=settings->value("Ui/ColumnOrder",QStringList()<<"100"<<"100"<<"100"<<"100"<<"100"<<"100"<<"100"<<"100"<<"100"<<"100"<<"100").toStringList();
for(int i=0;i<NUM_COLUMNS;i++){
if(i<ColumnOrderConfig.size()){
ColumnOrder[i]=ColumnOrderConfig[i].toInt();
}
else
ColumnOrder[i]=100;
}
updateColumns();
connect(header(),SIGNAL(sectionResized(int,int,int)),this,SLOT(OnColumnResized(int,int,int)));
connect(this,SIGNAL(itemSelectionChanged()),this,SLOT(OnItemsChanged()));
connect(&ClipboardTimer, SIGNAL(timeout()), this, SLOT(OnClipboardTimeOut()));
connect(header(),SIGNAL(sectionClicked(int)),this,SLOT(OnHeaderSectionClicked(int)));
connect(header(),SIGNAL(sectionMoved(int,int,int)),this,SLOT(OnColumnMoved(int,int,int)));
Clipboard=QApplication::clipboard();
ContextMenu=new QMenu(this);
setAlternatingRowColors(config.AlternatingRowColors);
pItems=&Items;
pEntryView=this;
}
KeepassEntryView::~KeepassEntryView(){
QStringList ColumnSizesConfig;
for(int i=0;i<ColumnSizes.size();i++){
config.ColumnSizes[i]=(int)(ColumnSizes[i]*10000.0f);
ColumnSizesConfig<<QString::number((int)(ColumnSizes[i]));
}
settings->setValue("Ui/ColumnSizes",ColumnSizesConfig);
QStringList ColumnConfig;
for(int i=0;i<Columns.size();i++){
if(Columns[i])
ColumnConfig<<"1";
else
ColumnConfig<<"0";
}
settings->setValue("Ui/ShowColumns",ColumnConfig);
QStringList ColumnOrderConfig;
for(int i=0;i<NUM_COLUMNS;i++){
ColumnOrderConfig << QString::number(ColumnOrder[i]);
}
settings->setValue("Ui/ColumnOrder",ColumnOrderConfig);
}
void KeepassEntryView::OnGroupChanged(IGroupHandle* group){
@ -84,6 +124,19 @@ void KeepassEntryView::OnItemsChanged(){
}
}
bool sortSearchResultsLessThan(const IEntryHandle* a, const IEntryHandle* b){
int indexA=0;
int indexB=0;
for(indexA;indexA<pItems->size();indexA++){
if((*pItems)[indexA]->EntryHandle==a)break;
}
for(indexB;indexB<pItems->size();indexB++){
if((*pItems)[indexB]->EntryHandle==b)break;
}
return pEntryView->indexOfTopLevelItem((*pItems)[indexA])<pEntryView->indexOfTopLevelItem((*pItems)[indexB]);
}
void KeepassEntryView::OnHeaderSectionClicked(int index){
if(header()->isSortIndicatorShown() && header()->sortIndicatorSection()==index){
header()->setSortIndicator(index,header()->sortIndicatorOrder() ? Qt::DescendingOrder : Qt::AscendingOrder);
@ -94,9 +147,18 @@ void KeepassEntryView::OnHeaderSectionClicked(int index){
header()->setSortIndicatorShown(true);
sortItems(index,Qt::AscendingOrder);
}
for(int i=0;i<Items.size();i++){
Items[i]->EntryHandle->setVisualIndexDirectly(indexOfTopLevelItem(Items[i]));
if(ViewMode==Normal){
for(int i=0;i<Items.size();i++){
Items[i]->EntryHandle->setVisualIndexDirectly(indexOfTopLevelItem(Items[i]));
}
}
else if(ViewMode==ShowSearchResults){
if(header()->sortIndicatorOrder()==Qt::AscendingOrder)
qSort(SearchResults.begin(),SearchResults.end(),sortSearchResultsLessThan);
else
qSort(SearchResults.end(),SearchResults.begin(),sortSearchResultsLessThan);
}
}
@ -131,14 +193,17 @@ void KeepassEntryView::OnDeleteEntry(){
void KeepassEntryView::updateEntry(EntryViewItem* item){
IEntryHandle* entry = item->EntryHandle;
int j=0;
if(config.Columns[0])item->setText(j++,entry->title());
if(config.Columns[1]){
if(Columns[0]){
item->setText(j++,entry->title());
item->setIcon(0,db->icon(entry->image()));
}
if(Columns[1]){
if(config.ListView_HideUsernames)
item->setText(j++,"******");
else
item->setText(j++,entry->username());}
if(config.Columns[2]){item->setText(j++,entry->url());}
if(config.Columns[3]){
if(Columns[2]){item->setText(j++,entry->url());}
if(Columns[3]){
if(config.ListView_HidePasswords)
item->setText(j++,"******");
else{
@ -147,19 +212,21 @@ void KeepassEntryView::updateEntry(EntryViewItem* item){
item->setText(j++,password.string());
}
}
if(config.Columns[4]){
item->setText(j++,entry->comment().section('\n',0,0));}
if(config.Columns[5]){
item->setText(j++,entry->expire().dateToString(Qt::LocalDate));}
if(config.Columns[6]){
item->setText(j++,entry->creation().dateToString(Qt::LocalDate));}
if(config.Columns[7]){
item->setText(j++,entry->lastMod().dateToString(Qt::LocalDate));}
if(config.Columns[8]){
item->setText(j++,entry->lastAccess().dateToString(Qt::LocalDate));}
if(config.Columns[9]){
item->setText(j++,entry->binaryDesc());}
item->setIcon(0,db->icon(entry->image()));
if(Columns[4]){
item->setText(j++,entry->comment().section('\n',0,0));}
if(Columns[5]){
item->setText(j++,entry->expire().dateToString(Qt::LocalDate));}
if(Columns[6]){
item->setText(j++,entry->creation().dateToString(Qt::LocalDate));}
if(Columns[7]){
item->setText(j++,entry->lastMod().dateToString(Qt::LocalDate));}
if(Columns[8]){
item->setText(j++,entry->lastAccess().dateToString(Qt::LocalDate));}
if(Columns[9]){
item->setText(j++,entry->binaryDesc());}
if(Columns[10]){
item->setText(j,entry->group()->title());
item->setIcon(j++,db->icon(entry->group()->image()));}
}
void KeepassEntryView::editEntry(EntryViewItem* item){
@ -272,13 +339,15 @@ void KeepassEntryView::resizeEvent(QResizeEvent* e){
void KeepassEntryView::showSearchResults(){
ViewMode=ShowSearchResults;
clear();
Items.clear();
createItems(SearchResults);
createItems(SearchResults);
}
void KeepassEntryView::showGroup(IGroupHandle* group){
ViewMode=Normal;
clear();
Items.clear();
if(group==NULL)return;
@ -294,14 +363,16 @@ void KeepassEntryView::createItems(QList<IEntryHandle*>& entries){
Items.push_back(item);
Items.back()->EntryHandle=entries[i];
int j=0;
if(config.Columns[0])item->setText(j++,entries[i]->title());
if(config.Columns[1]){
if(Columns[0]){
item->setText(j++,entries[i]->title());
item->setIcon(0,db->icon(entries[i]->image()));}
if(Columns[1]){
if(config.ListView_HideUsernames)
item->setText(j++,"******");
else
item->setText(j++,entries[i]->username());}
if(config.Columns[2]){item->setText(j++,entries[i]->url());}
if(config.Columns[3]){
if(Columns[2]){item->setText(j++,entries[i]->url());}
if(Columns[3]){
if(config.ListView_HidePasswords)
item->setText(j++,"******");
else{
@ -310,20 +381,21 @@ void KeepassEntryView::createItems(QList<IEntryHandle*>& entries){
item->setText(j++,password.string());
}
}
if(config.Columns[4]){
if(Columns[4]){
item->setText(j++,entries[i]->comment().section('\n',0,0));}
if(config.Columns[5]){
if(Columns[5]){
item->setText(j++,entries[i]->expire().dateToString(Qt::LocalDate));}
if(config.Columns[6]){
if(Columns[6]){
item->setText(j++,entries[i]->creation().dateToString(Qt::LocalDate));}
if(config.Columns[7]){
if(Columns[7]){
item->setText(j++,entries[i]->lastMod().dateToString(Qt::LocalDate));}
if(config.Columns[8]){
if(Columns[8]){
item->setText(j++,entries[i]->lastAccess().dateToString(Qt::LocalDate));}
if(config.Columns[9]){
if(Columns[9]){
item->setText(j++,entries[i]->binaryDesc());}
Items.back()->setIcon(0,db->icon(entries[i]->image()));
qDebug("%s : %i",entries[i]->title().toUtf8().data(),entries[i]->visualIndex());
if(Columns[10]){
item->setText(j,entries[i]->group()->title());
item->setIcon(j++,db->icon(entries[i]->group()->image()));}
}
}
@ -337,205 +409,163 @@ void KeepassEntryView::updateIcons(){
void KeepassEntryView::setEntry(IEntryHandle* entry){
}
/*
void KeepassEntryView::refreshItems(){
EntryViewItem *tmp=NULL;
for(int i=0;i<Items.size();i++){
tmp=Items[i];
IEntryHandle* entry=tmp->pEntry;
int j=0;
if(config.Columns[0]){
tmp->setText(j++,entry->Title);}
if(config.Columns[1]){
if(config.ListView_HideUsernames)
tmp->setText(j++,"******");
else
tmp->setText(j++,entry->UserName);}
if(config.Columns[2]){
tmp->setText(j++,entry->URL);}
if(config.Columns[3]){
if(config.ListView_HidePasswords)
tmp->setText(j++,"******");
else{
entry->Password.unlock();
tmp->setText(j++,entry->Password.string());
entry->Password.lock();}}
if(config.Columns[4]){
tmp->setText(j++,entry->Additional.section('\n',0,0));}
if(config.Columns[5]){
tmp->setText(j++,entry->Expire.dateToString(Qt::LocalDate));}
if(config.Columns[6]){
tmp->setText(j++,entry->Creation.dateToString(Qt::LocalDate));}
if(config.Columns[7]){
tmp->setText(j++,entry->LastMod.dateToString(Qt::LocalDate));}
if(config.Columns[8]){
tmp->setText(j++,entry->LastAccess.dateToString(Qt::LocalDate));}
if(config.Columns[9]){
tmp->setText(j++,entry->BinaryDesc);}
tmp->setIcon(0,db->icon(entry->ImageID));
}
}*/
void KeepassEntryView::updateColumns(){
setColumnCount(0);
QStringList cols;
if(config.Columns[0]){
if(Columns[0]){
cols << tr("Title");}
if(config.Columns[1]){
if(Columns[1]){
cols << tr("Username");}
if(config.Columns[2]){
if(Columns[2]){
cols << tr("URL");}
if(config.Columns[3]){
if(Columns[3]){
cols << tr("Password");}
if(config.Columns[4]){
if(Columns[4]){
cols << tr("Comments");}
if(config.Columns[5]){
if(Columns[5]){
cols << tr("Expires");}
if(config.Columns[6]){
if(Columns[6]){
cols << tr("Creation");}
if(config.Columns[7]){
if(Columns[7]){
cols << tr("Last Change");}
if(config.Columns[8]){
if(Columns[8]){
cols << tr("Last Access");}
if(config.Columns[9]){
if(Columns[9]){
cols << tr("Attachment");}
if(Columns[10]){
cols << tr("Group");}
setHeaderLabels(cols);
resizeColumns();
}
void KeepassEntryView::resizeColumns(){
AutoResizeColumns=false;
if(!header()->count())return;
for(int i=0;i<NUM_COLUMNS;i++)
if(!config.Columns[i])ColumnSizes[i]=0;
for(int i=0;i<NUM_COLUMNS;i++)
if(config.Columns[i] && ColumnSizes[i]==0)ColumnSizes[i]=0.1f;
float sum=0;
for(int i=0;i<NUM_COLUMNS;i++)
sum+=ColumnSizes[i];
for(int i=0;i<NUM_COLUMNS;i++)
ColumnSizes[i]/=sum;
int w=viewport()->width();
int wx=0; int j=0;
for(int i=0;i<NUM_COLUMNS;i++){
if(!config.Columns[i])continue;
int NewWidth=(int)(ColumnSizes[i]*(float)w);
wx+=NewWidth;
header()->resizeSection(j++,NewWidth);
//add rounding difference (w-wx) to the last column
if(j==header()->count()){
header()->resizeSection(j-1,header()->sectionSize(j-1)+(w-wx));
QMap<int,int> Order;
for(int i=NUM_COLUMNS-1;i>=0;i--)
Order.insertMulti(ColumnOrder[i],i);
QMapIterator<int, int> i(Order);
while (i.hasNext()) {
i.next();
int index=i.value();
if(!Columns[index])continue;
header()->moveSection(header()->visualIndex(logicalColIndex(index)),header()->count()-1);
}
}
AutoResizeColumns=true;
resizeColumns();
}
void KeepassEntryView::OnColumnMoved(int LogIndex,int OldVisIndex,int NewVisIndex){
for(int i=0;i<header()->count();i++){
ColumnOrder[columnListIndex(header()->logicalIndex(i))]=i;
}
}
void KeepassEntryView::OnColumnResized(int index,int Old, int New){
if(!AutoResizeColumns)return;
int i=0; int c=-1;
for(i;i<ColumnSizes.size();i++){
if(config.Columns[i])c++;
if(c==index)break;
int KeepassEntryView::logicalColIndex(int LstIndex){
qDebug("%i",LstIndex);
int c=-1;
for(int i=0;i<NUM_COLUMNS;i++){
if(Columns[i])c++;
if(i==LstIndex)return c;
}
Q_ASSERT(false);
}
int j=0; c=-1; bool IsLastColumn=true;
for(j;j<ColumnSizes.size();j++){
if(config.Columns[j])c++;
if(c==(index+1)){IsLastColumn=false; break;}
void KeepassEntryView::resizeColumns(){
AutoResizeColumns=false;
int w=viewport()->width();
int sum=0;
for(int i=0;i<header()->count();i++){
sum+=ColumnSizes[columnListIndex(i)];
}
float stretch=((float)w)/((float)sum);
sum=0;
for(int i=0;i<header()->count();i++){
int lstIndex=columnListIndex(header()->logicalIndex(i));
int NewSize=qRound(stretch*(float)ColumnSizes[lstIndex]);
sum+=NewSize;
if(i==header()->count()-1){
NewSize+=(w-sum); // add rounding difference to the last column
}
//qDebug("i=%i lstIndex=%i NewSize=%f",i,lstIndex,NewSize);
header()->resizeSection(header()->logicalIndex(i),NewSize);
ColumnSizes[lstIndex]=NewSize;
}
AutoResizeColumns=true;
}
if(IsLastColumn){
j=0; c=-1;
for(j;j<ColumnSizes.size();j++){
if(config.Columns[j])c++;
if(c==(index-1))break;
int KeepassEntryView::columnListIndex(int LogicalIndex){
int c=-1; int i=0;
for(i;i<NUM_COLUMNS;i++){
if(Columns[i])c++;
if(c==LogicalIndex)break;
}
return i;
}
int w=viewport()->width();
float div=(float)(New-Old)/(float)w;
if(((ColumnSizes[j]-div)*w > 2)){
ColumnSizes[j]-=div;
ColumnSizes[i]+=div;
}
resizeColumns();
void KeepassEntryView::OnColumnResized(int lindex,int Old, int New){
if(!AutoResizeColumns)return;
for(int i=0;i<header()->count();i++){
ColumnSizes[columnListIndex(i)]=header()->sectionSize(i);
}
resizeColumns();
}
void KeepassEntryView::mousePressEvent(QMouseEvent *event){
//save event position - maybe this is the start of a drag
if (event->button() == Qt::LeftButton)
DragStartPos = event->pos();
//call base function
QTreeWidget::mousePressEvent(event);
}
void KeepassEntryView::mouseMoveEvent(QMouseEvent *event){
/*
if(IsSearchGroup)
return;
if (!(event->buttons() & Qt::LeftButton))
return;
if ((event->pos() - DragStartPos).manhattanLength() < QApplication::startDragDistance())
return;
DragItems.clear();
EntryViewItem* DragStartItem=(EntryViewItem*)itemAt(DragStartPos);
if(!DragStartItem){
while(selectedItems().size()){
setItemSelected(selectedItems()[0],false);}
return;
}
if(selectedItems().size()==0){
setItemSelected(DragStartItem,true);}
else{
bool AlreadySelected=false;
for(int i=0;i<selectedItems().size();i++){
if(selectedItems()[i]==DragStartItem){AlreadySelected=true; break;}
}
if(!AlreadySelected){
if (!(event->buttons() & Qt::LeftButton))
return;
if ((event->pos() - DragStartPos).manhattanLength() < QApplication::startDragDistance())
return;
DragItems.clear();
EntryViewItem* DragStartItem=(EntryViewItem*)itemAt(DragStartPos);
if(!DragStartItem){
while(selectedItems().size()){
setItemSelected(selectedItems()[0],false);
setItemSelected(selectedItems()[0],false);}
return;
}
if(selectedItems().size()==0){
setItemSelected(DragStartItem,true);}
else{
bool AlreadySelected=false;
for(int i=0;i<selectedItems().size();i++){
if(selectedItems()[i]==DragStartItem){AlreadySelected=true; break;}
}
if(!AlreadySelected){
while(selectedItems().size()){
setItemSelected(selectedItems()[0],false);
}
setItemSelected(DragStartItem,true);
}
setItemSelected(DragStartItem,true);
}
}
DragItems=selectedItems();
QDrag *drag = new QDrag(this);
QFontMetrics fontmet(DragStartItem->font(0));
int DragPixmHeight=16;
if(fontmet.height()>16)DragPixmHeight=fontmet.height();
QString DragText;
if(DragItems.size()>1)DragText=QString(tr("%1 items")).arg(DragItems.size());
else DragText=((EntryViewItem*)DragItems[0])->pEntry->Title;
DragPixmap = QPixmap(fontmet.width(DragText)+19,DragPixmHeight);
DragPixmap.fill(QColor(255,255,255));
QPainter painter(&DragPixmap);
painter.setPen(QColor(0,0,0));
painter.setFont(DragItems[0]->font(0));
painter.drawPixmap(0,0,DragItems[0]->icon(0).pixmap(QSize(16,16)));
painter.drawText(19,DragPixmHeight-fontmet.strikeOutPos(),DragText);
QMimeData *mimeData = new QMimeData;
void* pDragItems=&DragItems;
mimeData->setData("keepass/entry",QByteArray((char*)&pDragItems,sizeof(void*)));
drag->setMimeData(mimeData);
drag->setPixmap(DragPixmap);
drag->start();
*/
DragItems=selectedItems();
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
void* pDragItems=&DragItems;
mimeData->setData("text/plain;charset=UTF-8",DragItems[0]->text(0).toUtf8());
mimeData->setData("application/x-keepassx-entry",QByteArray((char*)&pDragItems,sizeof(void*)));
drag->setMimeData(mimeData);
drag->setPixmap(DragPixmap);
drag->start();
}
void KeepassEntryView::removeDragItems(){
for(int i=0;i<DragItems.size();i++){
for(int j=0;j<Items.size();j++){
if(Items[j]==DragItems[i]){
Items.removeAt(j);
j--;
delete DragItems[i];
}
}
}
}
void KeepassEntryView::OnAutoType(){
@ -568,7 +598,7 @@ EntryViewItem::EntryViewItem(QTreeWidgetItem *parent, QTreeWidgetItem *preceding
bool EntryViewItem::operator<(const QTreeWidgetItem& other)const{
int SortCol=treeWidget()->sortColumn();
if(SortCol < 5 || SortCol==9){ //columns with string values (Title, Username, Password, URL, Comment)
if(SortCol < 5 || SortCol==9 || SortCol==10){ //columns with string values (Title, Username, Password, URL, Comment, Group)
if(QString::localeAwareCompare(text(SortCol),other.text(SortCol)) < 0)
return true;
else

@ -27,9 +27,10 @@
#include <QHeaderView>
#include <QTimer>
#include <QClipboard>
#include <QVarLengthArray>
#include "../StandardDatabase.h"
#define NUM_COLUMNS 10
#define NUM_COLUMNS 11
class EntryViewItem;
enum SelectionState{NONE,SINGLE,MULTIPLE,SEARCHGROUP};
@ -42,26 +43,31 @@ class KeepassEntryView:public QTreeWidget{
void showSearchResults();
void showGroup(IGroupHandle* group);
void updateColumns();
// void showSearchResults(QList<quint32>& results);
IDatabase* db;
QList<EntryViewItem*>Items;
QList<IEntryHandle*> SearchResults;
QMenu *ContextMenu;
QVarLengthArray<bool>Columns;
private:
void setEntry(IEntryHandle* entry);
void updateEntry(EntryViewItem*);
void editEntry(EntryViewItem*);
void createItems(QList<IEntryHandle*>& entries);
int columnListIndex(int LogicalIndex);
int logicalColIndex(int ListIndex);
QClipboard* Clipboard;
QTimer ClipboardTimer;
QList<float>ColumnSizes;
void resizeColumns();
bool AutoResizeColumns;
QPoint DragStartPos;
QList<QTreeWidgetItem*> DragItems;
QPixmap DragPixmap;
IGroupHandle* CurrentGroup;
enum EntryViewMode {Normal, ShowSearchResults};
EntryViewMode ViewMode;
QVarLengthArray<float>ColumnSizes;
QVarLengthArray<int>ColumnOrder;
virtual void contextMenuEvent(QContextMenuEvent *event);
virtual void paintEvent(QPaintEvent* event);
@ -85,6 +91,8 @@ class KeepassEntryView:public QTreeWidget{
void OnDeleteEntry();
void OnSaveAttachment();
void OnAutoType();
void removeDragItems();
void OnColumnMoved(int LogIndex,int OldVisIndex,int NewVisIndex);
signals:
void fileModified();
void selectionChanged(SelectionState);

@ -54,6 +54,7 @@ KeepassGroupView::KeepassGroupView(QWidget* parent):QTreeWidget(parent){
void KeepassGroupView::createItems(){
clear();
Items.clear();
InsLinePos=-1;
QList<IGroupHandle*> groups=db->groups();
for(int i=0;i<groups.size();i++){
if(groups[i]->parent()==NULL){
@ -178,7 +179,14 @@ void KeepassGroupView::dragEnterEvent ( QDragEnterEvent * event ){
LastHoverItem=NULL;
InsLinePos=-1;
if(event->mimeData()->hasFormat("application/x-keepassx")){
if(event->mimeData()->hasFormat("application/x-keepassx-group")){
DragType=GroupDrag;
event->accept();
return;
}
if(event->mimeData()->hasFormat("application/x-keepassx-entry")){
DragType=EntryDrag;
memcpy(&EntryDragItems,event->mimeData()->data("application/x-keepassx-entry").data(),sizeof(void*));
event->accept();
return;
}
@ -199,10 +207,39 @@ void KeepassGroupView::dragLeaveEvent ( QDragLeaveEvent * event ){
}
void KeepassGroupView::entryDropEvent( QDropEvent * event ){
if(LastHoverItem){
LastHoverItem->setBackgroundColor(0,QApplication::palette().color(QPalette::Base));
LastHoverItem->setForeground(0,QBrush(QApplication::palette().color(QPalette::Text)));
}
GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos());
if(!Item){
event->ignore();
return;
}
else{
if(Item->GroupHandle==((EntryViewItem*)(*EntryDragItems)[0])->EntryHandle->group())
return;
for(int i=0;i<EntryDragItems->size();i++){
db->moveEntry(((EntryViewItem*)(*EntryDragItems)[i])->EntryHandle,Item->GroupHandle);
}
emit entriesDropped();
emit fileModified();
}
}
void KeepassGroupView::dropEvent( QDropEvent * event ){
if(DragType==EntryDrag){
entryDropEvent(event);
return;
}
if(LastHoverItem){
LastHoverItem->setBackgroundColor(0,QApplication::palette().color(QPalette::Base));
LastHoverItem->setForeground(0,QBrush(QApplication::palette().color(QPalette::Text)));
}
if(InsLinePos!=-1){
int RemoveLine=InsLinePos;
@ -290,7 +327,38 @@ void KeepassGroupView::dropEvent( QDropEvent * event ){
}
void KeepassGroupView::entryDragMoveEvent( QDragMoveEvent * event ){
GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos());
if(!Item){
if(LastHoverItem){
LastHoverItem->setBackgroundColor(0,QApplication::palette().color(QPalette::Base));
LastHoverItem->setForeground(0,QBrush(QApplication::palette().color(QPalette::Text)));
LastHoverItem=NULL;
}
event->ignore();
return;
}
if(LastHoverItem != Item){
if(LastHoverItem){
LastHoverItem->setBackgroundColor(0,QApplication::palette().color(QPalette::Base));
LastHoverItem->setForeground(0,QBrush(QApplication::palette().color(QPalette::Text)));
}
Item->setBackgroundColor(0,QApplication::palette().color(QPalette::Highlight));
Item->setForeground(0,QBrush(QApplication::palette().color(QPalette::HighlightedText)));
LastHoverItem=Item;
}
event->accept();
return;
}
void KeepassGroupView::dragMoveEvent( QDragMoveEvent * event ){
if(DragType==EntryDrag){
entryDragMoveEvent(event);
return;
}
if(DragItem){
GroupViewItem* Item=(GroupViewItem*)itemAt(event->pos());
if(!Item){
@ -393,7 +461,7 @@ void KeepassGroupView::mouseMoveEvent(QMouseEvent *event){
QMimeData *mimeData = new QMimeData;
mimeData->setData("text/plain;charset=UTF-8",DragItem->text(0).toUtf8());
mimeData->setData("application/x-keepassx",QString("drag-type=group").toUtf8());
mimeData->setData("application/x-keepassx-group",QByteArray());
drag->setMimeData(mimeData);
Qt::DropAction dropAction = drag->start(Qt::MoveAction);

@ -40,10 +40,12 @@ class KeepassGroupView:public QTreeWidget{
void showSearchResults();
private:
virtual void dragEnterEvent ( QDragEnterEvent * event );
virtual void dragMoveEvent ( QDragMoveEvent * event );
virtual void dragEnterEvent(QDragEnterEvent* event);
virtual void dragMoveEvent(QDragMoveEvent* event);
void entryDragMoveEvent(QDragMoveEvent* event);
virtual void dragLeaveEvent ( QDragLeaveEvent * event );
virtual void dropEvent ( QDropEvent * event );
void entryDropEvent(QDropEvent* event);
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseMoveEvent(QMouseEvent *event);
virtual void paintEvent ( QPaintEvent * event );
@ -54,6 +56,9 @@ class KeepassGroupView:public QTreeWidget{
GroupViewItem* LastHoverItem;
int InsLinePos;
int InsLineStart;
enum GroupViewDragType{EntryDrag,GroupDrag};
GroupViewDragType DragType;
QList<QTreeWidgetItem*>* EntryDragItems;
public slots:
void OnCurrentGroupChanged(QTreeWidgetItem*,QTreeWidgetItem*);
@ -69,6 +74,7 @@ class KeepassGroupView:public QTreeWidget{
void groupChanged(IGroupHandle* NewGroup);
void searchResultsSelected();
void fileModified();
void entriesDropped();
};

@ -144,16 +144,8 @@ void KeepassMainWindow::setupConnections(){
connect(ViewShowEntryDetailsAction,SIGNAL(toggled(bool)),this,SLOT(OnViewShowEntryDetails(bool)));
connect(ViewHidePasswordsAction,SIGNAL(toggled(bool)), this, SLOT(OnUsernPasswVisibilityChanged(bool)));
connect(ViewHideUsernamesAction,SIGNAL(toggled(bool)), this, SLOT(OnUsernPasswVisibilityChanged(bool)));
connect(ViewColumnsTitleAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsUsernameAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsUrlAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsPasswordAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsCommentAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsExpireAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsCreationAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsLastChangeAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsLastAccessAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(ViewColumnsAttachmentAction,SIGNAL(toggled(bool)), this, SLOT(OnColumnVisibilityChanged(bool)));
connect(menuColumns,SIGNAL(triggered(QAction*)),this,SLOT(OnColumnVisibilityChanged(QAction*)));
connect(ViewToolButtonSize16Action,SIGNAL(toggled(bool)), this, SLOT(OnViewToolbarIconSize16(bool)));
connect(ViewToolButtonSize22Action,SIGNAL(toggled(bool)), this, SLOT(OnViewToolbarIconSize22(bool)));
connect(ViewToolButtonSize28Action,SIGNAL(toggled(bool)), this, SLOT(OnViewToolbarIconSize28(bool)));
@ -174,6 +166,7 @@ void KeepassMainWindow::setupConnections(){
connect(EntryView,SIGNAL(selectionChanged(SelectionState)),this,SLOT(OnEntryChanged(SelectionState)));
connect(GroupView,SIGNAL(searchResultsSelected()),EntryView,SLOT(OnShowSearchResults()));
connect(GroupView,SIGNAL(searchResultsSelected()),this,SLOT(OnShowSearchResults()));
connect(GroupView,SIGNAL(entriesDropped()),EntryView,SLOT(removeDragItems()));
connect(HideSearchResultsAction,SIGNAL(triggered()),GroupView,SLOT(OnHideSearchResults()));
connect(SysTray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(OnSysTrayActivated(QSystemTrayIcon::ActivationReason)));
@ -258,16 +251,17 @@ void KeepassMainWindow::setupMenus(){
ViewShowEntryDetailsAction->setChecked(config.EntryDetails);
ViewHidePasswordsAction->setChecked(config.ListView_HidePasswords);
ViewHideUsernamesAction->setChecked(config.ListView_HideUsernames);
ViewColumnsTitleAction->setChecked(config.Columns[0]);
ViewColumnsUsernameAction->setChecked(config.Columns[1]);
ViewColumnsUrlAction->setChecked(config.Columns[2]);
ViewColumnsPasswordAction->setChecked(config.Columns[3]);
ViewColumnsCommentAction->setChecked(config.Columns[4]);
ViewColumnsExpireAction->setChecked(config.Columns[5]);
ViewColumnsCreationAction->setChecked(config.Columns[6]);
ViewColumnsLastChangeAction->setChecked(config.Columns[7]);
ViewColumnsLastAccessAction->setChecked(config.Columns[8]);
ViewColumnsAttachmentAction->setChecked(config.Columns[9]);
ViewColumnsTitleAction->setChecked(EntryView->Columns[0]);
ViewColumnsUsernameAction->setChecked(EntryView->Columns[1]);
ViewColumnsUrlAction->setChecked(EntryView->Columns[2]);
ViewColumnsPasswordAction->setChecked(EntryView->Columns[3]);
ViewColumnsCommentAction->setChecked(EntryView->Columns[4]);
ViewColumnsExpireAction->setChecked(EntryView->Columns[5]);
ViewColumnsCreationAction->setChecked(EntryView->Columns[6]);
ViewColumnsLastChangeAction->setChecked(EntryView->Columns[7]);
ViewColumnsLastAccessAction->setChecked(EntryView->Columns[8]);
ViewColumnsAttachmentAction->setChecked(EntryView->Columns[9]);
ViewColumnsGroupAction->setChecked(EntryView->Columns[10]);
ViewShowStatusbarAction->setChecked(config.ShowStatusbar);
switch(config.ToolbarIconSize){
@ -754,24 +748,25 @@ void KeepassMainWindow::OnQuickSearch(){
GroupView->showSearchResults();
}
void KeepassMainWindow::OnColumnVisibilityChanged(bool value){
config.Columns[0]=ViewColumnsTitleAction->isChecked();
config.Columns[1]=ViewColumnsUsernameAction->isChecked();
config.Columns[2]=ViewColumnsUrlAction->isChecked();
config.Columns[3]=ViewColumnsPasswordAction->isChecked();
config.Columns[4]=ViewColumnsCommentAction->isChecked();
config.Columns[5]=ViewColumnsExpireAction->isChecked();
config.Columns[6]=ViewColumnsCreationAction->isChecked();
config.Columns[7]=ViewColumnsLastChangeAction->isChecked();
config.Columns[8]=ViewColumnsLastAccessAction->isChecked();
config.Columns[9]=ViewColumnsAttachmentAction->isChecked();
//EntryView->updateColumns();
void KeepassMainWindow::OnColumnVisibilityChanged(QAction* action){
EntryView->Columns[0]=ViewColumnsTitleAction->isChecked();
EntryView->Columns[1]=ViewColumnsUsernameAction->isChecked();
EntryView->Columns[2]=ViewColumnsUrlAction->isChecked();
EntryView->Columns[3]=ViewColumnsPasswordAction->isChecked();
EntryView->Columns[4]=ViewColumnsCommentAction->isChecked();
EntryView->Columns[5]=ViewColumnsExpireAction->isChecked();
EntryView->Columns[6]=ViewColumnsCreationAction->isChecked();
EntryView->Columns[7]=ViewColumnsLastChangeAction->isChecked();
EntryView->Columns[8]=ViewColumnsLastAccessAction->isChecked();
EntryView->Columns[9]=ViewColumnsAttachmentAction->isChecked();
EntryView->Columns[10]=ViewColumnsGroupAction->isChecked();
EntryView->updateColumns();
//if(FileOpen) EntryView->updateItems();
}
void KeepassMainWindow::OnUsernPasswVisibilityChanged(bool value){
config.ListView_HidePasswords=ViewHidePasswordsAction->isChecked();
config.ListView_HideUsernames=ViewHideUsernamesAction->isChecked();
config.ListView_HidePasswords=ViewHidePasswordsAction->isChecked();
config.ListView_HideUsernames=ViewHideUsernamesAction->isChecked();
//EntryView->refreshItems();
}

@ -77,7 +77,7 @@ class KeepassMainWindow : public QMainWindow, public Ui_MainWindow{
void OnViewToolbarIconSize28(bool);
void OnGroupSelectionChanged(IGroupHandle*);
void OnQuickSearch();
void OnColumnVisibilityChanged(bool show);
void OnColumnVisibilityChanged(QAction* action);
void OnUsernPasswVisibilityChanged(bool hide);
void OnFileModified();
void OnExtrasSettings();