1 /****************************************************************************************
2  * Copyright (c) 2009 John Atkinson <john@fauxnetic.co.uk>                              *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Pulic License for more details.              *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #include "DatabaseConfig.h"
18 
19 #include <PluginManager.h>
20 #include <core/support/Amarok.h>
21 #include <core/support/Debug.h>
22 #include "core/support/PluginFactory.h"
23 
24 #include <KConfigDialogManager>
25 #include <KMessageBox>
26 #include <KCMultiDialog>
27 
28 
DatabaseConfig(Amarok2ConfigDialog * parent,KConfigSkeleton * config)29 DatabaseConfig::DatabaseConfig( Amarok2ConfigDialog* parent, KConfigSkeleton *config )
30     : ConfigDialogBase( parent )
31     , m_configManager( new KConfigDialogManager( this, config ) )
32 {
33     setupUi( this );
34 
35     // Fix some weird tab orderness
36     setTabOrder( kcfg_Host,     kcfg_Port );        // host to port
37     setTabOrder( kcfg_Port,     kcfg_User );        // port to username
38     setTabOrder( kcfg_User,     kcfg_Password );    // username to password
39     setTabOrder( kcfg_Password, kcfg_Database );    // password to database
40 
41     // enable the test button if one of the plugin factories has a correct testSettings slot
42     // get all storage factories
43     auto factories = Plugins::PluginManager::instance()->factories( Plugins::PluginManager::Storage );
44     bool testFunctionAvailable = false;
45     for( const auto &factory : factories )
46     {
47         // check the meta object if there is a testSettings slot available
48         if( factory->metaObject()->
49             indexOfMethod( QMetaObject::normalizedSignature("testSettings(QString, QString, QString, int, QString)" ) ) >= 0 )
50             testFunctionAvailable = true;
51     }
52     button_Test->setEnabled( testFunctionAvailable );
53 
54     // connect slots
55     connect( kcfg_UseServer, &QCheckBox::stateChanged, this, &DatabaseConfig::toggleExternalConfigAvailable );
56 
57     connect( kcfg_Database, &QLineEdit::textChanged, this, &DatabaseConfig::updateSQLQuery );
58     connect( kcfg_User,     &QLineEdit::textChanged, this, &DatabaseConfig::updateSQLQuery );
59     connect( button_Test,   &QAbstractButton::clicked,  this, &DatabaseConfig::testDatabaseConnection );
60 
61     toggleExternalConfigAvailable( kcfg_UseServer->checkState() );
62 
63     updateSQLQuery();
64 
65     m_configManager->addWidget( this );
66 }
67 
~DatabaseConfig()68 DatabaseConfig::~DatabaseConfig()
69 {}
70 
71 void
toggleExternalConfigAvailable(const int checkBoxState)72 DatabaseConfig::toggleExternalConfigAvailable( const int checkBoxState ) //SLOT
73 {
74     group_Connection->setEnabled( checkBoxState == Qt::Checked );
75 }
76 
77 void
testDatabaseConnection()78 DatabaseConfig::testDatabaseConnection() //SLOT
79 {
80     // get all storage factories
81     auto factories = Plugins::PluginManager::instance()->factories( Plugins::PluginManager::Storage );
82 
83     // try if they have a testSettings slot that we can call
84     for( const auto &factory : factories )
85     {
86         bool callSucceeded = false;
87         QStringList connectionErrors;
88 
89         callSucceeded = QMetaObject::invokeMethod( factory.data(),
90                                "testSettings",
91                                Q_RETURN_ARG( QStringList, connectionErrors ),
92                                Q_ARG( QString, kcfg_Host->text() ),
93                                Q_ARG( QString, kcfg_User->text() ),
94                                Q_ARG( QString, kcfg_Password->text() ),
95                                Q_ARG( int, kcfg_Port->text().toInt() ),
96                                Q_ARG( QString, kcfg_Database->text() )
97                                );
98 
99         if( callSucceeded )
100         {
101             if( connectionErrors.isEmpty() )
102                 KMessageBox::messageBox( this, KMessageBox::Information,
103                                          i18n( "Amarok was able to establish a successful connection to the database." ),
104                                          i18n( "Success" ) );
105             else
106                 KMessageBox::error( this, i18n( "The amarok database reported "
107                                                 "the following errors:\n%1\nIn most cases you will need to resolve "
108                                                 "these errors before Amarok will run properly.",
109                                     connectionErrors.join( QStringLiteral("\n") ) ),
110                                     i18n( "Database Error" ));
111         }
112     }
113 }
114 
115 ///////////////////////////////////////////////////////////////
116 // REIMPLEMENTED METHODS from ConfigDialogBase
117 ///////////////////////////////////////////////////////////////
118 
119 bool
hasChanged()120 DatabaseConfig::hasChanged()
121 {
122     return false;
123 }
124 
125 bool
isDefault()126 DatabaseConfig::isDefault()
127 {
128     return false;
129 }
130 
131 void
updateSettings()132 DatabaseConfig::updateSettings()
133 {
134     if( m_configManager->hasChanged() )
135         KMessageBox::messageBox( nullptr, KMessageBox::Information,
136                  i18n( "Changes to database settings only take\neffect after Amarok is restarted." ),
137                  i18n( "Database settings changed" ) );
138 }
139 
140 
141 ///////////////////////////////////////////////////////////////
142 // PRIVATE METHODS
143 ///////////////////////////////////////////////////////////////
144 
145 void
updateSQLQuery()146 DatabaseConfig::updateSQLQuery() //SLOT
147 {
148     QString query;
149 
150     if( isSQLInfoPresent() )
151     {
152         // Query template:
153         // GRANT ALL ON amarokdb.* TO 'amarokuser'@'localhost' IDENTIFIED BY 'mypassword'; FLUSH PRIVILEGES;
154 
155         // Don't print the actual password!
156         const QString examplePassword = i18nc( "A default password for insertion into an example SQL command (so as not to print the real one). To be manually replaced by the user.", "password" );
157         query = QStringLiteral( "CREATE DATABASE %1;\nGRANT ALL PRIVILEGES ON %1.* TO '%2' IDENTIFIED BY '%3'; FLUSH PRIVILEGES;" )
158                    .arg( kcfg_Database->text(), kcfg_User->text(), examplePassword );
159     }
160     text_SQL->setPlainText( query );
161 }
162 
163 
164 inline bool
isSQLInfoPresent() const165 DatabaseConfig::isSQLInfoPresent() const
166 {
167     return !kcfg_Database->text().isEmpty() && !kcfg_User->text().isEmpty() && !kcfg_Host->text().isEmpty();
168 }
169 
170 
171 
172 
173