1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-15 10:33:59 +02:00

Merge branch 'qocoa'

This commit is contained in:
Leo Franchi
2012-08-16 21:54:24 -04:00
18 changed files with 1773 additions and 244 deletions

View File

@@ -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

View File

@@ -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( "<b>Services</b><br>"
"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( "<b>Collection</b><br>"
"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( "<b>Advanced</b><br>"
"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 );
}

View File

@@ -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;

82
src/Settings_Accounts.ui Normal file
View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Settings_Accounts</class>
<widget class="QWidget" name="Settings_Accounts">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>553</width>
<height>439</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QButton" name="installFromFileBtn" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Filter by capability:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="accountsFilterCombo"/>
</item>
</layout>
</item>
<item>
<widget class="QListView" name="accountsView">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QButton</class>
<extends>QWidget</extends>
<header>thirdparty/Qocoa/qbutton.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

271
src/Settings_Advanced.ui Normal file
View File

@@ -0,0 +1,271 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Settings_Advanced</class>
<widget class="QWidget" name="Settings_Advanced">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>475</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>2</number>
</property>
<item>
<widget class="QGroupBox" name="remoteConnectionsGroupBox">
<property name="title">
<string>Remote Peer Connection Method</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QRadioButton" name="lanOnlyRadioButton">
<property name="text">
<string>None (outgoing connections only)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="upnpRadioButton">
<property name="text">
<string>Use UPnP to establish port forward (recommended)</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="staticIpRadioButton">
<property name="text">
<string>Use static external IP address/host name and port</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="staticHostNamePortLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Set this to your external IP address or host name. Make sure to forward the port to this host!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="staticHostNamePortLayout">
<item>
<widget class="QLabel" name="staticHostNameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Static Host Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="staticHostName"/>
</item>
<item>
<widget class="QLabel" name="staticPortLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Static Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="staticPort">
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>50210</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="proxyGroupBox">
<property name="title">
<string>SOCKS Proxy</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="enableProxyCheckBox">
<property name="text">
<string>Use SOCKS Proxy</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="proxyButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Proxy Settings...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="otherSettingsGroupBox">
<property name="title">
<string>Other Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="checkBoxHttp">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Allow web browsers to interact with Tomahawk (recommended)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxReporter">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Send reports after Tomahawk crashed</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="aclEntryClearLayout">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="aclEntryClearButton">
<property name="text">
<string>Clear All Access Control Entries</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

102
src/Settings_Collection.ui Normal file
View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Settings_Collection</class>
<widget class="QWidget" name="Settings_Collection">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>403</width>
<height>370</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>2</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Path to scan for music files:</string>
</property>
</widget>
</item>
<item>
<widget class="CheckDirTree" name="dirTree"/>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_17">
<item>
<widget class="QCheckBox" name="enableEchonestCatalog">
<property name="toolTip">
<string>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.</string>
</property>
<property name="text">
<string>Upload collection list to The Echo Nest to enable user radio</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxWatchForChanges">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Watch for changes</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="scanTimeLabel">
<property name="text">
<string>Time between scans, in seconds:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="scannerTimeSpinBox">
<property name="minimum">
<number>60</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>CheckDirTree</class>
<extends>QTreeView</extends>
<header location="global">widgets/CheckDirTree.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>655</width>
<height>500</height>
<width>692</width>
<height>604</height>
</rect>
</property>
<property name="windowTitle">
@@ -22,7 +22,7 @@
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="accountsPage">
<layout class="QVBoxLayout" name="verticalLayout_11">
@@ -461,6 +461,12 @@
</widget>
</item>
</layout>
<zorder>buttonBox</zorder>
<zorder></zorder>
<zorder>frame_4</zorder>
<zorder>frame_2</zorder>
<zorder>frameNetworkAdvanced</zorder>
<zorder>stackedWidget</zorder>
</widget>
<customwidgets>
<customwidget>

View File

@@ -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();
}

View File

@@ -38,6 +38,7 @@
#include <shobjidl.h>
#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;

View File

@@ -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)

View File

@@ -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 )

View File

@@ -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 <QToolBar>
#include <QToolButton>
#include <QPushButton>
#include <QVBoxLayout>
class QButtonPrivate : public QObject
{
public:
QButtonPrivate(QButton *button, QAbstractButton *abstractButton)
: QObject(button), abstractButton(abstractButton) {}
QPointer<QAbstractButton> abstractButton;
};
QButton::QButton(QWidget *parent, BezelStyle) : QWidget(parent)
{
QAbstractButton *button = 0;
if (qobject_cast<QToolBar*>(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();
}

View File

@@ -0,0 +1,51 @@
#ifndef QBUTTON_H
#define QBUTTON_H
#include <QWidget>
#include <QPointer>
#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<QButtonPrivate> pimpl;
};
#endif // QBUTTON_H

View File

@@ -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<QButtonPrivate> 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"

View File

@@ -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)

View File

@@ -0,0 +1,174 @@
#include "qtoolbartabdialog.h"
#include <QToolBar>
#include <QStackedWidget>
#include <QAction>
#include <QVBoxLayout>
#include <QDialog>
#include <QDialogButtonBox>
#include <QDebug>
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<QDialog> dialog;
QWeakPointer<QToolbarTabDialog> 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"

View File

@@ -0,0 +1,70 @@
/*
Copyright (C) 2012 by Leo Franchi <lfranchi@kde.org>
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 <QObject>
#include <QScopedPointer>
#include <QPixmap>
#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<QToolbarTabDialogPrivate> pimpl;
friend class ::QToolbarTabDialogPrivate;
};
#endif // QTOOLBARTABWIDGET_H

View File

@@ -0,0 +1,461 @@
/*
Copyright (C) 2012 by Leo Franchi <lfranchi@kde.org>
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 <Foundation/NSAutoreleasePool.h>
#import <AppKit/NSToolbar.h>
#include <QCoreApplication>
#include <QIcon>
#include <QMap>
#include <QUuid>
#include <QMacNativeWidget>
#include <QPointer>
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<NSToolbarDelegate, NSWindowDelegate>
{
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<QToolbarTabDialog> q;
NSWindow* prefsWindow;
ToolbarDelegate *toolBarDelegate;
QMap<QString, ItemData> 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<NSView*>(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"