2012-05-15 07:02:05 -04:00
/*
* Copyright ( C ) 2012 Felix Geyer < debfx @ fobos . de >
2017-06-09 17:40:36 -04:00
* Copyright ( C ) 2017 KeePassXC Team < team @ keepassxc . org >
2012-05-15 07:02:05 -04:00
*
* 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 or ( at your option )
* version 3 of the License .
*
* 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "EditWidgetIcons.h"
# include "ui_EditWidgetIcons.h"
2013-10-03 09:18:16 -04:00
# include <QFileDialog>
2016-10-05 23:10:06 -04:00
# include <QMessageBox>
# include <QFileDialog>
2012-05-15 07:02:05 -04:00
2017-06-28 18:32:47 -04:00
# include "core/Config.h"
2012-05-15 07:02:05 -04:00
# include "core/Group.h"
# include "core/Metadata.h"
# include "core/Tools.h"
# include "gui/IconModels.h"
2013-10-08 16:09:20 -04:00
# include "gui/MessageBox.h"
2012-05-15 07:02:05 -04:00
2017-03-02 18:44:01 -05:00
# ifdef WITH_XC_HTTP
2017-02-15 14:23:06 -05:00
# include "http/qhttp/qhttpclient.hpp"
# include "http/qhttp/qhttpclientresponse.hpp"
using namespace qhttp : : client ;
2017-03-02 18:44:01 -05:00
# endif
2017-02-15 14:23:06 -05:00
2012-05-15 07:02:05 -04:00
IconStruct : : IconStruct ( )
: uuid ( Uuid ( ) )
, number ( 0 )
{
}
2012-05-15 12:51:45 -04:00
EditWidgetIcons : : EditWidgetIcons ( QWidget * parent )
2012-05-15 07:02:05 -04:00
: QWidget ( parent )
2012-07-19 07:57:55 -04:00
, m_ui ( new Ui : : EditWidgetIcons ( ) )
2015-07-24 12:28:12 -04:00
, m_database ( nullptr )
2012-07-19 07:57:55 -04:00
, m_defaultIconModel ( new DefaultIconModel ( this ) )
, m_customIconModel ( new CustomIconModel ( this ) )
2017-03-02 18:44:01 -05:00
# ifdef WITH_XC_HTTP
2017-03-02 19:49:32 -05:00
, m_fallbackToGoogle ( true )
, m_redirectCount ( 0 )
2017-03-10 08:28:26 -05:00
, m_httpClient ( nullptr )
2017-03-02 18:44:01 -05:00
# endif
2012-05-15 07:02:05 -04:00
{
m_ui - > setupUi ( this ) ;
m_ui - > defaultIconsView - > setModel ( m_defaultIconModel ) ;
m_ui - > customIconsView - > setModel ( m_customIconModel ) ;
connect ( m_ui - > defaultIconsView , SIGNAL ( clicked ( QModelIndex ) ) ,
this , SLOT ( updateRadioButtonDefaultIcons ( ) ) ) ;
connect ( m_ui - > customIconsView , SIGNAL ( clicked ( QModelIndex ) ) ,
this , SLOT ( updateRadioButtonCustomIcons ( ) ) ) ;
connect ( m_ui - > defaultIconsRadio , SIGNAL ( toggled ( bool ) ) ,
this , SLOT ( updateWidgetsDefaultIcons ( bool ) ) ) ;
connect ( m_ui - > customIconsRadio , SIGNAL ( toggled ( bool ) ) ,
this , SLOT ( updateWidgetsCustomIcons ( bool ) ) ) ;
connect ( m_ui - > addButton , SIGNAL ( clicked ( ) ) , SLOT ( addCustomIcon ( ) ) ) ;
connect ( m_ui - > deleteButton , SIGNAL ( clicked ( ) ) , SLOT ( removeCustomIcon ( ) ) ) ;
2016-10-05 23:10:06 -04:00
connect ( m_ui - > faviconButton , SIGNAL ( clicked ( ) ) , SLOT ( downloadFavicon ( ) ) ) ;
m_ui - > faviconButton - > setVisible ( false ) ;
2012-05-15 07:02:05 -04:00
}
EditWidgetIcons : : ~ EditWidgetIcons ( )
{
}
2016-10-05 23:10:06 -04:00
IconStruct EditWidgetIcons : : state ( )
2012-05-15 07:02:05 -04:00
{
2016-10-05 23:10:06 -04:00
Q_ASSERT ( m_database ) ;
Q_ASSERT ( ! m_currentUuid . isNull ( ) ) ;
2012-05-15 07:02:05 -04:00
IconStruct iconStruct ;
if ( m_ui - > defaultIconsRadio - > isChecked ( ) ) {
QModelIndex index = m_ui - > defaultIconsView - > currentIndex ( ) ;
if ( index . isValid ( ) ) {
iconStruct . number = index . row ( ) ;
}
2012-05-15 10:50:42 -04:00
else {
Q_ASSERT ( false ) ;
}
2012-05-15 07:02:05 -04:00
}
else {
QModelIndex index = m_ui - > customIconsView - > currentIndex ( ) ;
if ( index . isValid ( ) ) {
iconStruct . uuid = m_customIconModel - > uuidFromIndex ( m_ui - > customIconsView - > currentIndex ( ) ) ;
}
2012-05-15 10:50:42 -04:00
else {
iconStruct . number = - 1 ;
}
2012-05-15 07:02:05 -04:00
}
2017-02-15 14:23:06 -05:00
2016-07-31 17:53:26 -04:00
return iconStruct ;
}
void EditWidgetIcons : : reset ( )
{
2015-07-24 12:28:12 -04:00
m_database = nullptr ;
2012-05-15 10:50:42 -04:00
m_currentUuid = Uuid ( ) ;
2012-05-15 07:02:05 -04:00
}
2017-02-15 14:23:06 -05:00
void EditWidgetIcons : : load ( const Uuid & currentUuid , Database * database , const IconStruct & iconStruct , const QString & url )
2012-05-15 07:02:05 -04:00
{
2012-05-15 10:50:42 -04:00
Q_ASSERT ( database ) ;
Q_ASSERT ( ! currentUuid . isNull ( ) ) ;
2012-05-15 07:02:05 -04:00
m_database = database ;
m_currentUuid = currentUuid ;
2016-10-05 23:10:06 -04:00
setUrl ( url ) ;
2012-05-15 07:02:05 -04:00
2016-01-24 13:03:50 -05:00
m_customIconModel - > setIcons ( database - > metadata ( ) - > customIconsScaledPixmaps ( ) ,
2012-05-15 10:50:42 -04:00
database - > metadata ( ) - > customIconsOrder ( ) ) ;
2012-05-15 07:02:05 -04:00
2012-05-15 10:50:42 -04:00
Uuid iconUuid = iconStruct . uuid ;
if ( iconUuid . isNull ( ) ) {
int iconNumber = iconStruct . number ;
m_ui - > defaultIconsView - > setCurrentIndex ( m_defaultIconModel - > index ( iconNumber , 0 ) ) ;
m_ui - > defaultIconsRadio - > setChecked ( true ) ;
}
else {
QModelIndex index = m_customIconModel - > indexFromUuid ( iconUuid ) ;
if ( index . isValid ( ) ) {
m_ui - > customIconsView - > setCurrentIndex ( index ) ;
m_ui - > customIconsRadio - > setChecked ( true ) ;
2012-05-15 07:02:05 -04:00
}
else {
2012-05-15 10:50:42 -04:00
m_ui - > defaultIconsView - > setCurrentIndex ( m_defaultIconModel - > index ( 0 , 0 ) ) ;
m_ui - > defaultIconsRadio - > setChecked ( true ) ;
2012-05-15 07:02:05 -04:00
}
}
}
2017-02-15 14:23:06 -05:00
void EditWidgetIcons : : setUrl ( const QString & url )
2016-10-05 23:10:06 -04:00
{
2017-03-02 18:44:01 -05:00
# ifdef WITH_XC_HTTP
2016-10-05 23:10:06 -04:00
m_url = url ;
m_ui - > faviconButton - > setVisible ( ! url . isEmpty ( ) ) ;
2017-02-15 14:23:06 -05:00
resetFaviconDownload ( ) ;
2017-03-02 18:44:01 -05:00
# else
2017-03-10 08:28:26 -05:00
Q_UNUSED ( url ) ;
2017-03-02 18:44:01 -05:00
m_ui - > faviconButton - > setVisible ( false ) ;
# endif
2016-10-05 23:10:06 -04:00
}
void EditWidgetIcons : : downloadFavicon ( )
{
2017-03-02 18:44:01 -05:00
# ifdef WITH_XC_HTTP
2016-10-11 18:04:44 -04:00
QUrl url = QUrl ( m_url ) ;
url . setPath ( " /favicon.ico " ) ;
fetchFavicon ( url ) ;
2017-03-02 18:44:01 -05:00
# endif
2016-10-11 18:04:44 -04:00
}
2016-10-05 23:10:06 -04:00
2017-03-02 18:44:01 -05:00
# ifdef WITH_XC_HTTP
2017-02-15 14:23:06 -05:00
void EditWidgetIcons : : fetchFavicon ( const QUrl & url )
2016-10-11 18:04:44 -04:00
{
2017-02-15 14:23:06 -05:00
if ( nullptr = = m_httpClient ) {
m_httpClient = new QHttpClient ( this ) ;
2016-10-05 23:10:06 -04:00
}
2017-02-15 14:23:06 -05:00
bool requestMade = m_httpClient - > request ( qhttp : : EHTTP_GET , url , [ this , url ] ( QHttpResponse * response ) {
if ( m_database = = nullptr ) {
return ;
}
response - > collectData ( ) ;
response - > onEnd ( [ this , response , & url ] ( ) {
int status = response - > status ( ) ;
if ( 200 = = status ) {
QImage image ;
image . loadFromData ( response - > collectedData ( ) ) ;
if ( ! image . isNull ( ) ) {
//Set the image
Uuid uuid = Uuid : : random ( ) ;
m_database - > metadata ( ) - > addCustomIcon ( uuid , image . scaled ( 16 , 16 ) ) ;
m_customIconModel - > setIcons ( m_database - > metadata ( ) - > customIconsScaledPixmaps ( ) ,
m_database - > metadata ( ) - > customIconsOrder ( ) ) ;
QModelIndex index = m_customIconModel - > indexFromUuid ( uuid ) ;
m_ui - > customIconsView - > setCurrentIndex ( index ) ;
m_ui - > customIconsRadio - > setChecked ( true ) ;
resetFaviconDownload ( ) ;
} else {
fetchFaviconFromGoogle ( url . host ( ) ) ;
}
} else if ( 301 = = status | | 302 = = status ) {
// Check if server has sent a redirect
QUrl possibleRedirectUrl ( response - > headers ( ) . value ( " location " , " " ) ) ;
if ( ! possibleRedirectUrl . isEmpty ( ) & & possibleRedirectUrl ! = m_redirectUrl & & m_redirectCount < 3 ) {
resetFaviconDownload ( false ) ;
m_redirectUrl = possibleRedirectUrl ;
+ + m_redirectCount ;
fetchFavicon ( m_redirectUrl ) ;
} else {
// website is trying to redirect to itself or
// maximum number of redirects has been reached, fall back to Google
fetchFaviconFromGoogle ( url . host ( ) ) ;
}
} else {
fetchFaviconFromGoogle ( url . host ( ) ) ;
}
} ) ;
} ) ;
if ( ! requestMade ) {
resetFaviconDownload ( ) ;
return ;
2016-10-05 23:10:06 -04:00
}
2017-02-15 14:23:06 -05:00
m_httpClient - > setConnectingTimeOut ( 5000 , [ this ] ( ) {
2017-06-29 13:54:49 -04:00
QUrl tempurl = QUrl ( m_url ) ;
if ( tempurl . scheme ( ) = = " http " ) {
resetFaviconDownload ( ) ;
2017-07-13 17:10:15 -04:00
MessageBox : : warning ( this , tr ( " Error " ) , tr ( " Unable to fetch favicon. " ) + " \n " + tr ( " Hint: You can enable Google as a fallback under Tools>Settings>Security " ) ) ;
2017-06-29 13:54:49 -04:00
} else {
tempurl . setScheme ( " http " ) ;
2017-07-03 09:40:05 -04:00
m_url = tempurl . url ( ) ;
2017-06-29 13:54:49 -04:00
tempurl . setPath ( " /favicon.ico " ) ;
fetchFavicon ( tempurl ) ;
}
2017-02-15 14:23:06 -05:00
} ) ;
m_ui - > faviconButton - > setDisabled ( true ) ;
2016-10-05 23:10:06 -04:00
}
2017-02-15 14:23:06 -05:00
void EditWidgetIcons : : fetchFaviconFromGoogle ( const QString & domain )
2016-10-11 18:04:44 -04:00
{
2017-06-28 18:32:47 -04:00
if ( config ( ) - > get ( " security/IconDownloadFallbackToGoogle " , false ) . toBool ( ) & & m_fallbackToGoogle ) {
2017-02-15 14:23:06 -05:00
resetFaviconDownload ( ) ;
2016-10-11 18:04:44 -04:00
m_fallbackToGoogle = false ;
2017-07-13 17:10:15 -04:00
QUrl faviconUrl = QUrl ( " https://www.google.com/s2/favicons " ) ;
faviconUrl . setQuery ( " domain= " + domain ) ;
fetchFavicon ( faviconUrl ) ;
2017-02-09 20:11:43 -05:00
} else {
2017-02-15 14:23:06 -05:00
resetFaviconDownload ( ) ;
2016-10-11 18:04:44 -04:00
MessageBox : : warning ( this , tr ( " Error " ) , tr ( " Unable to fetch favicon. " ) ) ;
}
}
2017-02-15 14:23:06 -05:00
void EditWidgetIcons : : resetFaviconDownload ( bool clearRedirect )
2016-10-05 23:10:06 -04:00
{
2016-10-11 18:04:44 -04:00
if ( clearRedirect ) {
2017-02-15 14:23:06 -05:00
m_redirectUrl . clear ( ) ;
2016-10-11 18:04:44 -04:00
m_redirectCount = 0 ;
}
2016-10-05 23:10:06 -04:00
2017-02-15 14:23:06 -05:00
if ( nullptr ! = m_httpClient ) {
m_httpClient - > deleteLater ( ) ;
m_httpClient = nullptr ;
2017-01-27 13:43:45 -05:00
}
2017-02-15 14:23:06 -05:00
m_fallbackToGoogle = true ;
m_ui - > faviconButton - > setDisabled ( false ) ;
2016-10-05 23:10:06 -04:00
}
2017-03-02 18:44:01 -05:00
# endif
2016-10-05 23:10:06 -04:00
2012-05-15 07:02:05 -04:00
void EditWidgetIcons : : addCustomIcon ( )
{
if ( m_database ) {
2012-06-06 04:21:17 -04:00
QString filter = QString ( " %1 (%2);;%3 (*) " ) . arg ( tr ( " Images " ) ,
2012-05-15 07:02:05 -04:00
Tools : : imageReaderFilter ( ) , tr ( " All files " ) ) ;
QString filename = QFileDialog : : getOpenFileName (
this , tr ( " Select Image " ) , " " , filter ) ;
if ( ! filename . isEmpty ( ) ) {
2016-10-05 23:10:06 -04:00
QImage image ( filename ) ;
2012-05-15 07:02:05 -04:00
if ( ! image . isNull ( ) ) {
Uuid uuid = Uuid : : random ( ) ;
2016-10-05 23:10:06 -04:00
m_database - > metadata ( ) - > addCustomIcon ( uuid , image . scaled ( 16 , 16 ) ) ;
2016-01-24 13:03:50 -05:00
m_customIconModel - > setIcons ( m_database - > metadata ( ) - > customIconsScaledPixmaps ( ) ,
2012-05-15 07:02:05 -04:00
m_database - > metadata ( ) - > customIconsOrder ( ) ) ;
QModelIndex index = m_customIconModel - > indexFromUuid ( uuid ) ;
m_ui - > customIconsView - > setCurrentIndex ( index ) ;
}
else {
2017-03-10 09:58:42 -05:00
emit messageEditEntry ( tr ( " Can't read icon " ) , MessageWidget : : Error ) ;
2012-05-15 07:02:05 -04:00
}
}
}
}
void EditWidgetIcons : : removeCustomIcon ( )
{
if ( m_database ) {
QModelIndex index = m_ui - > customIconsView - > currentIndex ( ) ;
if ( index . isValid ( ) ) {
Uuid iconUuid = m_customIconModel - > uuidFromIndex ( index ) ;
2016-09-02 13:51:51 -04:00
const QList < Entry * > allEntries = m_database - > rootGroup ( ) - > entriesRecursive ( true ) ;
2017-02-28 22:45:40 -05:00
QList < Entry * > entriesWithSameIcon ;
2012-05-15 10:00:30 -04:00
QList < Entry * > historyEntriesWithSameIcon ;
2016-09-02 13:51:51 -04:00
for ( Entry * entry : allEntries ) {
2012-05-15 10:00:30 -04:00
if ( iconUuid = = entry - > iconUuid ( ) ) {
2017-02-28 22:45:40 -05:00
// Check if this is a history entry (no assigned group)
if ( ! entry - > group ( ) ) {
2012-05-15 10:00:30 -04:00
historyEntriesWithSameIcon < < entry ;
2017-02-28 22:45:40 -05:00
} else if ( m_currentUuid ! = entry - > uuid ( ) ) {
entriesWithSameIcon < < entry ;
2012-05-15 10:00:30 -04:00
}
2012-05-15 07:02:05 -04:00
}
}
2016-09-02 13:51:51 -04:00
const QList < Group * > allGroups = m_database - > rootGroup ( ) - > groupsRecursive ( true ) ;
2017-02-28 22:45:40 -05:00
QList < Group * > groupsWithSameIcon ;
for ( Group * group : allGroups ) {
2012-05-15 07:02:05 -04:00
if ( iconUuid = = group - > iconUuid ( ) & & m_currentUuid ! = group - > uuid ( ) ) {
2017-02-28 22:45:40 -05:00
groupsWithSameIcon < < group ;
2012-05-15 07:02:05 -04:00
}
}
2017-02-28 22:45:40 -05:00
int iconUseCount = entriesWithSameIcon . size ( ) + groupsWithSameIcon . size ( ) ;
if ( iconUseCount > 0 ) {
QMessageBox : : StandardButton ans = MessageBox : : question ( this , tr ( " Confirm Delete " ) ,
tr ( " This icon is used by %1 entries, and will be replaced "
" by the default icon. Are you sure you want to delete it? " )
. arg ( iconUseCount ) , QMessageBox : : Yes | QMessageBox : : No ) ;
2012-05-15 10:00:30 -04:00
2017-02-28 22:45:40 -05:00
if ( ans = = QMessageBox : : No ) {
// Early out, nothing is changed
return ;
} else {
// Revert matched entries to the default entry icon
for ( Entry * entry : asConst ( entriesWithSameIcon ) ) {
entry - > setIcon ( Entry : : DefaultIconNumber ) ;
}
// Revert matched groups to the default group icon
for ( Group * group : asConst ( groupsWithSameIcon ) ) {
group - > setIcon ( Group : : DefaultIconNumber ) ;
}
2012-05-15 07:02:05 -04:00
}
}
2017-02-28 22:45:40 -05:00
// Remove the icon from history entries
for ( Entry * entry : asConst ( historyEntriesWithSameIcon ) ) {
entry - > setUpdateTimeinfo ( false ) ;
entry - > setIcon ( 0 ) ;
entry - > setUpdateTimeinfo ( true ) ;
}
// Remove the icon from the database
m_database - > metadata ( ) - > removeCustomIcon ( iconUuid ) ;
m_customIconModel - > setIcons ( m_database - > metadata ( ) - > customIconsScaledPixmaps ( ) ,
m_database - > metadata ( ) - > customIconsOrder ( ) ) ;
// Reset the current icon view
updateRadioButtonDefaultIcons ( ) ;
if ( m_database - > resolveEntry ( m_currentUuid ) ! = nullptr ) {
m_ui - > defaultIconsView - > setCurrentIndex ( m_defaultIconModel - > index ( Entry : : DefaultIconNumber ) ) ;
} else {
m_ui - > defaultIconsView - > setCurrentIndex ( m_defaultIconModel - > index ( Group : : DefaultIconNumber ) ) ;
2012-05-15 07:02:05 -04:00
}
}
}
}
void EditWidgetIcons : : updateWidgetsDefaultIcons ( bool check )
{
if ( check ) {
QModelIndex index = m_ui - > defaultIconsView - > currentIndex ( ) ;
if ( ! index . isValid ( ) ) {
m_ui - > defaultIconsView - > setCurrentIndex ( m_defaultIconModel - > index ( 0 , 0 ) ) ;
}
else {
m_ui - > defaultIconsView - > setCurrentIndex ( index ) ;
}
m_ui - > customIconsView - > selectionModel ( ) - > clearSelection ( ) ;
m_ui - > addButton - > setEnabled ( false ) ;
m_ui - > deleteButton - > setEnabled ( false ) ;
}
}
void EditWidgetIcons : : updateWidgetsCustomIcons ( bool check )
{
if ( check ) {
QModelIndex index = m_ui - > customIconsView - > currentIndex ( ) ;
if ( ! index . isValid ( ) ) {
m_ui - > customIconsView - > setCurrentIndex ( m_customIconModel - > index ( 0 , 0 ) ) ;
}
else {
m_ui - > customIconsView - > setCurrentIndex ( index ) ;
}
m_ui - > defaultIconsView - > selectionModel ( ) - > clearSelection ( ) ;
m_ui - > addButton - > setEnabled ( true ) ;
m_ui - > deleteButton - > setEnabled ( true ) ;
}
}
void EditWidgetIcons : : updateRadioButtonDefaultIcons ( )
{
m_ui - > defaultIconsRadio - > setChecked ( true ) ;
}
void EditWidgetIcons : : updateRadioButtonCustomIcons ( )
{
m_ui - > customIconsRadio - > setChecked ( true ) ;
}