You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
amarok/amarok/src/browserbar.cpp

409 lines
11 KiB

/***************************************************************************
* Copyright (C) 2004, 2005 Max Howell <max.howell@methylblue.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "amarok.h"
#include "amarokconfig.h"
#include "browserbar.h"
#include "debug.h"
#include "enginecontroller.h"
#include "multitabbar.h" //m_tabBar
#include <kapplication.h> //kapp
#include <kconfig.h>
#include <kiconloader.h> //multiTabBar icons
#include <klocale.h>
#include <tqcursor.h> //for resize cursor
#include <tqpainter.h>
#include <tqsignalmapper.h> //m_mapper
#include <tqstyle.h> //Amarok::Splitter
#include <tqtooltip.h>
// we emulate a qsplitter, mostly for historic reasons, but there are still a few advantages
// mostly we can stop the browserbar getting resized too small so that switching browser looks wrong
namespace Amarok
{
class Splitter : public TQWidget {
public:
Splitter( BrowserBar *w ) : TQWidget( w, "divider" )
{
setCursor( TQCursor(SplitHCursor) );
styleChange( tqstyle() );
}
virtual void paintEvent( TQPaintEvent* )
{
TQPainter p( this );
parentWidget()->tqstyle().tqdrawPrimitive( TQStyle::PE_Splitter, &p, rect(), colorGroup(), TQStyle::Style_Horizontal );
}
virtual void styleChange( TQStyle& )
{
setFixedWidth( tqstyle().pixelMetric( TQStyle::PM_SplitterWidth, this ) );
}
virtual void mouseMoveEvent( TQMouseEvent *e )
{
static_cast<BrowserBar*>(TQT_TQWIDGET(parent()))->mouseMovedOverSplitter( e );
}
};
}
BrowserBar* BrowserBar::s_instance = 0;
BrowserBar::BrowserBar( TQWidget *parent )
: TQWidget( parent, "BrowserBar" )
, EngineObserver( EngineController::instance() )
, m_playlistBox( new TQVBox( this ) )
, m_divider( new Amarok::Splitter( this ) )
, m_browserBox( new TQVBox( this ) )
, m_currentIndex( -1 )
, m_lastIndex( -1 )
, m_mapper( new TQSignalMapper( TQT_TQOBJECT(this) ) )
{
m_tabManagementButton = new TQPushButton( SmallIconSet(Amarok::icon( "configure" )), 0, this, "tab_managment_button" );
connect (m_tabManagementButton, TQT_SIGNAL(clicked()), TQT_SLOT(showBrowserSelectionMenu()));
m_tabManagementButton->setIsMenuButton ( true ); //deprecated, but since I cannot add menu directly to button it is needed.
TQToolTip::add (m_tabManagementButton, i18n("Manage tabs"));
m_tabBar = new MultiTabBar( MultiTabBar::Vertical, this );
m_tabManagementButton->setFixedWidth(m_tabBar->sizeHint().width());
m_tabManagementButton->setFixedHeight(m_tabBar->sizeHint().width());
s_instance = this;
m_pos = m_tabBar->sizeHint().width() + 5; //5 = esthetic spacing
m_tabBar->setStyle( MultiTabBar::AMAROK );
m_tabBar->setPosition( MultiTabBar::Left );
m_tabBar->showActiveTabTexts( true );
m_tabBar->setFixedWidth( m_pos );
m_tabBar->move( 0, 25 );
TQVBoxLayout *layout = new TQVBoxLayout( m_browserBox );
layout->addSpacing( 3 ); // aesthetics
layout->setAutoAdd( true );
m_browserBox->move( m_pos, 0 );
m_browserBox->hide();
m_divider->hide();
m_playlistBox->setSpacing( 1 );
connect( m_mapper, TQT_SIGNAL(mapped( int )), TQT_SLOT(showHideBrowser( int )) );
//m_tabBar->appendButton( Amarok::icon( "configure" ), 1, 0, TQString() );
}
BrowserBar::~BrowserBar()
{
KConfig* const config = Amarok::config( "BrowserBar" );
config->writeEntry( "CurrentPane", m_currentIndex != -1 ? TQString(currentBrowser()->name()) : TQString() );
config->writeEntry( "Width", m_browserBox->width() );
}
void
BrowserBar::makeDropProxy( const TQString &name, DropProxyTarget *finalTarget )
{
int id = m_browserIds[name];
MultiTabBarButton *button = m_tabBar->tab( id );
if( button )
button->proxyDrops( finalTarget );
}
int
BrowserBar::restoreWidth()
{
const int index = indexForName( Amarok::config( "BrowserBar" )->readEntry( "CurrentPane" ) );
const int width = Amarok::config( "BrowserBar" )->readNumEntry( "Width", browser( index )->sizeHint().width() );
m_browserBox->resize( width, height() );
m_pos = m_browserBox->width() + m_tabBar->width();
return index;
}
void
BrowserBar::polish()
{
DEBUG_FUNC_INFO
TQWidget::polish();
uint M = 0;
foreachType( BrowserList, m_browsers ) {
const uint m = (*it)->minimumWidth();
if (m > M)
M = m;
if (m > 250) {
warning() << "Browser is too large, mxcl says castrate the developer: " << (*it)->name() << ", " << M << endl;
M = 250;
}
}
m_browserBox->setMinimumWidth( M );
const int index = restoreWidth();
if (index != -1)
// if we did it for -1 it ruins the browserBox size
showHideBrowser( index );
}
void
BrowserBar::adjustWidgetSizes()
{
//TODO set the geometry of the PlaylistWindow before
// the browsers are loaded so this isn't called twice
const uint w = width();
const uint h = height();
const uint maxW = maxBrowserWidth();
const uint p = (m_pos < maxW) ? m_pos : maxW;
const uint ppw = p + m_divider->width();
const uint tbw = m_tabBar->width();
m_divider->move( p, 0 );
const uint offset = !m_divider->isHidden() ? ppw : tbw;
m_browserBox->resize( p - tbw, h );
m_playlistBox->setGeometry( offset, 0, w - offset, h );
}
void
BrowserBar::mouseMovedOverSplitter( TQMouseEvent *e )
{
const uint oldPos = m_pos;
const uint newPos = mapFromGlobal( e->globalPos() ).x();
const uint minWidth = m_tabBar->width() + m_browserBox->minimumWidth();
const uint maxWidth = maxBrowserWidth();
if( newPos < minWidth )
m_pos = minWidth;
else if( newPos > maxWidth )
m_pos = maxWidth;
else
m_pos = newPos;
if( m_pos != oldPos )
adjustWidgetSizes();
}
bool
BrowserBar::event( TQEvent *e )
{
switch( e->type() )
{
case TQEvent::LayoutHint:
//FIXME include browserholder width
setMinimumWidth(
m_tabBar->minimumWidth() +
m_divider->minimumWidth() +
m_browserBox->width() +
m_playlistBox->minimumWidth() );
break;
case TQEvent::Resize:
// DEBUG_LINE_INFO
m_divider->resize( 0, height() ); //TQt will set width
m_tabBar->resize( 0, height() ); //TQt will set width
adjustWidgetSizes();
return true;
default:
;
}
return TQWidget::event( e );
}
void
BrowserBar::addBrowser( const TQString &identifier, TQWidget *widget, const TQString &title, const TQString& icon )
{
const int id = m_tabBar->tabs()->count(); // the next available id
const TQString name( widget->name() );
m_browserIds[name] = id;
TQWidget *tab;
widget->reparent( m_browserBox, TQPoint() );
widget->hide();
m_tabBar->appendTab( SmallIcon( icon ), id, title, identifier );
tab = m_tabBar->tab( id );
tab->setFocusPolicy( TQ_NoFocus ); //FIXME you can focus on the tab, but they respond to no input!
//we use a SignalMapper to show/hide the corresponding browser when tabs are clicked
connect( tab, TQT_SIGNAL(clicked()), m_mapper, TQT_SLOT(map()) );
m_mapper->setMapping( TQT_TQOBJECT(tab), id );
connect( tab, TQT_SIGNAL(initiateDrag ( int ) ), this, TQT_SLOT( showBrowser( int )) );
m_browsers.push_back( widget );
}
void
BrowserBar::removeMediaBrowser( TQWidget *widget )
{
BrowserList::iterator it = tqFind( m_browsers.begin(), m_browsers.end(), widget );
if( it != m_browsers.end() )
m_browsers.erase( it );
TQWidget *tab;
tab = m_tabBar->tab( m_browserIds["MediaBrowser"] );
m_mapper->removeMappings( TQT_TQOBJECT(tab) );
m_tabBar->removeTab( m_browserIds["MediaBrowser"] );
}
void
BrowserBar::showHideBrowser( int index )
{
const int prevIndex = m_currentIndex;
if( m_currentIndex != -1 ) {
///first we need to hide the currentBrowser
m_currentIndex = -1; //to prevent race condition, see CVS history
m_browsers[prevIndex]->hide();
m_tabBar->setTab( prevIndex, false );
}
if( index == prevIndex ) {
///close the BrowserBar
m_browserBox->hide();
m_divider->hide();
adjustWidgetSizes();
}
else if( (uint)index < m_browsers.count() ) {
///open up target
TQWidget* const target = m_browsers[index];
m_currentIndex = index;
m_divider->show();
target->show();
target->setFocus();
m_browserBox->show();
m_tabBar->setTab( index, true );
if( prevIndex == -1 ) {
// we need to show the browserBox
// m_pos dictates how everything will be sized in adjustWidgetSizes()
m_pos = m_browserBox->width() + m_tabBar->width();
adjustWidgetSizes();
}
}
emit browserActivated( index );
}
void
BrowserBar::showHideVisibleBrowser( int index )
{
int realindex = -1;
TQPtrList<MultiTabBarTab> tabs = *m_tabBar->tabs();
for( int i = 0, n = tabs.count(); i < n; ++i )
{
if( tabs.at( i )->visible() )
index--;
if( index < 0 )
{
realindex = i;
break;
}
}
if( realindex >= 0 )
showHideBrowser( realindex );
}
TQWidget*
BrowserBar::browser( const TQString &name ) const
{
foreachType( BrowserList, m_browsers )
if( name == (*it)->name() )
return *it;
return 0;
}
int
BrowserBar::visibleCount() const
{
int num = 0;
TQPtrList<MultiTabBarTab> tabs = *m_tabBar->tabs();
for( int i = 0, n = tabs.count(); i < n; ++i )
{
if( tabs.at( i )->visible() )
num++;
}
return num;
}
int
BrowserBar::indexForName( const TQString &name ) const
{
for( uint x = 0; x < m_browsers.count(); ++x )
if( name == m_browsers[x]->name() )
return x;
return -1;
}
void
BrowserBar::showBrowserSelectionMenu()
{
m_tabBar->showTabSelectionMenu(mapToGlobal(TQPoint(m_tabManagementButton->pos().x(), m_tabManagementButton->pos().y() +m_tabManagementButton->height() )));
}
void
BrowserBar::engineStateChanged( Engine::State state, Engine::State oldState )
{
if( !AmarokConfig::autoShowContextBrowser() || m_currentIndex == -1 )
return;
switch( state ) {
case Engine::Playing:
if( oldState != Engine::Paused && m_currentIndex != -1 ) {
m_lastIndex = m_currentIndex;
showBrowser( "ContextBrowser" );
}
break;
case Engine::Empty:
if( m_lastIndex >= 0 )
showBrowser( m_lastIndex );
default:
;
}
}
#include "browserbar.moc"