Logo Search packages:      
Sourcecode: webissues version File versions  Download package

builder.cpp

/**************************************************************************
* Simple XML-based UI builder for Qt 4
* Copyright (C) 2007 Michał Męciński
*
* 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 "builder.h"

#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QToolBar>

#include "node.h"
#include "client.h"


using namespace XmlUi;

00024 Builder::Builder( QMainWindow* window ) : QObject( window ),
    m_mainWindow( window )
{
}

00029 Builder::~Builder()
{
}

00033 void Builder::addClient( Client* client )
{
    if ( !m_clients.contains( client ) ) {
        m_clients.append( client );

        client->setBuilder( this );

        rebuildAll();
    }
}

00044 void Builder::removeClient( Client* client )
{
    if ( m_clients.contains( client ) ) {
        m_clients.removeAt( m_clients.indexOf( client ) );

        client->setBuilder( NULL );

        rebuildAll();
    }
}

Node Builder::mergeNodes( const Node& node1, const Node& node2 )
{
    Node result;

    result.setType( node1.type() );
    result.setId( node1.id() );

    QList<Node> children;

    int mergePos = -1;

    // copy nodes from node1 and find the position of the empty <merge/> element
    for ( int i = 0; i < node1.children().count(); i++ ) {
        Node child = node1.children().at( i );

        if ( child.type() == Merge && child.id().isEmpty() )
            mergePos = children.count();
        else
            children.append( child );
    }

    // no <merge/> element, append node2 to the end
    if ( mergePos < 0 )
        mergePos = children.count();

    // process nodes from node2
    for ( int i = 0; i < node2.children().count(); i++ ) {
        Node child = node2.children().at( i );

        bool merged = false;

        // find a matching node from node1
        for ( int j = 0; j < children.count(); j++ ) {
            if ( canMergeNodes( children.at( j ), child ) ) {
                // replace the original node with the recursively merged node
                children.replace( j, mergeNodes( children.at( j ), child ) );
                merged = true;
                break;
            }
        }

        // no matching node to merge with, insert into merge location
        if ( !merged )
            children.insert( mergePos++, child );
    }

    result.setChildren( children );

    return result;
}

bool Builder::canMergeNodes( const Node& node1, const Node& node2 )
{
    // separators are never merged
    if ( node1.type() == Separator && node2.type() == Separator )
        return false;

    // the menu bar is always merged
    if ( node1.type() == MenuBar && node2.type() == MenuBar )
        return true;

    // merge if both type and id is the same
    return node1.type() == node2.type() && node1.id() == node2.id();
}

Node Builder::resolveGroups( const Node& node )
{
    Node result;

    result.setType( node.type() );
    result.setId( node.id() );

    for ( int i = 0; i < node.children().count(); i++ ) {
        Node child = node.children().at( i );

        // do not copy groups
        if ( child.type() == Group )
            continue;

        if ( child.type() == Merge ) {
            // look for the matching group
            for ( int j = 0; j < node.children().count(); j++ ) {
                Node group = node.children().at( j );
                if ( group.type() == Group && group.id() == child.id() ) {
                    // process the group recursively and insert all its children
                    group = resolveGroups( group );
                    for ( int k = 0; k < group.children().count(); k++ )
                        result.addChild( group.children().at( k ) );
                    break;
                }
            }
            continue;
        }

        // process the element's groups recursively
        if ( child.children().count() > 0 )
            child = resolveGroups( child );

        result.addChild( child );
    }

    return result;
}

00159 void Builder::rebuildAll()
{
    if ( m_clients.isEmpty() )
        return;

    m_mainWindow->setUpdatesEnabled( false );

    Node node = m_clients.at( 0 )->rootNode();

    for ( int i = 1; i < m_clients.count(); i++ )
        node = mergeNodes( node, m_clients.at( i )->rootNode() );

    m_rootNode = resolveGroups( node );

    m_mainWindow->menuBar()->clear();

    m_oldToolBars = m_toolBars;
    m_toolBars.clear();

    QList<QMenu*> menus = m_contextMenus.values();
    for ( int i = 0; i < menus.count(); i++ )
        delete menus.at( i );
    m_contextMenus.clear();

    for ( int i = 0; i < m_rootNode.children().count(); i++ ) {
        Node child = m_rootNode.children().at( i );
        if ( child.type() == MenuBar ) {
            populateMenuBar( child );
        } else if ( child.type() == ToolBar ) {
            createToolBar( child );
        }
    }

    for ( int i = 0; i < m_oldToolBars.count(); i++ )
        delete m_oldToolBars.at( i );
    m_oldToolBars.clear();

    m_mainWindow->setUpdatesEnabled( true );

    emit reset();
}

void Builder::populateMenuBar( const Node& node )
{
    for ( int i = 0; i < node.children().count(); i++ ) {
        Node child = node.children().at( i );
        if ( child.type() == Menu ) {
            QMenu* menu = createMenu( child );
            if ( menu )
                m_mainWindow->menuBar()->addMenu( menu );
        }
    }
}

QToolBar* Builder::createToolBar( const Node& node )
{
    QToolBar* toolBar = NULL;
    bool isNew = false;
    bool separator = false;

    for ( int i = 0; i < node.children().count(); i++ ) {
        Node child = node.children().at( i );

        if ( child.type() == Separator && toolBar != NULL ) {
            separator = true;
            continue;
        }

        QAction* action = NULL;

        if ( child.type() == Action )
            action = findAction( child.id() );

        if ( !action )
            continue;

        if ( !toolBar ) {
            QString title = findTitle( node.id() );
            for ( int i = 0; i < m_oldToolBars.count(); i++ ) {
                if ( m_oldToolBars[ i ]->windowTitle() == title ) {
                    toolBar = m_oldToolBars[ i ];
                    m_oldToolBars.removeAt( i );
                    toolBar->setVisible( false );
                    toolBar->clear();
                    break;
                }
            }
            if ( !toolBar ) {
                toolBar = new QToolBar( title, m_mainWindow );
                isNew = true;
            }
            m_toolBars.append( toolBar );
        }

        if ( separator ) {
            toolBar->addSeparator();
            separator = false;
        }

        toolBar->addAction( action );
    }

    if ( isNew )
        m_mainWindow->addToolBar( toolBar );
    else if ( toolBar )
        toolBar->setVisible( true );

    return toolBar;
}

QMenu* Builder::createMenu( const Node& node )
{
    QMenu* menu = NULL;
    bool separator = false;

    for ( int i = 0; i < node.children().count(); i++ ) {
        Node child = node.children().at( i );

        if ( child.type() == Separator && menu != NULL ) {
            separator = true;
            continue;
        }

        QAction* action = NULL;

        if ( child.type() == Action )
            action = findAction( child.id() );

        if ( child.type() == Menu ) {
            QMenu* subMenu = createMenu( child );
            if ( subMenu )
                action = subMenu->menuAction();
        }

        if ( !action )
            continue;

        if ( !menu ) {
            QString title = findTitle( node.id() );
            menu = new QMenu( title, m_mainWindow );
        }

        if ( separator ) {
            menu->addSeparator();
            separator = false;
        }

        menu->addAction( action );
    }

    return menu;
}

00312 QMenu* Builder::contextMenu( const QString& id )
{
    QMenu* menu = m_contextMenus.value( id, NULL );
    if ( menu )
        return menu;

    for ( int i = 0; i < m_rootNode.children().count(); i++ ) {
        Node child = m_rootNode.children().at( i );
        if ( child.type() == Menu && child.id() == id ) {
            menu = createMenu( child );
            break;
        }
    }

    if ( menu )
        m_contextMenus.insert( id, menu );

    return menu;
}

QAction* Builder::findAction( const QString& id )
{
    for ( int i = m_clients.count() - 1; i >= 0; i-- ) {
        QAction* action = m_clients.at( i )->action( id );
        if ( action && action->isVisible() )
            return action;
    }

    return NULL;
}

QString Builder::findTitle( const QString& id )
{
    for ( int i = m_clients.count() - 1; i >= 0; i-- ) {
        QString title = m_clients.at( i )->title( id );
        if ( !title.isEmpty() )
            return title;
    }

    return id;
}

#include "builder.moc"

Generated by  Doxygen 1.6.0   Back to index