diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d9c2338d0..13bb0ecf4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -91,7 +91,9 @@ ENDIF()
SET( tomahawkUI ${tomahawkUI}
TomahawkWindow.ui
DiagnosticsDialog.ui
- StackedSettingsDialog.ui
+ Settings_Accounts.ui
+ Settings_Advanced.ui
+ Settings_Collection.ui
ProxyDialog.ui
AudioControls.ui
diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp
index 06217c8aa..e573842c4 100644
--- a/src/SettingsDialog.cpp
+++ b/src/SettingsDialog.cpp
@@ -53,75 +53,65 @@
#include "utils/Logger.h"
#include "accounts/AccountFactoryWrapper.h"
#include "accounts/spotify/SpotifyAccount.h"
+#include "thirdparty/Qocoa/qtoolbartabdialog.h"
+#include "thirdparty/Qocoa/qbutton.h"
#include "ui_ProxyDialog.h"
-#include "ui_StackedSettingsDialog.h"
+#include "ui_Settings_Accounts.h"
+#include "ui_Settings_Collection.h"
+#include "ui_Settings_Advanced.h"
using namespace Tomahawk;
using namespace Accounts;
-SettingsDialog::SettingsDialog( QWidget *parent )
- : QDialog( parent )
- , ui( new Ui_StackedSettingsDialog )
- , m_proxySettings( this )
+SettingsDialog::SettingsDialog(QObject *parent )
+ : QObject( parent )
+ , m_accountsWidgetUi( new Ui_Settings_Accounts )
+ , m_accountsWidget( new QWidget )
+ , m_collectionWidgetUi( new Ui_Settings_Collection )
+ , m_collectionWidget( new QWidget )
+ , m_advancedWidgetUi( new Ui_Settings_Advanced )
+ , m_advancedWidget( new QWidget )
+ , m_proxySettings( 0 )
, m_rejected( false )
, m_restartRequired( false )
, m_accountModel( 0 )
, m_sipSpinner( 0 )
{
- ui->setupUi( this );
+ m_accountsWidgetUi->setupUi( m_accountsWidget );
+ m_collectionWidgetUi->setupUi( m_collectionWidget );
+ m_advancedWidgetUi->setupUi( m_advancedWidget );
+
+ m_accountsWidgetUi->accountsFilterCombo->setFocusPolicy( Qt::NoFocus );
+
+ m_dialog = new QToolbarTabDialog;
+
TomahawkSettings* s = TomahawkSettings::instance();
- TomahawkUtils::unmarginLayout( layout() );
- TomahawkUtils::unmarginLayout( ui->horizontalLayout );
-
-#ifdef Q_WS_X11
- ui->stackedWidget->setContentsMargins( 4, 4, 4, 4 );
-#else
- ui->stackedWidget->setContentsMargins( 4, 4, 4, 0 );
-#endif
- ui->checkBoxReporter->setChecked( s->crashReporterEnabled() );
- ui->checkBoxHttp->setChecked( s->httpEnabled() );
-
- QFrame *sepLine = new QFrame( this );
- sepLine->setFrameShape( QFrame::HLine );
- sepLine->setFrameShadow( QFrame::Sunken );
- ui->horizontalLayout->insertWidget( 0, sepLine );
-
- m_toolBar = new QToolBar( tr( "Tomahawk Settings" ), this );
- ui->horizontalLayout->insertWidget( 0, m_toolBar );
- m_toolBar->setToolButtonStyle( Qt::ToolButtonTextUnderIcon );
+ m_advancedWidgetUi->checkBoxReporter->setChecked( s->crashReporterEnabled() );
+ m_advancedWidgetUi->checkBoxHttp->setChecked( s->httpEnabled() );
//Network settings
TomahawkSettings::ExternalAddressMode mode = TomahawkSettings::instance()->externalAddressMode();
if ( mode == TomahawkSettings::Lan )
- ui->lanOnlyRadioButton->setChecked( true );
+ m_advancedWidgetUi->lanOnlyRadioButton->setChecked( true );
else if ( mode == TomahawkSettings::Static )
- ui->staticIpRadioButton->setChecked( true );
+ m_advancedWidgetUi->staticIpRadioButton->setChecked( true );
else
- ui->upnpRadioButton->setChecked( true );
+ m_advancedWidgetUi->upnpRadioButton->setChecked( true );
- ui->staticHostNamePortLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
- ui->staticHostName->setEnabled( ui->staticIpRadioButton->isChecked() );
- ui->staticPort->setEnabled( ui->staticIpRadioButton->isChecked() );
- ui->staticHostNameLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
- ui->staticPortLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticHostNamePortLabel->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticHostName->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticPort->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticHostNameLabel->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticPortLabel->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
bool useProxy = TomahawkSettings::instance()->proxyType() == QNetworkProxy::Socks5Proxy;
- ui->enableProxyCheckBox->setChecked( useProxy );
- ui->proxyButton->setEnabled( useProxy );
+ m_advancedWidgetUi->enableProxyCheckBox->setChecked( useProxy );
+ m_advancedWidgetUi->proxyButton->setEnabled( useProxy );
- ui->aclEntryClearButton->setEnabled( TomahawkSettings::instance()->aclEntries().size() > 0 );
- connect( ui->aclEntryClearButton, SIGNAL( clicked( bool ) ), this, SLOT( aclEntryClearButtonClicked() ) );
-
- createIcons();
-#ifdef Q_WS_X11
- setContentsMargins( 4, 4, 4, 4 );
-#elif defined( Q_OS_MAC )
- setContentsMargins( 0, 0, 0, 4 );
-#else
- setContentsMargins( 0, 4, 4, 4 );
-#endif
+ m_advancedWidgetUi->aclEntryClearButton->setEnabled( TomahawkSettings::instance()->aclEntries().size() > 0 );
+ connect( m_advancedWidgetUi->aclEntryClearButton, SIGNAL( clicked( bool ) ), this, SLOT( aclEntryClearButtonClicked() ) );
#ifdef Q_WS_MAC
// Avoid resize handles on sheets on osx
@@ -130,16 +120,18 @@ SettingsDialog::SettingsDialog( QWidget *parent )
p->setFixedSize( 0, 0 );
#endif
+ m_accountsWidgetUi->installFromFileBtn->setText( tr( "Install from file" ) );
+
// Accounts
AccountDelegate* accountDelegate = new AccountDelegate( this );
- ui->accountsView->setItemDelegate( accountDelegate );
- ui->accountsView->setContextMenuPolicy( Qt::CustomContextMenu );
- ui->accountsView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
- ui->accountsView->setMouseTracking( true );
+ m_accountsWidgetUi->accountsView->setItemDelegate( accountDelegate );
+ m_accountsWidgetUi->accountsView->setContextMenuPolicy( Qt::CustomContextMenu );
+ m_accountsWidgetUi->accountsView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
+ m_accountsWidgetUi->accountsView->setMouseTracking( true );
connect( accountDelegate, SIGNAL( openConfig( Tomahawk::Accounts::Account* ) ), this, SLOT( openAccountConfig( Tomahawk::Accounts::Account* ) ) );
connect( accountDelegate, SIGNAL( openConfig( Tomahawk::Accounts::AccountFactory* ) ), this, SLOT( openAccountFactoryConfig( Tomahawk::Accounts::AccountFactory* ) ) );
- connect( accountDelegate, SIGNAL( update( QModelIndex ) ), ui->accountsView, SLOT( update( QModelIndex ) ) );
+ connect( accountDelegate, SIGNAL( update( QModelIndex ) ), m_accountsWidgetUi->accountsView, SLOT( update( QModelIndex ) ) );
m_accountModel = new AccountModel( this );
m_accountProxy = new AccountModelFilterProxy( m_accountModel );
@@ -150,59 +142,75 @@ SettingsDialog::SettingsDialog( QWidget *parent )
connect( m_accountProxy, SIGNAL( errorInstalling( QPersistentModelIndex ) ), accountDelegate, SLOT( errorInstalling(QPersistentModelIndex) ) );
connect( m_accountProxy, SIGNAL( scrollTo( QModelIndex ) ), this, SLOT( scrollTo( QModelIndex ) ) );
- ui->accountsView->setModel( m_accountProxy );
+ m_accountsWidgetUi->accountsView->setModel( m_accountProxy );
- connect( ui->installFromFileBtn, SIGNAL( clicked( bool ) ), this, SLOT( installFromFile() ) );
+ connect( m_accountsWidgetUi->installFromFileBtn, SIGNAL( clicked( bool ) ), this, SLOT( installFromFile() ) );
connect( m_accountModel, SIGNAL( createAccount( Tomahawk::Accounts::AccountFactory* ) ), this, SLOT( createAccountFromFactory( Tomahawk::Accounts::AccountFactory* ) ) );
- ui->accountsFilterCombo->addItem( tr( "All" ), Accounts::NoType );
- ui->accountsFilterCombo->addItem( accountTypeToString( SipType ), SipType );
- ui->accountsFilterCombo->addItem( accountTypeToString( ResolverType ), ResolverType );
- ui->accountsFilterCombo->addItem( accountTypeToString( StatusPushType ), StatusPushType );
+ m_accountsWidgetUi->accountsFilterCombo->addItem( tr( "All" ), Accounts::NoType );
+ m_accountsWidgetUi->accountsFilterCombo->addItem( accountTypeToString( SipType ), SipType );
+ m_accountsWidgetUi->accountsFilterCombo->addItem( accountTypeToString( ResolverType ), ResolverType );
+ m_accountsWidgetUi->accountsFilterCombo->addItem( accountTypeToString( StatusPushType ), StatusPushType );
- connect( ui->accountsFilterCombo, SIGNAL( activated( int ) ), this, SLOT( accountsFilterChanged( int ) ) );
+ connect( m_accountsWidgetUi->accountsFilterCombo, SIGNAL( activated( int ) ), this, SLOT( accountsFilterChanged( int ) ) );
if ( !Servent::instance()->isReady() )
{
- m_sipSpinner = new AnimatedSpinner( ui->accountsView );
+ m_sipSpinner = new AnimatedSpinner( m_accountsWidgetUi->accountsView );
m_sipSpinner->fadeIn();
connect( Servent::instance(), SIGNAL( ready() ), this, SLOT( serventReady() ) );
}
// ADVANCED
- ui->staticHostName->setText( s->externalHostname() );
- ui->staticPort->setValue( s->externalPort() );
- ui->proxyButton->setVisible( true );
+ m_advancedWidgetUi->staticHostName->setText( s->externalHostname() );
+ m_advancedWidgetUi->staticPort->setValue( s->externalPort() );
+ m_advancedWidgetUi->proxyButton->setVisible( true );
- ui->checkBoxWatchForChanges->setChecked( s->watchForChanges() );
- ui->scannerTimeSpinBox->setValue( s->scannerTime() );
- ui->enableEchonestCatalog->setChecked( s->enableEchonestCatalogs() );
+ m_collectionWidgetUi->checkBoxWatchForChanges->setChecked( s->watchForChanges() );
+ m_collectionWidgetUi->scannerTimeSpinBox->setValue( s->scannerTime() );
+ m_collectionWidgetUi->enableEchonestCatalog->setChecked( s->enableEchonestCatalogs() );
- connect( ui->checkBoxWatchForChanges, SIGNAL( clicked( bool ) ), SLOT( updateScanOptionsView() ) );
+ connect( m_collectionWidgetUi->checkBoxWatchForChanges, SIGNAL( clicked( bool ) ), SLOT( updateScanOptionsView() ) );
- if ( ui->checkBoxWatchForChanges->isChecked() )
+ if ( m_collectionWidgetUi->checkBoxWatchForChanges->isChecked() )
{
- ui->scanTimeLabel->show();
- ui->scannerTimeSpinBox->show();
+ m_collectionWidgetUi->scanTimeLabel->show();
+ m_collectionWidgetUi->scannerTimeSpinBox->show();
}
else
{
- ui->scanTimeLabel->hide();
- ui->scannerTimeSpinBox->hide();
+ m_collectionWidgetUi->scanTimeLabel->hide();
+ m_collectionWidgetUi->scannerTimeSpinBox->hide();
}
foreach ( const QString& dir, TomahawkSettings::instance()->scannerPaths() )
{
- ui->dirTree->checkPath( dir, Qt::Checked );
+ m_collectionWidgetUi->dirTree->checkPath( dir, Qt::Checked );
}
- ui->advancedPage->setMinimumSize( ui->advancedPage->sizeHint() );
- int buttonsWidth = qMax( ui->proxyButton->sizeHint().width(),
- ui->aclEntryClearButton->sizeHint().width() );
- ui->proxyButton->setFixedWidth( buttonsWidth );
- ui->aclEntryClearButton->setFixedWidth( buttonsWidth );
+ int buttonsWidth = qMax( m_advancedWidgetUi->proxyButton->sizeHint().width(),
+ m_advancedWidgetUi->aclEntryClearButton->sizeHint().width() );
+ m_advancedWidgetUi->proxyButton->setFixedWidth( buttonsWidth );
+ m_advancedWidgetUi->aclEntryClearButton->setFixedWidth( buttonsWidth );
+#ifndef Q_OS_MAC
+ m_advancedWidget->setMinimumSize( m_advancedWidget->sizeHint() );
+ m_accountsWidget->setMinimumWidth( 500 );
+#else
+ m_accountsWidget->setContentsMargins( 6, 6, 6, 6 );
+ m_accountsWidgetUi->horizontalLayout->setContentsMargins( 0, 0, 0, 0 );
+ m_accountsWidgetUi->installFromFileBtn->setContentsMargins( -4, 0, 0, 0 );
+ m_accountsWidget->setMinimumSize( 550, 400 );
+ m_accountsWidgetUi->accountsView->setAttribute( Qt::WA_MacShowFocusRect, false );
+
+ m_collectionWidget->setContentsMargins( 6, 6, 6, 6 );
+ m_collectionWidget->setMinimumHeight( m_collectionWidgetUi->verticalLayout->sizeHint().height() + 20 );
+ m_collectionWidgetUi->dirTree->setAttribute( Qt::WA_MacShowFocusRect, false );
+
+ m_advancedWidget->setContentsMargins( 6, 6, 6, 6 );
+ m_advancedWidget->setMinimumHeight( m_advancedWidgetUi->verticalLayout->sizeHint().height() );
+#endif
// NOW PLAYING
// #ifdef Q_WS_MAC
@@ -211,72 +219,96 @@ SettingsDialog::SettingsDialog( QWidget *parent )
// ui->checkBoxEnableAdium->hide();
// #endif
- connect( ui->proxyButton, SIGNAL( clicked() ), SLOT( showProxySettings() ) );
- connect( ui->lanOnlyRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
- connect( ui->staticIpRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
- connect( ui->upnpRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
- connect( ui->lanOnlyRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
- connect( ui->staticIpRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
- connect( ui->upnpRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
- connect( ui->enableProxyCheckBox, SIGNAL( toggled(bool) ), SLOT( toggleProxyEnabled() ) );
- connect( this, SIGNAL( rejected() ), SLOT( onRejected() ) );
+ m_dialog->addTab( m_accountsWidget, QPixmap( RESPATH "images/account-settings.png" ), tr( "Services" ), tr( "Configure the accounts and services used by Tomahawk "
+ "to search and retrieve music, find your friends and "
+ "update your status." ) );
+
+ m_dialog->addTab( m_collectionWidget, QPixmap( RESPATH "images/music-settings.png" ), tr( "Collection" ), tr( "Manage how Tomahawk finds music on your computer." ));
+
+ m_dialog->addTab( m_advancedWidget, QPixmap( RESPATH "images/advanced-settings.png" ), tr( "Advanced" ), tr( "Configure Tomahawk's advanced settings, including "
+ "network connectivity settings, browser interaction "
+ "and more." ) );
+
+ m_dialog->setCurrentIndex( 0 );
+
+ connect( m_advancedWidgetUi->proxyButton, SIGNAL( clicked() ), SLOT( showProxySettings() ) );
+ connect( m_advancedWidgetUi->lanOnlyRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
+ connect( m_advancedWidgetUi->staticIpRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
+ connect( m_advancedWidgetUi->upnpRadioButton, SIGNAL( toggled(bool) ), SLOT( requiresRestart() ) );
+ connect( m_advancedWidgetUi->lanOnlyRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
+ connect( m_advancedWidgetUi->staticIpRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
+ connect( m_advancedWidgetUi->upnpRadioButton, SIGNAL( toggled(bool) ), SLOT( toggleRemoteMode() ) );
+ connect( m_advancedWidgetUi->enableProxyCheckBox, SIGNAL( toggled(bool) ), SLOT( toggleProxyEnabled() ) );
+
+ connect( m_dialog, SIGNAL( accepted() ), SLOT( saveSettings() ) );
+ connect( m_dialog, SIGNAL( rejected() ), SLOT( onRejected() ) );
+}
+
+
+void
+SettingsDialog::saveSettings()
+{
+ qDebug() << Q_FUNC_INFO;
+
+ TomahawkSettings* s = TomahawkSettings::instance();
+
+ s->setCrashReporterEnabled( m_advancedWidgetUi->checkBoxReporter->checkState() == Qt::Checked );
+ s->setHttpEnabled( m_advancedWidgetUi->checkBoxHttp->checkState() == Qt::Checked );
+ s->setProxyType( m_advancedWidgetUi->enableProxyCheckBox->isChecked() ? QNetworkProxy::Socks5Proxy : QNetworkProxy::NoProxy );
+ s->setExternalAddressMode( m_advancedWidgetUi->upnpRadioButton->isChecked() ? TomahawkSettings::Upnp : ( m_advancedWidgetUi->lanOnlyRadioButton->isChecked() ? TomahawkSettings::Lan : TomahawkSettings::Static ) );
+
+ s->setExternalHostname( m_advancedWidgetUi->staticHostName->text() );
+ s->setExternalPort( m_advancedWidgetUi->staticPort->value() );
+
+ s->setScannerPaths( m_collectionWidgetUi->dirTree->getCheckedPaths() );
+ s->setWatchForChanges( m_collectionWidgetUi->checkBoxWatchForChanges->isChecked() );
+ s->setScannerTime( m_collectionWidgetUi->scannerTimeSpinBox->value() );
+ s->setEnableEchonestCatalogs( m_collectionWidgetUi->enableEchonestCatalog->isChecked() );
+
+// s->setNowPlayingEnabled( ui->checkBoxEnableAdium->isChecked() );
+
+ s->applyChanges();
+ s->sync();
+
+ if ( m_restartRequired )
+ QMessageBox::information( 0, tr( "Information" ), tr( "Some changed settings will not take effect until Tomahawk is restarted" ) );
+
+ TomahawkUtils::NetworkProxyFactory* proxyFactory = TomahawkUtils::proxyFactory();
+ if ( !m_advancedWidgetUi->enableProxyCheckBox->isChecked() )
+ {
+ tDebug() << Q_FUNC_INFO << "Got NoProxy selected";
+ proxyFactory->setProxy( QNetworkProxy::NoProxy );
+ }
+ else
+ {
+ tDebug() << Q_FUNC_INFO << "Got Socks5Proxy selected";
+ proxyFactory->setProxy( QNetworkProxy( QNetworkProxy::Socks5Proxy, s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() ) );
+ if ( !s->proxyNoProxyHosts().isEmpty() )
+ {
+ tDebug() << Q_FUNC_INFO << "noproxy hosts:" << s->proxyNoProxyHosts();
+ tDebug() << Q_FUNC_INFO << "split noproxy line edit is " << s->proxyNoProxyHosts().split( ' ', QString::SkipEmptyParts );
+ proxyFactory->setNoProxyHosts( s->proxyNoProxyHosts().split( ' ', QString::SkipEmptyParts ) );
+ }
+ }
}
SettingsDialog::~SettingsDialog()
{
- qDebug() << Q_FUNC_INFO;
-
- if ( !m_rejected )
- {
- TomahawkSettings* s = TomahawkSettings::instance();
-
- s->setCrashReporterEnabled( ui->checkBoxReporter->checkState() == Qt::Checked );
- s->setHttpEnabled( ui->checkBoxHttp->checkState() == Qt::Checked );
- s->setProxyType( ui->enableProxyCheckBox->isChecked() ? QNetworkProxy::Socks5Proxy : QNetworkProxy::NoProxy );
- s->setExternalAddressMode( ui->upnpRadioButton->isChecked() ? TomahawkSettings::Upnp : ( ui->lanOnlyRadioButton->isChecked() ? TomahawkSettings::Lan : TomahawkSettings::Static ) );
-
- s->setExternalHostname( ui->staticHostName->text() );
- s->setExternalPort( ui->staticPort->value() );
-
- s->setScannerPaths( ui->dirTree->getCheckedPaths() );
- s->setWatchForChanges( ui->checkBoxWatchForChanges->isChecked() );
- s->setScannerTime( ui->scannerTimeSpinBox->value() );
- s->setEnableEchonestCatalogs( ui->enableEchonestCatalog->isChecked() );
-
-// s->setNowPlayingEnabled( ui->checkBoxEnableAdium->isChecked() );
-
- s->applyChanges();
- s->sync();
-
- if ( m_restartRequired )
- QMessageBox::information( this, tr( "Information" ), tr( "Some changed settings will not take effect until Tomahawk is restarted" ) );
-
- TomahawkUtils::NetworkProxyFactory* proxyFactory = TomahawkUtils::proxyFactory();
- if ( !ui->enableProxyCheckBox->isChecked() )
- {
- tDebug() << Q_FUNC_INFO << "Got NoProxy selected";
- proxyFactory->setProxy( QNetworkProxy::NoProxy );
- }
- else
- {
- tDebug() << Q_FUNC_INFO << "Got Socks5Proxy selected";
- proxyFactory->setProxy( QNetworkProxy( QNetworkProxy::Socks5Proxy, s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() ) );
- if ( !s->proxyNoProxyHosts().isEmpty() )
- {
- tDebug() << Q_FUNC_INFO << "noproxy hosts:" << s->proxyNoProxyHosts();
- tDebug() << Q_FUNC_INFO << "split noproxy line edit is " << s->proxyNoProxyHosts().split( ' ', QString::SkipEmptyParts );
- proxyFactory->setNoProxyHosts( s->proxyNoProxyHosts().split( ' ', QString::SkipEmptyParts ) );
- }
- }
- }
- else
- qDebug() << "Settings dialog cancelled, NOT saving prefs.";
-
- delete ui;
+ m_accountsWidget->deleteLater();
+ m_collectionWidget->deleteLater();
+ m_advancedWidget->deleteLater();
+ m_dialog->deleteLater();
}
+void
+SettingsDialog::show()
+{
+ m_dialog->setCurrentIndex( 0 );
+ m_dialog->show();
+}
+
void
SettingsDialog::serventReady()
{
@@ -284,73 +316,6 @@ SettingsDialog::serventReady()
}
-void
-SettingsDialog::createIcons()
-{
- ensurePolished();
-
- m_settingsGroup = new QActionGroup( m_toolBar );
-
- QWidget *leftSpacer = new QWidget( m_toolBar );
- leftSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
- m_toolBar->addWidget( leftSpacer );
-
- QAction *accountsAction = new QAction( QIcon( RESPATH "images/account-settings.png" ),
- tr( "Services" ),
- m_toolBar );
- accountsAction->setCheckable( true );
- accountsAction->setToolTip( tr( "Services
"
- "Configure the accounts and services used by Tomahawk "
- "to search and retrieve music, find your friends and "
- "update your status." ) );
- m_settingsGroup->addAction( accountsAction );
-
- QAction *musicAction = new QAction( QIcon( RESPATH "images/music-settings.png" ),
- tr( "Collection" ),
- m_toolBar );
- musicAction->setCheckable( true );
- musicAction->setToolTip( tr( "Collection
"
- "Manage how Tomahawk finds music on your computer." ) );
- m_settingsGroup->addAction( musicAction );
-
-
- QAction *advancedAction = new QAction( QIcon( RESPATH "images/advanced-settings.png" ),
- tr( "Advanced" ),
- m_toolBar );
- advancedAction->setCheckable( true );
- advancedAction->setToolTip( tr( "Advanced
"
- "Configure Tomahawk's advanced settings, including "
- "network connectivity settings, browser interaction "
- "and more." ) );
- m_settingsGroup->addAction( advancedAction );
-
- m_settingsGroup->setExclusive( true );
-
- m_toolBar->addActions( m_settingsGroup->actions() );
-
- QWidget *rightSpacer = new QWidget( m_toolBar );
- rightSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
- m_toolBar->addWidget( rightSpacer );
-
- connect( m_settingsGroup, SIGNAL( triggered( QAction * ) ),
- this, SLOT( changePage( QAction * ) ) );
-
- accountsAction->setChecked( true );
- changePage( accountsAction );
-}
-
-
-void
-SettingsDialog::changePage( QAction *action )
-{
- int index = m_settingsGroup->actions().indexOf( action );
- if( ui->stackedWidget->currentIndex() != index )
- {
- ui->stackedWidget->setCurrentIndex( index );
- }
-}
-
-
void
SettingsDialog::onRejected()
{
@@ -361,11 +326,12 @@ SettingsDialog::onRejected()
void
SettingsDialog::changeEvent( QEvent *e )
{
- QDialog::changeEvent( e );
switch ( e->type() )
{
case QEvent::LanguageChange:
- ui->retranslateUi( this );
+ m_accountsWidgetUi->retranslateUi( m_accountsWidget );
+ m_collectionWidgetUi->retranslateUi( m_collectionWidget );
+ m_advancedWidgetUi->retranslateUi( m_advancedWidget );
break;
default:
@@ -386,33 +352,33 @@ SettingsDialog::showProxySettings()
void
SettingsDialog::toggleRemoteMode()
{
- ui->staticHostNamePortLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
- ui->staticHostName->setEnabled( ui->staticIpRadioButton->isChecked() );
- ui->staticPort->setEnabled( ui->staticIpRadioButton->isChecked() );
- ui->staticHostNameLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
- ui->staticPortLabel->setEnabled( ui->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticHostNamePortLabel->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticHostName->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticPort->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticHostNameLabel->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
+ m_advancedWidgetUi->staticPortLabel->setEnabled( m_advancedWidgetUi->staticIpRadioButton->isChecked() );
}
void
SettingsDialog::toggleProxyEnabled()
{
- ui->proxyButton->setEnabled( ui->enableProxyCheckBox->isChecked() );
+ m_advancedWidgetUi->proxyButton->setEnabled( m_advancedWidgetUi->enableProxyCheckBox->isChecked() );
}
void
SettingsDialog::updateScanOptionsView()
{
- if ( ui->checkBoxWatchForChanges->isChecked() )
+ if ( m_collectionWidgetUi->checkBoxWatchForChanges->isChecked() )
{
- ui->scanTimeLabel->show();
- ui->scannerTimeSpinBox->show();
+ m_collectionWidgetUi->scanTimeLabel->show();
+ m_collectionWidgetUi->scannerTimeSpinBox->show();
}
else
{
- ui->scanTimeLabel->hide();
- ui->scannerTimeSpinBox->hide();
+ m_collectionWidgetUi->scanTimeLabel->hide();
+ m_collectionWidgetUi->scannerTimeSpinBox->hide();
}
}
@@ -420,7 +386,7 @@ SettingsDialog::updateScanOptionsView()
void
SettingsDialog::accountsFilterChanged( int )
{
- AccountType filter = static_cast< AccountType >( ui->accountsFilterCombo->itemData( ui->accountsFilterCombo->currentIndex() ).toInt() );
+ AccountType filter = static_cast< AccountType >( m_accountsWidgetUi->accountsFilterCombo->itemData( m_accountsWidgetUi->accountsFilterCombo->currentIndex() ).toInt() );
m_accountProxy->setFilterType( filter );
}
@@ -445,13 +411,13 @@ SettingsDialog::openAccountFactoryConfig( AccountFactory* factory )
}
#ifndef Q_OS_MAC
- AccountFactoryWrapper dialog( factory, this );
+ AccountFactoryWrapper dialog( factory, 0 );
QWeakPointer< AccountFactoryWrapper > watcher( &dialog );
dialog.exec();
#else
// on osx a sheet needs to be non-modal
- AccountFactoryWrapper* dialog = new AccountFactoryWrapper( factory, this );
+ AccountFactoryWrapper* dialog = new AccountFactoryWrapper( factory, 0 );
dialog->show();
#endif
}
@@ -460,21 +426,21 @@ SettingsDialog::openAccountFactoryConfig( AccountFactory* factory )
void
SettingsDialog::createAccountFromFactory( AccountFactory* factory )
{
- TomahawkUtils::createAccountFromFactory( factory, this );
+ TomahawkUtils::createAccountFromFactory( factory, 0 );
}
void
SettingsDialog::openAccountConfig( Account* account, bool showDelete )
{
- TomahawkUtils::openAccountConfig( account, this, showDelete );
+ TomahawkUtils::openAccountConfig( account, 0, showDelete );
}
void
SettingsDialog::installFromFile()
{
- const QString resolver = QFileDialog::getOpenFileName( this, tr( "Install resolver from file" ), TomahawkSettings::instance()->scriptDefaultPath() );
+ const QString resolver = QFileDialog::getOpenFileName( 0, tr( "Install resolver from file" ), TomahawkSettings::instance()->scriptDefaultPath() );
if( !resolver.isEmpty() )
{
@@ -520,7 +486,7 @@ void
SettingsDialog::aclEntryClearButtonClicked()
{
QMessageBox::StandardButton button = QMessageBox::question(
- ui->stackedWidget,
+ 0,
tr( "Delete all Access Control entries?" ),
tr( "Do you really want to delete all Access Control entries? You will be asked for a decision again for each peer that you connect to." ),
QMessageBox::Ok | QMessageBox::Cancel,
@@ -529,7 +495,7 @@ SettingsDialog::aclEntryClearButtonClicked()
if ( button == QMessageBox::Ok )
{
ACLRegistry::instance()->wipeEntries();
- ui->aclEntryClearButton->setEnabled( false );
+ m_advancedWidgetUi->aclEntryClearButton->setEnabled( false );
}
}
@@ -537,7 +503,7 @@ SettingsDialog::aclEntryClearButtonClicked()
void
SettingsDialog::scrollTo( const QModelIndex& idx )
{
- ui->accountsView->scrollTo( idx, QAbstractItemView::PositionAtBottom );
+ m_accountsWidgetUi->accountsView->scrollTo( idx, QAbstractItemView::PositionAtBottom );
}
diff --git a/src/SettingsDialog.h b/src/SettingsDialog.h
index 88cb934a0..885997fde 100644
--- a/src/SettingsDialog.h
+++ b/src/SettingsDialog.h
@@ -31,14 +31,16 @@
class AnimatedSpinner;
class QListWidgetItem;
-class Ui_StackedSettingsDialog;
+class Ui_Settings_Accounts;
+class Ui_Settings_Collection;
+class Ui_Settings_Advanced;
class SipPlugin;
class ResolversModel;
class QNetworkReply;
+class QToolbarTabDialog;
namespace Ui
{
- class SettingsDialog;
class ProxyDialog;
}
@@ -68,14 +70,15 @@ private:
Ui::ProxyDialog* ui;
};
-class SettingsDialog : public QDialog
+class SettingsDialog : public QObject
{
Q_OBJECT
public:
- explicit SettingsDialog( QWidget* parent = 0 );
+ explicit SettingsDialog( QObject* parent = 0 );
~SettingsDialog();
+ void show();
protected:
void changeEvent( QEvent* e );
@@ -97,20 +100,26 @@ private slots:
void updateScanOptionsView();
- void changePage( QAction *action );
void serventReady();
void aclEntryClearButtonClicked();
-
+
void requiresRestart();
+private slots:
+ void saveSettings();
+
private:
- void createIcons();
+ Ui_Settings_Accounts* m_accountsWidgetUi;
+ QWidget* m_accountsWidget;
- Ui_StackedSettingsDialog* ui;
+ Ui_Settings_Collection* m_collectionWidgetUi;
+ QWidget* m_collectionWidget;
- QToolBar *m_toolBar;
- QActionGroup *m_settingsGroup;
+ Ui_Settings_Advanced* m_advancedWidgetUi;
+ QWidget* m_advancedWidget;
+
+ QToolbarTabDialog* m_dialog;
ProxyDialog m_proxySettings;
bool m_rejected;
diff --git a/src/Settings_Accounts.ui b/src/Settings_Accounts.ui
new file mode 100644
index 000000000..de51ed1f0
--- /dev/null
+++ b/src/Settings_Accounts.ui
@@ -0,0 +1,82 @@
+
+
+ Settings_Accounts
+
+
+
+ 0
+ 0
+ 553
+ 439
+
+
+
+ Form
+
+
+
+ 2
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Filter by capability:
+
+
+
+ -
+
+
+
+
+ -
+
+
+ true
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+
+
+
+
+
+ QButton
+ QWidget
+ thirdparty/Qocoa/qbutton.h
+ 1
+
+
+
+
+
diff --git a/src/Settings_Advanced.ui b/src/Settings_Advanced.ui
new file mode 100644
index 000000000..324bace00
--- /dev/null
+++ b/src/Settings_Advanced.ui
@@ -0,0 +1,271 @@
+
+
+ Settings_Advanced
+
+
+
+ 0
+ 0
+ 469
+ 475
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+ 2
+
+ -
+
+
+ Remote Peer Connection Method
+
+
+
-
+
+
+ None (outgoing connections only)
+
+
+
+ -
+
+
+ Use UPnP to establish port forward (recommended)
+
+
+
+ -
+
+
+ Use static external IP address/host name and port
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Set this to your external IP address or host name. Make sure to forward the port to this host!
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Static Host Name:
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Static Port:
+
+
+
+ -
+
+
+ 65535
+
+
+ 50210
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 10
+
+
+
+
+ -
+
+
+ SOCKS Proxy
+
+
+
-
+
+
+ Use SOCKS Proxy
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Expanding
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Proxy Settings...
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 10
+
+
+
+
+ -
+
+
+ Other Settings
+
+
+
-
+
+
+ Qt::LeftToRight
+
+
+ Allow web browsers to interact with Tomahawk (recommended)
+
+
+ true
+
+
+
+ -
+
+
+ Qt::LeftToRight
+
+
+ Send reports after Tomahawk crashed
+
+
+ true
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Expanding
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Clear All Access Control Entries
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 13
+
+
+
+
+
+
+
+
+
diff --git a/src/Settings_Collection.ui b/src/Settings_Collection.ui
new file mode 100644
index 000000000..6579d2d51
--- /dev/null
+++ b/src/Settings_Collection.ui
@@ -0,0 +1,102 @@
+
+
+ Settings_Collection
+
+
+
+ 0
+ 0
+ 403
+ 370
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+ 2
+
+ -
+
+
-
+
+
+ Path to scan for music files:
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ The Echo Nest supports keeping track of your catalog metadata
+ and using it to craft personalized radios. Enabling this option
+ will allow you (and all your friends) to create automatic playlists
+ and stations based on your personal taste profile.
+
+
+ Upload collection list to The Echo Nest to enable user radio
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Watch for changes
+
+
+
+ -
+
+
-
+
+
+ Time between scans, in seconds:
+
+
+
+ -
+
+
+ 60
+
+
+ 999999999
+
+
+
+
+
+
+
+
+
+
+
+ CheckDirTree
+ QTreeView
+
+
+
+
+
+
diff --git a/src/StackedSettingsDialog.ui b/src/StackedSettingsDialog.ui
index af3cfe49d..0377d15dd 100644
--- a/src/StackedSettingsDialog.ui
+++ b/src/StackedSettingsDialog.ui
@@ -6,8 +6,8 @@
0
0
- 655
- 500
+ 692
+ 604
@@ -22,7 +22,7 @@
-
- 0
+ 1
@@ -461,6 +461,12 @@
+ buttonBox
+
+ frame_4
+ frame_2
+ frameNetworkAdvanced
+ stackedWidget
diff --git a/src/TomahawkWindow.cpp b/src/TomahawkWindow.cpp
index 8f01a4103..c2a39f628 100644
--- a/src/TomahawkWindow.cpp
+++ b/src/TomahawkWindow.cpp
@@ -101,6 +101,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
, m_searchWidget( 0 )
, m_audioControls( new AudioControls( this ) )
, m_trayIcon( new TomahawkTrayIcon( this ) )
+ , m_settingsDialog( 0 )
, m_audioRetryCounter( 0 )
{
setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
@@ -803,8 +804,10 @@ TomahawkWindow::onHistoryForwardAvailable( bool avail )
void
TomahawkWindow::showSettingsDialog()
{
- SettingsDialog win;
- win.exec();
+ if ( !m_settingsDialog )
+ m_settingsDialog = new SettingsDialog;
+
+ m_settingsDialog->show();
}
diff --git a/src/TomahawkWindow.h b/src/TomahawkWindow.h
index 5191efce1..3289b5f8c 100644
--- a/src/TomahawkWindow.h
+++ b/src/TomahawkWindow.h
@@ -38,6 +38,7 @@
#include
#endif
+class SettingsDialog;
namespace Tomahawk
{
namespace Accounts
@@ -184,6 +185,7 @@ private:
QueueView* m_queueView;
AnimatedSplitter* m_sidebar;
JobStatusSortModel* m_jobsModel;
+ SettingsDialog* m_settingsDialog;
// Menus and menu actions: Accounts menu
QMenuBar *m_menuBar;
diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt
index c148deb59..ecec610b1 100644
--- a/src/libtomahawk/CMakeLists.txt
+++ b/src/libtomahawk/CMakeLists.txt
@@ -391,7 +391,9 @@ IF( APPLE )
SET( libSources ${libSources}
utils/TomahawkUtils_Mac.mm
mac/FileHelpers.mm
+ thirdparty/Qocoa/qbutton_mac.mm
thirdparty/Qocoa/qsearchfield_mac.mm
+ thirdparty/Qocoa/qtoolbartabdialog_mac.mm
widgets/SourceTreePopupDialog_mac.mm )
SET_SOURCE_FILES_PROPERTIES(utils/TomahawkUtils_Mac.mm PROPERTIES COMPILE_FLAGS "-fvisibility=default")
@@ -408,7 +410,7 @@ IF( APPLE )
/System/Library/Frameworks/Security.framework
)
ELSE( APPLE )
- SET( libGuiSources ${libGuiSources} thirdparty/Qocoa/qsearchfield.cpp )
+ SET( libGuiSources ${libGuiSources} thirdparty/Qocoa/qbutton.cpp thirdparty/Qocoa/qsearchfield.cpp thirdparty/Qocoa/qtoolbartabdialog.cpp )
ENDIF( APPLE )
IF(LIBLASTFM_FOUND)
diff --git a/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp b/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp
index 6a8c98b63..9d985f156 100644
--- a/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp
+++ b/src/libtomahawk/accounts/lastfm/LastFmConfig.cpp
@@ -294,7 +294,7 @@ LastFmConfig::onLovedFinished( QNetworkReply* reply )
m_ui->progressBar->setValue( thisPage );
foreach ( lastfm::XmlQuery e, loved.children( "track" ) )
{
-// tDebug() << "Found:" << e.children( "artist" ).first()["name"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt();
+ tDebug() << "Found:" << e.children( "artist" ).first()["name"].text() << e["name"].text() << e["date"].attribute( "uts" ).toUInt();
Tomahawk::query_ptr query = Tomahawk::Query::get( e.children( "artist" ).first()["name"].text(), e["name"].text(), QString(), QString(), false );
if ( query.isNull() )
continue;
@@ -336,6 +336,8 @@ LastFmConfig::onLovedFinished( QNetworkReply* reply )
bool trackEquality( const Tomahawk::query_ptr& first, const Tomahawk::query_ptr& second )
{
+ qDebug() << "Comparing:" << first->track() << second->track();
+ qDebug() << "==========" << first->artist() << second->artist();
return first->equals( second, true );
}
@@ -372,15 +374,20 @@ LastFmConfig::syncLoved()
foreach ( const Tomahawk::query_ptr& localLoved, myLoved )
{
+ qDebug() << "CHECKING FOR LOCAL LOVED ON LAST.FM TOO:" << m_localLoved[ localLoved ].value.toString() << localLoved->track() << localLoved->artist();
QSet< Tomahawk::query_ptr >::const_iterator iter = std::find_if( m_lastfmLoved.begin(), m_lastfmLoved.end(), boost::bind( &trackEquality, _1, boost::ref( localLoved ) ) );
+ qDebug() << "Result:" << (iter == m_lastfmLoved.constEnd());
// If we unloved it locally, but it's still loved on last.fm, unlove it
if ( m_localLoved[ localLoved ].value.toString() == "false" && iter != m_lastfmLoved.constEnd() )
lastFmToUnlove << localLoved;
// If we loved it locally but not loved on last.fm, love it
if ( m_localLoved[ localLoved ].value.toString() == "true" && iter == m_lastfmLoved.constEnd() )
+ {
+ qDebug() << "Found Local loved track but not on last.fm!:" << localLoved->track() << localLoved->artist();
lastFmToLove << localLoved;
+ }
}
foreach ( const Tomahawk::query_ptr& track, localToLove )
diff --git a/src/libtomahawk/thirdparty/Qocoa/qbutton.cpp b/src/libtomahawk/thirdparty/Qocoa/qbutton.cpp
new file mode 100644
index 000000000..0a79e2baf
--- /dev/null
+++ b/src/libtomahawk/thirdparty/Qocoa/qbutton.cpp
@@ -0,0 +1,89 @@
+/*
+Copyright (C) 2011 by Mike McQuaid
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "qbutton.h"
+
+#include
+#include
+#include
+#include
+
+class QButtonPrivate : public QObject
+{
+public:
+ QButtonPrivate(QButton *button, QAbstractButton *abstractButton)
+ : QObject(button), abstractButton(abstractButton) {}
+ QPointer abstractButton;
+};
+
+QButton::QButton(QWidget *parent, BezelStyle) : QWidget(parent)
+{
+ QAbstractButton *button = 0;
+ if (qobject_cast(parent))
+ button = new QToolButton(this);
+ else
+ button = new QPushButton(this);
+ connect(button, SIGNAL(clicked()),
+ this, SIGNAL(clicked()));
+ pimpl = new QButtonPrivate(this, button);
+
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->addWidget(button);
+}
+
+void QButton::setText(const QString &text)
+{
+ Q_ASSERT(pimpl);
+ if (pimpl)
+ pimpl->abstractButton->setText(text);
+}
+
+void QButton::setImage(const QPixmap &image)
+{
+ Q_ASSERT(pimpl);
+ if (pimpl)
+ pimpl->abstractButton->setIcon(image);
+}
+
+void QButton::setChecked(bool checked)
+{
+ Q_ASSERT(pimpl);
+ if (pimpl)
+ pimpl->abstractButton->setChecked(checked);
+}
+
+void QButton::setCheckable(bool checkable)
+{
+ Q_ASSERT(pimpl);
+ if (pimpl)
+ pimpl->abstractButton->setCheckable(checkable);
+}
+
+bool QButton::isChecked()
+{
+ Q_ASSERT(pimpl);
+ if (!pimpl)
+ return false;
+
+ return pimpl->abstractButton->isChecked();
+}
diff --git a/src/libtomahawk/thirdparty/Qocoa/qbutton.h b/src/libtomahawk/thirdparty/Qocoa/qbutton.h
new file mode 100644
index 000000000..591c37ffc
--- /dev/null
+++ b/src/libtomahawk/thirdparty/Qocoa/qbutton.h
@@ -0,0 +1,51 @@
+#ifndef QBUTTON_H
+#define QBUTTON_H
+
+#include
+#include
+
+#include "DllMacro.h"
+
+class QButtonPrivate;
+class DLLEXPORT QButton : public QWidget
+{
+ Q_OBJECT
+public:
+ // Matches NSBezelStyle
+ enum BezelStyle {
+ Rounded = 1,
+ RegularSquare = 2,
+ Disclosure = 5,
+ ShadowlessSquare = 6,
+ Circular = 7,
+ TexturedSquare = 8,
+ HelpButton = 9,
+ SmallSquare = 10,
+ TexturedRounded = 11,
+ RoundRect = 12,
+ Recessed = 13,
+ RoundedDisclosure = 14,
+#ifdef __MAC_10_7
+ Inline = 15
+#endif
+ };
+
+ explicit QButton(QWidget *parent, BezelStyle bezelStyle = Rounded);
+
+public slots:
+ void setText(const QString &text);
+ void setImage(const QPixmap &image);
+ void setChecked(bool checked);
+
+public:
+ void setCheckable(bool checkable);
+ bool isChecked();
+
+signals:
+ void clicked(bool checked = false);
+
+private:
+ friend class QButtonPrivate;
+ QPointer pimpl;
+};
+#endif // QBUTTON_H
diff --git a/src/libtomahawk/thirdparty/Qocoa/qbutton_mac.mm b/src/libtomahawk/thirdparty/Qocoa/qbutton_mac.mm
new file mode 100644
index 000000000..9dfdf9672
--- /dev/null
+++ b/src/libtomahawk/thirdparty/Qocoa/qbutton_mac.mm
@@ -0,0 +1,232 @@
+/*
+Copyright (C) 2011 by Mike McQuaid
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "qbutton.h"
+
+#include "qocoa_mac.h"
+
+#import "Foundation/NSAutoreleasePool.h"
+#import "AppKit/NSButton.h"
+#import "AppKit/NSFont.h"
+
+class QButtonPrivate : public QObject
+{
+public:
+ QButtonPrivate(QButton *qButton, NSButton *nsButton, QButton::BezelStyle bezelStyle)
+ : QObject(qButton), qButton(qButton), nsButton(nsButton)
+ {
+ switch(bezelStyle) {
+ case QButton::Disclosure:
+ case QButton::Circular:
+#ifdef __MAC_10_7
+ case QButton::Inline:
+#endif
+ case QButton::RoundedDisclosure:
+ case QButton::HelpButton:
+ [nsButton setTitle:@""];
+ default:
+ break;
+ }
+
+ NSFont* font = 0;
+ switch(bezelStyle) {
+ case QButton::RoundRect:
+ font = [NSFont fontWithName:@"Lucida Grande" size:12];
+ break;
+
+ case QButton::Recessed:
+ font = [NSFont fontWithName:@"Lucida Grande Bold" size:12];
+ break;
+
+#ifdef __MAC_10_7
+ case QButton::Inline:
+ font = [NSFont boldSystemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]];
+ break;
+#endif
+
+ default:
+ font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]];
+ break;
+ }
+ [nsButton setFont:font];
+
+ switch(bezelStyle) {
+ case QButton::Rounded:
+ qButton->setMinimumWidth(40);
+ qButton->setFixedHeight(24);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ break;
+ case QButton::RegularSquare:
+ case QButton::TexturedSquare:
+ qButton->setMinimumSize(14, 23);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ break;
+ case QButton::ShadowlessSquare:
+ qButton->setMinimumSize(5, 25);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ break;
+ case QButton::SmallSquare:
+ qButton->setMinimumSize(4, 21);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ break;
+ case QButton::TexturedRounded:
+ qButton->setMinimumSize(10, 22);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ break;
+ case QButton::RoundRect:
+ case QButton::Recessed:
+ qButton->setMinimumWidth(16);
+ qButton->setFixedHeight(18);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ break;
+ case QButton::Disclosure:
+ qButton->setMinimumWidth(13);
+ qButton->setFixedHeight(13);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ break;
+ case QButton::Circular:
+ qButton->setMinimumSize(16, 16);
+ qButton->setMaximumHeight(40);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ break;
+ case QButton::HelpButton:
+ case QButton::RoundedDisclosure:
+ qButton->setMinimumWidth(22);
+ qButton->setFixedHeight(22);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ break;
+#ifdef __MAC_10_7
+ case QButton::Inline:
+ qButton->setMinimumWidth(10);
+ qButton->setFixedHeight(16);
+ qButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ break;
+#endif
+ }
+
+ switch(bezelStyle) {
+ case QButton::Recessed:
+ [nsButton setButtonType:NSPushOnPushOffButton];
+ case QButton::Disclosure:
+ [nsButton setButtonType:NSOnOffButton];
+ default:
+ [nsButton setButtonType:NSMomentaryPushInButton];
+ }
+
+ [nsButton setBezelStyle:bezelStyle];
+ }
+
+ void clicked()
+ {
+ emit qButton->clicked(qButton->isChecked());
+ }
+
+ ~QButtonPrivate() {
+ [[nsButton target] release];
+ [nsButton setTarget:nil];
+ }
+
+ QButton *qButton;
+ NSButton *nsButton;
+};
+
+@interface QButtonTarget : NSObject
+{
+@public
+ QPointer pimpl;
+}
+-(void)clicked;
+@end
+
+@implementation QButtonTarget
+-(void)clicked {
+ Q_ASSERT(pimpl);
+ if (pimpl)
+ pimpl->clicked();
+}
+@end
+
+QButton::QButton(QWidget *parent, BezelStyle bezelStyle) : QWidget(parent)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSButton *button = [[NSButton alloc] init];
+ pimpl = new QButtonPrivate(this, button, bezelStyle);
+
+ QButtonTarget *target = [[QButtonTarget alloc] init];
+ target->pimpl = pimpl;
+ [button setTarget:target];
+
+ [button setAction:@selector(clicked)];
+
+ setupLayout(button, this);
+
+ [button release];
+
+ [pool drain];
+}
+
+void QButton::setText(const QString &text)
+{
+ Q_ASSERT(pimpl);
+ if (!pimpl)
+ return;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [pimpl->nsButton setTitle:fromQString(text)];
+ [pool drain];
+}
+
+void QButton::setImage(const QPixmap &image)
+{
+ Q_ASSERT(pimpl);
+ if (pimpl)
+ [pimpl->nsButton setImage:fromQPixmap(image)];
+}
+
+void QButton::setChecked(bool checked)
+{
+ Q_ASSERT(pimpl);
+ if (pimpl)
+ [pimpl->nsButton setState:checked];
+}
+
+void QButton::setCheckable(bool checkable)
+{
+ const NSInteger cellMask = checkable ? NSChangeBackgroundCellMask : NSNoCellMask;
+
+ Q_ASSERT(pimpl);
+ if (pimpl)
+ [[pimpl->nsButton cell] setShowsStateBy:cellMask];
+}
+
+bool QButton::isChecked()
+{
+ Q_ASSERT(pimpl);
+ if (!pimpl)
+ return false;
+
+ return [pimpl->nsButton state];
+}
+
+#include "moc_qbutton.cpp"
+
diff --git a/src/libtomahawk/thirdparty/Qocoa/qocoa_mac.h b/src/libtomahawk/thirdparty/Qocoa/qocoa_mac.h
index ee620a3a5..053f57a06 100644
--- a/src/libtomahawk/thirdparty/Qocoa/qocoa_mac.h
+++ b/src/libtomahawk/thirdparty/Qocoa/qocoa_mac.h
@@ -32,7 +32,7 @@ static inline NSString* fromQString(const QString &string)
{
const QByteArray utf8 = string.toUtf8();
const char* cString = utf8.constData();
- return [[NSString alloc] initWithUTF8String:cString];
+ return [[[NSString alloc] initWithUTF8String:cString] autorelease];
}
static inline QString toQString(NSString *string)
@@ -45,7 +45,7 @@ static inline QString toQString(NSString *string)
static inline NSImage* fromQPixmap(const QPixmap &pixmap)
{
CGImageRef cgImage = pixmap.toMacCGImageRef();
- return [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize];
+ return [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease];
}
static inline void setupLayout(void *cocoaView, QWidget *parent)
diff --git a/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog.cpp b/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog.cpp
new file mode 100644
index 000000000..4d7419915
--- /dev/null
+++ b/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog.cpp
@@ -0,0 +1,174 @@
+#include "qtoolbartabdialog.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class QToolbarTabDialogPrivate : public QObject {
+ Q_OBJECT
+public:
+ QToolbarTabDialogPrivate(QToolbarTabDialog* qq) : q(qq), layout(0), toolbar(0), rightSpacer(0), stack(0), separator(0), buttons(0), actionGroup(0) {}
+
+public slots:
+ void actionTriggered(QAction* action) {
+ if (dialog.isNull())
+ return;
+
+ const int idx = toolbar->actions().indexOf(action);
+ // There's a left spacer, so we want 1 less
+ Q_ASSERT(idx > 0);
+ if (idx < 1)
+ return;
+
+ stack->setCurrentIndex(idx - 1);
+ }
+
+ void accepted() {
+ Q_ASSERT(!dialog.isNull());
+ Q_ASSERT(!q.isNull());
+
+ dialog.data()->hide();
+ emit q.data()->accepted();
+ }
+
+ void rejected() {
+ Q_ASSERT(!dialog.isNull());
+ Q_ASSERT(!q.isNull());
+
+ dialog.data()->hide();
+ emit q.data()->rejected();
+ }
+
+public:
+ QWeakPointer dialog;
+ QWeakPointer q;
+
+ QVBoxLayout* layout;
+ QToolBar* toolbar;
+ QAction* rightSpacer;
+ QStackedWidget* stack;
+ QFrame* separator;
+ QDialogButtonBox* buttons;
+ QActionGroup* actionGroup;
+
+};
+
+QToolbarTabDialog::QToolbarTabDialog() :
+ QObject(0),
+ pimpl(new QToolbarTabDialogPrivate(this))
+{
+ pimpl->dialog = new QDialog;
+ pimpl->dialog.data()->setModal(true);
+
+ pimpl->toolbar = new QToolBar(pimpl->dialog.data());
+ pimpl->toolbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+
+ pimpl->stack = new QStackedWidget(pimpl->dialog.data());
+
+ pimpl->separator = new QFrame(pimpl->dialog.data());
+ pimpl->separator->setFrameShape(QFrame::HLine);
+ pimpl->separator->setFrameShadow(QFrame::Sunken);
+
+ pimpl->actionGroup = new QActionGroup(pimpl->dialog.data());
+
+ connect(pimpl->toolbar, SIGNAL(actionTriggered(QAction*)), pimpl.data(), SLOT(actionTriggered(QAction*)));
+
+ pimpl->buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, pimpl->dialog.data());
+ connect(pimpl->buttons, SIGNAL(accepted()), pimpl->dialog.data(), SLOT(accept()));
+ connect(pimpl->buttons, SIGNAL(rejected()), pimpl->dialog.data(), SLOT(reject()));
+
+ connect(pimpl->dialog.data(), SIGNAL(accepted()), pimpl.data(), SLOT(accepted()));
+ connect(pimpl->dialog.data(), SIGNAL(rejected()), pimpl.data(), SLOT(rejected()));
+
+ QWidget* leftSpacer = new QWidget(pimpl->toolbar);
+ leftSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ QWidget* rightSpacer = new QWidget(pimpl->toolbar);
+ rightSpacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ pimpl->toolbar->addWidget(leftSpacer);
+ pimpl->rightSpacer = pimpl->toolbar->addWidget(rightSpacer);
+
+ pimpl->layout = new QVBoxLayout;
+ pimpl->layout->setContentsMargins( 4, 4, 4, 4 );
+ pimpl->layout->addWidget(pimpl->toolbar);
+ pimpl->layout->addWidget(pimpl->separator);
+ pimpl->layout->addWidget(pimpl->stack);
+ pimpl->layout->addWidget(pimpl->buttons);
+ pimpl->dialog.data()->setLayout(pimpl->layout);
+}
+
+QToolbarTabDialog::~QToolbarTabDialog()
+{
+ if (pimpl && !pimpl->dialog.isNull()) {
+ delete pimpl->dialog.data();
+ }
+}
+
+void QToolbarTabDialog::addTab(QWidget* page, const QPixmap& icon, const QString& label, const QString& tooltip)
+{
+ Q_ASSERT(pimpl);
+ if (!pimpl)
+ return;
+
+ pimpl->toolbar->removeAction(pimpl->rightSpacer);
+
+ QAction* action = new QAction(icon, label, pimpl->toolbar);
+ action->setCheckable(true);
+ action->setToolTip(tooltip);
+
+ pimpl->actionGroup->addAction(action);
+
+ pimpl->toolbar->addAction(action);
+ pimpl->stack->addWidget(page);
+
+ pimpl->toolbar->addAction(pimpl->rightSpacer);
+}
+
+void QToolbarTabDialog::setCurrentIndex(int index)
+{
+ Q_ASSERT(pimpl);
+ if (!pimpl || pimpl->dialog.isNull())
+ return;
+
+
+ Q_ASSERT(index < pimpl->toolbar->actions().length() + 1);
+ Q_ASSERT(index < pimpl->stack->count());
+ if (index < 0 || index > pimpl->toolbar->actions().length())
+ return;
+ if (index > pimpl->stack->count())
+ return;
+
+ if (pimpl->stack->currentIndex() != index)
+ pimpl->stack->setCurrentIndex(index);
+
+ // 1 spacer item before the first action
+ QAction* toCheck = pimpl->toolbar->actions().at(index + 1);
+ if (pimpl->actionGroup->checkedAction() != toCheck)
+ toCheck->setChecked(true);
+}
+
+void QToolbarTabDialog::show()
+{
+ Q_ASSERT(pimpl);
+ Q_ASSERT(!pimpl->dialog.isNull());
+ if (!pimpl || pimpl->dialog.isNull())
+ return;
+
+ pimpl->dialog.data()->show();
+}
+
+void QToolbarTabDialog::hide()
+{
+ Q_ASSERT(pimpl);
+ Q_ASSERT(!pimpl->dialog.isNull());
+ if (!pimpl || pimpl->dialog.isNull())
+ return;
+
+ pimpl->dialog.data()->hide();
+}
+
+#include "qtoolbartabdialog.moc"
diff --git a/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog.h b/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog.h
new file mode 100644
index 000000000..d1e9aee74
--- /dev/null
+++ b/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2012 by Leo Franchi
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#ifndef QTOOLBARTABWIDGET_H
+#define QTOOLBARTABWIDGET_H
+
+#include
+#include
+#include
+
+#include "DllMacro.h"
+
+class QToolbarTabDialogPrivate;
+
+class QAction;
+
+/**
+ Dialog with a toolbar that behaves like a tab widget.
+
+ Note that on OS X there are no OK/Cancel buttons, every setting should be applied immediately.
+ The accepted() signal will be emitted on close/hide regardless.
+ */
+class DLLEXPORT QToolbarTabDialog : public QObject
+{
+ Q_OBJECT
+public:
+ QToolbarTabDialog();
+ virtual ~QToolbarTabDialog();
+
+ /*
+ * If the given widget has a QSizePolicy of Fixed in either direction, the dialog will not be resizable in that
+ * direction.
+ */
+ void addTab(QWidget* page, const QPixmap& icon, const QString& label, const QString& tooltip = QString());
+
+ void setCurrentIndex(int index);
+
+ void show();
+ void hide();
+
+Q_SIGNALS:
+ void accepted();
+ void rejected();
+
+private:
+ QScopedPointer pimpl;
+
+ friend class ::QToolbarTabDialogPrivate;
+};
+
+#endif // QTOOLBARTABWIDGET_H
diff --git a/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog_mac.mm b/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog_mac.mm
new file mode 100644
index 000000000..7c5fbced2
--- /dev/null
+++ b/src/libtomahawk/thirdparty/Qocoa/qtoolbartabdialog_mac.mm
@@ -0,0 +1,461 @@
+/*
+ Copyright (C) 2012 by Leo Franchi
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#include "qtoolbartabdialog.h"
+
+#include "qocoa_mac.h"
+
+#import
+#import
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+struct ItemData {
+ QPixmap icon;
+ QString text, tooltip;
+ QMacNativeWidget* nativeWidget;
+ QWidget* page;
+};
+
+
+namespace {
+
+static const int TOOLBAR_ITEM_WIDTH = 32;
+
+CGFloat ToolbarHeightForWindow(NSWindow *window)
+{
+ CGFloat toolbarHeight = 0.0f;
+
+ NSToolbar *toolbar = toolbar = [window toolbar];
+
+ if(toolbar && [toolbar isVisible])
+ {
+ NSRect windowFrame = [NSWindow contentRectForFrameRect:[window frame]
+ styleMask:[window styleMask]];
+ toolbarHeight = NSHeight(windowFrame) - NSHeight([[window contentView] frame]);
+ }
+
+ return toolbarHeight;
+}
+
+};
+
+@interface ToolbarDelegate : NSObject
+{
+ QToolbarTabDialogPrivate *pimpl;
+}
+// Internal
+-(void)setPrivate:(QToolbarTabDialogPrivate*)withPimpl;
+
+// NSToolbarItem action
+-(void)changePanes:(id)sender;
+
+// NSToolbarDelegate
+-(NSToolbarItem *) toolbar: (NSToolbar *)toolbar itemForItemIdentifier: (NSString *) itemIdent willBeInsertedIntoToolbar:(BOOL) willBeInserted;
+-(NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar;
+-(NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar;
+-(NSArray*) toolbarSelectableItemIdentifiers: (NSToolbar*)toolbar;
+
+// NSWindowDelegate
+-(NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize;
+-(void)windowWillClose:(NSNotification *)notification;
+@end
+
+class QToolbarTabDialogPrivate {
+public:
+ QToolbarTabDialogPrivate(QToolbarTabDialog* dialog) : q(dialog),
+ currentPane(NULL),
+ minimumWidth(0)
+ {
+ }
+
+ ~QToolbarTabDialogPrivate() {
+ // unset the delegate and toolbar from the window and manually release them
+ // otherwise, for some reason the old delegate is laying around when we
+ // create a new NSWindow
+ [[prefsWindow toolbar] setDelegate:NULL];
+ [prefsWindow setToolbar:NULL];
+ [prefsWindow release];
+ [toolBar release];
+ [toolBarDelegate release];
+ }
+
+ void calculateSize() {
+ NSRect windowFrame = [prefsWindow frame];
+
+ while ([[toolBar visibleItems] count] < [[toolBar items] count]) {
+ //Each toolbar item is 32x32; we expand by one toolbar item width repeatedly until they all fit
+ windowFrame.origin.x -= TOOLBAR_ITEM_WIDTH / 2;
+ windowFrame.size.width += TOOLBAR_ITEM_WIDTH / 2;
+
+ [prefsWindow setFrame:windowFrame display:NO];
+ [prefsWindow setMinSize: windowFrame.size];
+ }
+ minimumWidth = windowFrame.size.width;
+ }
+
+ void showPaneWithIdentifier(NSString* ident) {
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+ const QString identStr = toQString(ident);
+ Q_ASSERT(items.contains(identStr));
+ if (!items.contains(identStr))
+ return;
+
+ QWidget* newWidget = items[identStr].nativeWidget;
+ Q_ASSERT(newWidget);
+ if (!newWidget)
+ return;
+
+ QWidget* newPage = items[identStr].page;
+ Q_ASSERT(newPage);
+ if (!newPage)
+ return;
+
+ const NSRect oldFrame = [[prefsWindow contentView] frame];
+
+ // Clear first responder on window and set a temporary NSView on the window
+ // while we change the widget out underneath
+ [prefsWindow makeFirstResponder:nil];
+
+ NSView *tempView = [[NSView alloc] initWithFrame:[[prefsWindow contentView] frame]];
+ [prefsWindow setContentView:tempView];
+ [tempView release];
+
+ QSize sizeToUse = newPage->sizeHint().isNull() ? newPage->size() : newPage->sizeHint();
+ sizeToUse.setWidth(qMax(sizeToUse.width(), newPage->minimumWidth()));
+ sizeToUse.setHeight(qMax(sizeToUse.height(), newPage->minimumHeight()));
+
+ static const int spacing = 4;
+
+ [prefsWindow setMinSize:NSMakeSize(sizeToUse.width(), sizeToUse.height())];
+
+ // Make room for the new view
+ NSRect newFrame = [prefsWindow frame];
+ newFrame.size.height = sizeToUse.height() + ([prefsWindow frame].size.height - [[prefsWindow contentView] frame].size.height) + spacing;
+ newFrame.size.width = sizeToUse.width() + spacing;
+
+ // Don't resize the width---only the height, so use the maximum width for any page
+ // or the same width as before, if the user already resized it to be larger.
+ newFrame.size.width < minimumWidth ? newFrame.size.width = minimumWidth
+ : newFrame.size.width = qMax(newFrame.size.width, oldFrame.size.width);
+
+ // Preserve upper left point of window during resize.
+ newFrame.origin.y += ([[prefsWindow contentView] frame].size.height - sizeToUse.height()) - spacing;
+
+ [prefsWindow setFrame:newFrame display:YES animate:YES];
+
+ [prefsWindow setContentView: [panes objectForKey:ident]];
+ currentPane = ident;
+
+ // Resize the Qt widget immediately as well
+ resizeCurrentPageToSize([[prefsWindow contentView] frame].size);
+
+ NSSize minSize = [prefsWindow frame].size;
+ minSize.height -= ToolbarHeightForWindow(prefsWindow);
+
+ [prefsWindow setMinSize:minSize];
+
+ BOOL canResize = YES;
+ NSSize maxSize = NSMakeSize(FLT_MAX, FLT_MAX);
+
+ if (newPage->sizePolicy().horizontalPolicy() == QSizePolicy::Fixed) {
+ canResize = NO;
+ maxSize.width = sizeToUse.width();
+ }
+ if (newPage->sizePolicy().verticalPolicy() == QSizePolicy::Fixed) {
+ canResize = NO;
+ maxSize.height = sizeToUse.height();
+ }
+
+
+ [prefsWindow setMaxSize:maxSize];
+ [prefsWindow setShowsResizeIndicator:canResize];
+
+ [prefsWindow setTitle:ident];
+ [prefsWindow makeFirstResponder:[panes objectForKey:ident]];
+
+ [pool drain];
+ }
+
+ void resizeCurrentPageToSize(NSSize frameSize) {
+ const QString curPane = toQString(currentPane);
+ if (items.contains(curPane) && items[curPane].nativeWidget) {
+ items[curPane].nativeWidget->resize(frameSize.width, frameSize.height);
+ }
+ }
+
+ void emitAccepted() {
+ if (q.isNull())
+ return;
+
+ q.data()->accepted();
+ }
+
+ QWeakPointer q;
+
+ NSWindow* prefsWindow;
+ ToolbarDelegate *toolBarDelegate;
+ QMap items;
+
+ NSMutableDictionary *panes;
+ NSToolbar *toolBar;
+ NSString* currentPane;
+
+ int minimumWidth;
+};
+
+
+@implementation ToolbarDelegate
+
+-(id) init {
+ if( self = [super init] )
+ {
+ pimpl = nil;
+ }
+
+ return self;
+}
+
+-(void) setPrivate:(QToolbarTabDialogPrivate *)withPimpl
+{
+ pimpl = withPimpl;
+}
+
+-(void)changePanes:(id)sender
+{
+ Q_UNUSED(sender);
+ if (!pimpl)
+ return;
+
+ pimpl->showPaneWithIdentifier([pimpl->toolBar selectedItemIdentifier]);
+}
+
+-(NSToolbarItem *) toolbar: (NSToolbar *)toolbar itemForItemIdentifier: (NSString *) itemIdent willBeInsertedIntoToolbar:(BOOL) willBeInserted
+{
+ Q_UNUSED(toolbar);
+ Q_UNUSED(willBeInserted);
+ if (!pimpl)
+ return nil;
+
+ NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdent] autorelease];
+ const QString identQStr = toQString(itemIdent);
+ if (pimpl->items.contains(identQStr))
+ {
+ const ItemData& data = pimpl->items[identQStr];
+ NSString* label = fromQString(data.text);
+
+ [toolbarItem setLabel:label];
+ [toolbarItem setPaletteLabel:label];
+
+ [toolbarItem setToolTip:fromQString(data.tooltip)];
+ [toolbarItem setImage:fromQPixmap(data.icon)];
+
+ [toolbarItem setTarget: self];
+ [toolbarItem setAction: @selector(changePanes:)];
+
+ } else {
+ toolbarItem = nil;
+ }
+
+ return toolbarItem;
+}
+
+-(NSArray*) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
+{
+ Q_UNUSED(toolbar);
+ if (!pimpl)
+ return [NSArray array];
+
+ NSMutableArray* allowedItems = [[[NSMutableArray alloc] init] autorelease];
+
+ Q_FOREACH( const QString& identQStr, pimpl->items.keys())
+ [allowedItems addObject:fromQString(identQStr)];
+
+ [allowedItems addObjectsFromArray:[NSArray arrayWithObjects:NSToolbarSeparatorItemIdentifier,
+ NSToolbarSpaceItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier,
+ NSToolbarCustomizeToolbarItemIdentifier, nil] ];
+
+ return allowedItems;
+}
+
+
+-(NSArray*) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
+{
+ Q_UNUSED(toolbar);
+ if (!pimpl)
+ return [NSArray array];
+
+ return [[[NSMutableArray alloc] initWithArray:[pimpl->panes allKeys]] autorelease];
+
+}
+
+
+-(NSArray*) toolbarSelectableItemIdentifiers: (NSToolbar*)toolbar
+{
+ Q_UNUSED(toolbar);
+ if (!pimpl)
+ return [NSArray array];
+
+ return [[[NSMutableArray alloc] initWithArray:[pimpl->panes allKeys]] autorelease];
+}
+
+-(NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
+{
+ if (!pimpl)
+ return frameSize;
+
+ pimpl->resizeCurrentPageToSize([[sender contentView] frame].size);
+
+ return frameSize;
+}
+
+-(void)windowWillClose:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+
+ pimpl->emitAccepted();
+}
+@end
+
+QToolbarTabDialog::QToolbarTabDialog() :
+ QObject(0),
+ pimpl(new QToolbarTabDialogPrivate(this))
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ pimpl->panes = [[NSMutableDictionary alloc] init];
+
+ static const int defaultWidth = 350;
+ static const int defaultHeight = 200;
+ pimpl->prefsWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, defaultWidth, defaultHeight)
+ styleMask:NSClosableWindowMask | NSResizableWindowMask | NSTitledWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+
+ [pimpl->prefsWindow setReleasedWhenClosed:NO];
+ [pimpl->prefsWindow setTitle:@"Preferences"];
+
+ // identifier is some app-unique string, since all toolbars in an app share state. make this unique to this app's preferences window
+ pimpl->toolBar = [[NSToolbar alloc] initWithIdentifier:[NSString stringWithFormat:@"%@.prefspanel.toolbar", fromQString(QCoreApplication::instance()->applicationName())]];
+ [pimpl->toolBar setAllowsUserCustomization: NO];
+ [pimpl->toolBar setAutosavesConfiguration: NO];
+ [pimpl->toolBar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
+
+ pimpl->toolBarDelegate = [[ToolbarDelegate alloc] init];
+ [pimpl->toolBarDelegate setPrivate:pimpl.data()];
+
+ [pimpl->prefsWindow setDelegate:pimpl->toolBarDelegate];
+ [pimpl->toolBar setDelegate:pimpl->toolBarDelegate];
+
+ [pimpl->prefsWindow setToolbar:pimpl->toolBar];
+
+ [pool drain];
+}
+
+QToolbarTabDialog::~QToolbarTabDialog()
+{
+}
+
+void QToolbarTabDialog::addTab(QWidget* page, const QPixmap& icon, const QString& label, const QString& tooltip)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSString* identifier = fromQString(label);
+
+ QMacNativeWidget* nativeWidget = new QMacNativeWidget;
+ nativeWidget->move(0, 0);
+ nativeWidget->setPalette(page->palette());
+ nativeWidget->setAutoFillBackground(true);
+
+ QVBoxLayout* l = new QVBoxLayout;
+ l->setContentsMargins(2, 2, 2, 2);
+ l->setSpacing(0);
+ page->setAttribute(Qt::WA_LayoutUsesWidgetRect);
+ l->addWidget(page);
+ nativeWidget->setLayout(l);
+
+ NSView *nativeView = reinterpret_cast(nativeWidget->winId());
+ [nativeView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ [nativeView setAutoresizesSubviews:YES];
+
+ pimpl->minimumWidth = qMax(pimpl->minimumWidth, page->sizeHint().width());
+
+ nativeWidget->show();
+
+ ItemData data;
+ data.icon = icon;
+ data.text = label;
+ data.tooltip = tooltip;
+ data.nativeWidget = nativeWidget;
+ data.page = page;
+ pimpl->items.insert(label, data);
+
+ [pimpl->panes setObject:nativeView forKey:identifier];
+
+ pimpl->showPaneWithIdentifier(identifier);
+
+ [pimpl->toolBar insertItemWithItemIdentifier:identifier atIndex:[[pimpl->toolBar items] count]];
+ [pimpl->toolBar setSelectedItemIdentifier:identifier];
+ [[pimpl->prefsWindow standardWindowButton:NSWindowZoomButton] setEnabled:NO];
+
+ pimpl->calculateSize();
+ [pool drain];
+}
+
+
+void QToolbarTabDialog::setCurrentIndex(int index)
+{
+ Q_ASSERT(pimpl);
+ if (!pimpl)
+ return;
+
+ [pimpl->toolBar setSelectedItemIdentifier:[[[pimpl->toolBar items] objectAtIndex:index] itemIdentifier]];
+ pimpl->showPaneWithIdentifier([[[pimpl->toolBar items] objectAtIndex:index] itemIdentifier]);
+}
+
+void QToolbarTabDialog::show()
+{
+ Q_ASSERT(pimpl);
+ if (!pimpl)
+ return;
+
+ [pimpl->prefsWindow center];
+ [pimpl->prefsWindow makeKeyAndOrderFront:nil];
+}
+
+void QToolbarTabDialog::hide()
+{
+ Q_ASSERT(pimpl);
+ if (!pimpl)
+ return;
+
+ [pimpl->prefsWindow close];
+ emit accepted();
+}
+
+#include "moc_qtoolbartabdialog.cpp"