<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Pavel Strakhov
 *
 * 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 "ToolWindowManagerArea.h"
#include "ToolWindowManager.h"
#include <QApplication>
#include <QMouseEvent>
#include <QDebug>

ToolWindowManagerArea::ToolWindowManagerArea(ToolWindowManager *manager, QWidget *parent) :
  QTabWidget(parent)
, m_manager(manager)
{
  m_dragCanStart = false;
  m_tabDragCanStart = false;
  m_inTabMoved = false;
  setMovable(true);
  setTabsClosable(true);
  setDocumentMode(true);
  tabBar()->installEventFilter(this);
  m_manager->m_areas << this;

  QObject::connect(tabBar(), &QTabBar::tabMoved, this, &ToolWindowManagerArea::tabMoved);
}

ToolWindowManagerArea::~ToolWindowManagerArea() {
  m_manager->m_areas.removeOne(this);
}

void ToolWindowManagerArea::addToolWindow(QWidget *toolWindow) {
  addToolWindows(QList<QWidget*>() << toolWindow);
}

void ToolWindowManagerArea::addToolWindows(const QList<QWidget *> &toolWindows) {
  int index = 0;
  foreach(QWidget* toolWindow, toolWindows) {
    index = addTab(toolWindow, toolWindow->windowIcon(), toolWindow->windowTitle());
    if(m_manager->toolWindowProperties(toolWindow) & ToolWindowManager::HideCloseButton) {
      tabBar()->tabButton(index, QTabBar::RightSide)->resize(0, 0);
    }
  }
  setCurrentIndex(index);
  m_manager->m_lastUsedArea = this;
}

QList<QWidget *> ToolWindowManagerArea::toolWindows() {
  QList<QWidget *> result;
  for(int i = 0; i < count(); i++) {
    result << widget(i);
  }
  return result;
}

void ToolWindowManagerArea::updateToolWindow(QWidget* toolWindow) {
  int index = indexOf(toolWindow);
  if(index >= 0) {
    if(m_manager->toolWindowProperties(toolWindow) & ToolWindowManager::HideCloseButton) {
      tabBar()->tabButton(index, QTabBar::RightSide)->resize(0, 0);
    } else {
      tabBar()->tabButton(index, QTabBar::RightSide)->resize(16, 16);
    }
    tabBar()->setTabText(index, toolWindow->windowTitle());
  }
}

void ToolWindowManagerArea::mousePressEvent(QMouseEvent *) {
  if (qApp->mouseButtons() == Qt::LeftButton) {
    m_dragCanStart = true;
  }
}

void ToolWindowManagerArea::mouseReleaseEvent(QMouseEvent *) {
  m_dragCanStart = false;
  m_manager->updateDragPosition();
}

void ToolWindowManagerArea::mouseMoveEvent(QMouseEvent *) {
  check_mouse_move();
}

bool ToolWindowManagerArea::eventFilter(QObject *object, QEvent *event) {
  if (object == tabBar()) {
    if (event->type() == QEvent::MouseButtonPress &&
        qApp->mouseButtons() == Qt::LeftButton) {

      int tabIndex = tabBar()->tabAt(static_cast<QMouseEvent*>(event)->pos());

      // can start tab drag only if mouse is at some tab, not at empty tabbar space
      if (tabIndex >= 0) {
        m_tabDragCanStart = true;

        if (m_manager->toolWindowProperties(widget(tabIndex)) & ToolWindowManager::DisableDraggableTab) {
          setMovable(false);
        } else {
          setMovable(true);
        }
      } else {
        m_dragCanStart = true;
      }

    } else if (event->type() == QEvent::MouseButtonRelease) {
      m_tabDragCanStart = false;
      m_dragCanStart = false;
      m_manager->updateDragPosition();
    } else if (event->type() == QEvent::MouseMove) {
      m_manager->updateDragPosition();
      if (m_tabDragCanStart) {
        if (tabBar()->rect().contains(static_cast<QMouseEvent*>(event)->pos())) {
          return false;
        }
        if (qApp->mouseButtons() != Qt::LeftButton) {
          return false;
        }
        QWidget* toolWindow = currentWidget();
        if (!toolWindow || !m_manager->m_toolWindows.contains(toolWindow)) {
          return false;
        }
        m_tabDragCanStart = false;
        //stop internal tab drag in QTabBar
        QMouseEvent* releaseEvent = new QMouseEvent(QEvent::MouseButtonRelease,
                                                    static_cast<QMouseEvent*>(event)->pos(),
                                                    Qt::LeftButton, Qt::LeftButton, 0);
        qApp->sendEvent(tabBar(), releaseEvent);
        m_manager->startDrag(QList<QWidget*>() << toolWindow);
      } else if (m_dragCanStart) {
        check_mouse_move();
      }
    }
  }
  return QTabWidget::eventFilter(object, event);
}

QVariantMap ToolWindowManagerArea::saveState() {
  QVariantMap result;
  result["type"] = "area";
  result["currentIndex"] = currentIndex();
  QStringList objectNames;
  for(int i = 0; i < count(); i++) {
    QString name = widget(i)->objectName();
    if (name.isEmpty()) {
      qWarning("cannot save state of tool window without object name");
    } else {
      objectNames << name;
    }
  }
  result["objectNames"] = objectNames;
  return result;
}

void ToolWindowManagerArea::restoreState(const QVariantMap &data) {
  foreach(QVariant objectNameValue, data["objectNames"].toList()) {
    QString objectName = objectNameValue.toString();
    if (objectName.isEmpty()) { continue; }
    bool found = false;
    foreach(QWidget* toolWindow, m_manager->m_toolWindows) {
      if (toolWindow->objectName() == objectName) {
        addToolWindow(toolWindow);
        found = true;
        break;
      }
    }
    if (!found) {
      qWarning("tool window with name '%s' not found", objectName.toLocal8Bit().constData());
    }
  }
  setCurrentIndex(data["currentIndex"].toInt());
}

void ToolWindowManagerArea::check_mouse_move() {
  m_manager->updateDragPosition();
  if (qApp->mouseButtons() == Qt::LeftButton &&
      !rect().contains(mapFromGlobal(QCursor::pos())) &&
      m_dragCanStart) {
    m_dragCanStart = false;
    QList<QWidget*> toolWindows;
    for(int i = 0; i < count(); i++) {
      QWidget* toolWindow = widget(i);
      if (!m_manager->m_toolWindows.contains(toolWindow)) {
        qWarning("tab widget contains unmanaged widget");
      } else {
        toolWindows << toolWindow;
      }
    }
    m_manager->startDrag(toolWindows);
  }
}

void ToolWindowManagerArea::tabMoved(int from, int to) {
  if(m_inTabMoved) return;

  QWidget *a = widget(from);
  QWidget *b = widget(to);

  if(!a || !b) return;

  if(m_manager->toolWindowProperties(a) & ToolWindowManager::DisableDraggableTab ||
     m_manager->toolWindowProperties(b) & ToolWindowManager::DisableDraggableTab)
  {
    m_inTabMoved = true;
    tabBar()->moveTab(to, from);
    m_inTabMoved = false;
  }
}
<commit_msg>Serialise area objects as [name, data] pairs, with custom persist data<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Pavel Strakhov
 *
 * 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 "ToolWindowManagerArea.h"
#include "ToolWindowManager.h"
#include <QApplication>
#include <QMouseEvent>
#include <QDebug>

ToolWindowManagerArea::ToolWindowManagerArea(ToolWindowManager *manager, QWidget *parent) :
  QTabWidget(parent)
, m_manager(manager)
{
  m_dragCanStart = false;
  m_tabDragCanStart = false;
  m_inTabMoved = false;
  setMovable(true);
  setTabsClosable(true);
  setDocumentMode(true);
  tabBar()->installEventFilter(this);
  m_manager->m_areas << this;

  QObject::connect(tabBar(), &QTabBar::tabMoved, this, &ToolWindowManagerArea::tabMoved);
}

ToolWindowManagerArea::~ToolWindowManagerArea() {
  m_manager->m_areas.removeOne(this);
}

void ToolWindowManagerArea::addToolWindow(QWidget *toolWindow) {
  addToolWindows(QList<QWidget*>() << toolWindow);
}

void ToolWindowManagerArea::addToolWindows(const QList<QWidget *> &toolWindows) {
  int index = 0;
  foreach(QWidget* toolWindow, toolWindows) {
    index = addTab(toolWindow, toolWindow->windowIcon(), toolWindow->windowTitle());
    if(m_manager->toolWindowProperties(toolWindow) & ToolWindowManager::HideCloseButton) {
      tabBar()->tabButton(index, QTabBar::RightSide)->resize(0, 0);
    }
  }
  setCurrentIndex(index);
  m_manager->m_lastUsedArea = this;
}

QList<QWidget *> ToolWindowManagerArea::toolWindows() {
  QList<QWidget *> result;
  for(int i = 0; i < count(); i++) {
    result << widget(i);
  }
  return result;
}

void ToolWindowManagerArea::updateToolWindow(QWidget* toolWindow) {
  int index = indexOf(toolWindow);
  if(index >= 0) {
    if(m_manager->toolWindowProperties(toolWindow) & ToolWindowManager::HideCloseButton) {
      tabBar()->tabButton(index, QTabBar::RightSide)->resize(0, 0);
    } else {
      tabBar()->tabButton(index, QTabBar::RightSide)->resize(16, 16);
    }
    tabBar()->setTabText(index, toolWindow->windowTitle());
  }
}

void ToolWindowManagerArea::mousePressEvent(QMouseEvent *) {
  if (qApp->mouseButtons() == Qt::LeftButton) {
    m_dragCanStart = true;
  }
}

void ToolWindowManagerArea::mouseReleaseEvent(QMouseEvent *) {
  m_dragCanStart = false;
  m_manager->updateDragPosition();
}

void ToolWindowManagerArea::mouseMoveEvent(QMouseEvent *) {
  check_mouse_move();
}

bool ToolWindowManagerArea::eventFilter(QObject *object, QEvent *event) {
  if (object == tabBar()) {
    if (event->type() == QEvent::MouseButtonPress &&
        qApp->mouseButtons() == Qt::LeftButton) {

      int tabIndex = tabBar()->tabAt(static_cast<QMouseEvent*>(event)->pos());

      // can start tab drag only if mouse is at some tab, not at empty tabbar space
      if (tabIndex >= 0) {
        m_tabDragCanStart = true;

        if (m_manager->toolWindowProperties(widget(tabIndex)) & ToolWindowManager::DisableDraggableTab) {
          setMovable(false);
        } else {
          setMovable(true);
        }
      } else {
        m_dragCanStart = true;
      }

    } else if (event->type() == QEvent::MouseButtonRelease) {
      m_tabDragCanStart = false;
      m_dragCanStart = false;
      m_manager->updateDragPosition();
    } else if (event->type() == QEvent::MouseMove) {
      m_manager->updateDragPosition();
      if (m_tabDragCanStart) {
        if (tabBar()->rect().contains(static_cast<QMouseEvent*>(event)->pos())) {
          return false;
        }
        if (qApp->mouseButtons() != Qt::LeftButton) {
          return false;
        }
        QWidget* toolWindow = currentWidget();
        if (!toolWindow || !m_manager->m_toolWindows.contains(toolWindow)) {
          return false;
        }
        m_tabDragCanStart = false;
        //stop internal tab drag in QTabBar
        QMouseEvent* releaseEvent = new QMouseEvent(QEvent::MouseButtonRelease,
                                                    static_cast<QMouseEvent*>(event)->pos(),
                                                    Qt::LeftButton, Qt::LeftButton, 0);
        qApp->sendEvent(tabBar(), releaseEvent);
        m_manager->startDrag(QList<QWidget*>() << toolWindow);
      } else if (m_dragCanStart) {
        check_mouse_move();
      }
    }
  }
  return QTabWidget::eventFilter(object, event);
}

QVariantMap ToolWindowManagerArea::saveState() {
  QVariantMap result;
  result["type"] = "area";
  result["currentIndex"] = currentIndex();
  QVariantList objects;
  objects.reserve(count());
  for(int i = 0; i < count(); i++) {
    QWidget *w = widget(i);
    QString name = w->objectName();
    if (name.isEmpty()) {
      qWarning("cannot save state of tool window without object name");
    } else {
      QVariantMap objectData;
      objectData["name"] = name;
      objectData["data"] = w->property("persistData");
      objects.push_back(objectData);
    }
  }
  result["objects"] = objects;
  return result;
}

void ToolWindowManagerArea::restoreState(const QVariantMap &data) {
  foreach(QVariant object, data["objects"].toList()) {
    QVariantMap objectData = object.toMap();
    if (objectData.isEmpty()) { continue; }
    QString objectName = objectData["name"].toString();
    if (objectName.isEmpty()) { continue; }
    QWidget *t = NULL;
    foreach(QWidget* toolWindow, m_manager->m_toolWindows) {
      if (toolWindow->objectName() == objectName) {
        t = toolWindow;
        break;
      }
    }
    if (t) {
        t->setProperty("persistData", objectData["data"]);
        addToolWindow(t);
    } else {
      qWarning("tool window with name '%s' not found or created", objectName.toLocal8Bit().constData());
    }
  }
  setCurrentIndex(data["currentIndex"].toInt());
}

void ToolWindowManagerArea::check_mouse_move() {
  m_manager->updateDragPosition();
  if (qApp->mouseButtons() == Qt::LeftButton &&
      !rect().contains(mapFromGlobal(QCursor::pos())) &&
      m_dragCanStart) {
    m_dragCanStart = false;
    QList<QWidget*> toolWindows;
    for(int i = 0; i < count(); i++) {
      QWidget* toolWindow = widget(i);
      if (!m_manager->m_toolWindows.contains(toolWindow)) {
        qWarning("tab widget contains unmanaged widget");
      } else {
        toolWindows << toolWindow;
      }
    }
    m_manager->startDrag(toolWindows);
  }
}

void ToolWindowManagerArea::tabMoved(int from, int to) {
  if(m_inTabMoved) return;

  QWidget *a = widget(from);
  QWidget *b = widget(to);

  if(!a || !b) return;

  if(m_manager->toolWindowProperties(a) & ToolWindowManager::DisableDraggableTab ||
     m_manager->toolWindowProperties(b) & ToolWindowManager::DisableDraggableTab)
  {
    m_inTabMoved = true;
    tabBar()->moveTab(to, from);
    m_inTabMoved = false;
  }
}
<|endoftext|>


<commit_before>//
//  kern_nvhda.cpp
//  WhateverGreen
//
//  Copyright © 2018 vit9696. All rights reserved.
//

#include "kern_nvhda.hpp"

#include <Headers/kern_util.hpp>
#include <libkern/libkern.h>
#include <IOKit/pci/IOPCIDevice.h>
#include <IOKit/IODeviceTreeSupport.h>

// Workaround for systems with BIOSes that default-disable the HD Audio function on their NVIDIA GPUs.
// We match the device with a higher IOProbeScore than the NVIDIA drivers, use our probe routine to
// enable the HD Audio function, trigger a PCI rescan, and then return a probe failure so that the
// real driver can continue to load.
//
// References:
// https://bugs.freedesktop.org/show_bug.cgi?id=75985
// https://devtalk.nvidia.com/default/topic/1024022/linux/gtx-1060-no-audio-over-hdmi-only-hda-intel-detected-azalia/
// https://github.com/acidanthera/bugtracker/issues/292

OSDefineMetaClassAndStructors(NVHDAEnabler, IOService);

IOService* NVHDAEnabler::probe(IOService *provider, SInt32 *score) {
	auto pciDevice = OSDynamicCast(IOPCIDevice, provider);
	if (!pciDevice) {
		SYSLOG("NVHDAEnabler", "probe: pciDevice is NULL");
		return nullptr;
	}

	uint32_t hdaEnableDword = pciDevice->configRead32(HDAEnableReg);
	if (hdaEnableDword & HDAEnableBit) {
		DBGLOG("NVHDAEnabler", "probe: HDA enable bit is already set, nothing to do");
		return nullptr;
	}

	DBGLOG("NVHDAEnabler", "probe: reg is 0x%x, setting HDA enable bit", hdaEnableDword);
	hdaEnableDword |= HDAEnableBit;
	pciDevice->configWrite32(HDAEnableReg, hdaEnableDword);

	// Verify with readback
	DBGLOG("NVHDAEnabler", "probe: readback: reg is 0x%x", pciDevice->configRead32(HDAEnableReg));

	// Find the parent IOPCIBridge
	auto parentBridge = OSDynamicCast(IOPCIDevice, pciDevice->getParentEntry(gIODTPlane));
	if (!parentBridge) {
		DBGLOG("NVHDAEnabler", "probe: Can't find the parent bridge's IOPCIDevice");
		return nullptr;
	}

	DBGLOG("NVHDAEnabler", "probe: Requesting parent bridge rescan");

	// Mark this device and the parent bridge as needing scanning, then trigger the rescan.
	pciDevice->kernelRequestProbe(kIOPCIProbeOptionNeedsScan);
	parentBridge->kernelRequestProbe(kIOPCIProbeOptionNeedsScan | kIOPCIProbeOptionDone);

	// This probe must always fail so that the real driver can get a chance to load afterwards.
	return nullptr;
}

bool NVHDAEnabler::start(IOService *provider) {
	SYSLOG("NVHDAEnabler", "start: shouldn't be called!");
	return false;
}
<commit_msg>Fix compiler warning with latest 10.15 SDK<commit_after>//
//  kern_nvhda.cpp
//  WhateverGreen
//
//  Copyright © 2018 vit9696. All rights reserved.
//

#include "kern_nvhda.hpp"

#include <Headers/kern_util.hpp>
#include <libkern/libkern.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
#include <IOKit/pci/IOPCIDevice.h>
#pragma clang diagnostic pop
#include <IOKit/IODeviceTreeSupport.h>

// Workaround for systems with BIOSes that default-disable the HD Audio function on their NVIDIA GPUs.
// We match the device with a higher IOProbeScore than the NVIDIA drivers, use our probe routine to
// enable the HD Audio function, trigger a PCI rescan, and then return a probe failure so that the
// real driver can continue to load.
//
// References:
// https://bugs.freedesktop.org/show_bug.cgi?id=75985
// https://devtalk.nvidia.com/default/topic/1024022/linux/gtx-1060-no-audio-over-hdmi-only-hda-intel-detected-azalia/
// https://github.com/acidanthera/bugtracker/issues/292

OSDefineMetaClassAndStructors(NVHDAEnabler, IOService);

IOService* NVHDAEnabler::probe(IOService *provider, SInt32 *score) {
	auto pciDevice = OSDynamicCast(IOPCIDevice, provider);
	if (!pciDevice) {
		SYSLOG("NVHDAEnabler", "probe: pciDevice is NULL");
		return nullptr;
	}

	uint32_t hdaEnableDword = pciDevice->configRead32(HDAEnableReg);
	if (hdaEnableDword & HDAEnableBit) {
		DBGLOG("NVHDAEnabler", "probe: HDA enable bit is already set, nothing to do");
		return nullptr;
	}

	DBGLOG("NVHDAEnabler", "probe: reg is 0x%x, setting HDA enable bit", hdaEnableDword);
	hdaEnableDword |= HDAEnableBit;
	pciDevice->configWrite32(HDAEnableReg, hdaEnableDword);

	// Verify with readback
	DBGLOG("NVHDAEnabler", "probe: readback: reg is 0x%x", pciDevice->configRead32(HDAEnableReg));

	// Find the parent IOPCIBridge
	auto parentBridge = OSDynamicCast(IOPCIDevice, pciDevice->getParentEntry(gIODTPlane));
	if (!parentBridge) {
		DBGLOG("NVHDAEnabler", "probe: Can't find the parent bridge's IOPCIDevice");
		return nullptr;
	}

	DBGLOG("NVHDAEnabler", "probe: Requesting parent bridge rescan");

	// Mark this device and the parent bridge as needing scanning, then trigger the rescan.
	pciDevice->kernelRequestProbe(kIOPCIProbeOptionNeedsScan);
	parentBridge->kernelRequestProbe(kIOPCIProbeOptionNeedsScan | kIOPCIProbeOptionDone);

	// This probe must always fail so that the real driver can get a chance to load afterwards.
	return nullptr;
}

bool NVHDAEnabler::start(IOService *provider) {
	SYSLOG("NVHDAEnabler", "start: shouldn't be called!");
	return false;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: MasterPageObserver.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: hr $ $Date: 2007-07-31 17:25:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "MasterPageObserver.hxx"

#include <algorithm>
#include "drawdoc.hxx"
#include "sdpage.hxx"
#include <hash_map>
#include <set>
#include <vector>
#include <svtools/lstner.hxx>
#ifndef INCLUDED_OSL_DOUBLECHECKEDLOCKING_H
#include <osl/doublecheckedlocking.h>
#endif
#ifndef INCLUDED_OSL_GETGLOBALMUTEX_HXX
#include <osl/getglobalmutex.hxx>
#endif

namespace sd {

class MasterPageObserver::Implementation
    : public SfxListener
{
public:
    /** The single instance of this class.  It is created on demand when
        Instance() is called for the first time.
    */
    static MasterPageObserver* mpInstance;

    /** The master page observer will listen to events of this document and
        detect changes of the use of master pages.
    */
    void RegisterDocument (SdDrawDocument& rDocument);

    /** The master page observer will stop to listen to events of this
        document.
    */
    void UnregisterDocument (SdDrawDocument& rDocument);

    /** Add a listener that is informed of master pages that are newly
        assigned to slides or become unassigned.
        @param rEventListener
            The event listener to call for future events.  Call
            RemoveEventListener() before the listener is destroyed.
    */
    void AddEventListener (const Link& rEventListener);

    /** Remove the given listener from the list of listeners.
        @param rEventListener
            After this method returns the given listener is not called back
            from this object.  Passing a listener that has not
            been registered before is safe and is silently ignored.
    */
    void RemoveEventListener (const Link& rEventListener);

    /** Return a set of the names of master pages for the given document.
        This convenience method exists because this set is part of the
        internal data structure and thus takes no time to create.
    */
    inline MasterPageObserver::MasterPageNameSet GetMasterPageNames (
        SdDrawDocument& rDocument);

private:
    ::std::vector<Link> maListeners;

    struct DrawDocHash {
        size_t operator()(SdDrawDocument* argument) const
        { return reinterpret_cast<unsigned long>(argument); }
    };
    typedef ::std::hash_map<SdDrawDocument*,
                            MasterPageObserver::MasterPageNameSet,
                            DrawDocHash>
        MasterPageContainer;
    MasterPageContainer maUsedMasterPages;

    virtual void Notify(
        SfxBroadcaster& rBroadcaster,
        const SfxHint& rHint);

    void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);

    void SendEvent (MasterPageObserverEvent& rEvent);
};

MasterPageObserver* MasterPageObserver::Implementation::mpInstance = NULL;

//===== MasterPageObserver ====================================================

MasterPageObserver&  MasterPageObserver::Instance (void)
{
    if (Implementation::mpInstance == NULL)
    {
        ::osl::GetGlobalMutex aMutexFunctor;
        ::osl::MutexGuard aGuard (aMutexFunctor());
        if (Implementation::mpInstance == NULL)
        {
            MasterPageObserver* pInstance = new MasterPageObserver ();
            SdGlobalResourceContainer::Instance().AddResource (
                ::std::auto_ptr<SdGlobalResource>(pInstance));
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            Implementation::mpInstance = pInstance;
        }
    }
    else
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();

    DBG_ASSERT(Implementation::mpInstance!=NULL,
        "MasterPageObserver::Instance(): instance is NULL");
    return *Implementation::mpInstance;
}

void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
{
    mpImpl->RegisterDocument (rDocument);
}

void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
{
    mpImpl->UnregisterDocument (rDocument);
}

void MasterPageObserver::AddEventListener (const Link& rEventListener)
{

    mpImpl->AddEventListener (rEventListener);
}

void MasterPageObserver::RemoveEventListener (const Link& rEventListener)
{
    mpImpl->RemoveEventListener (rEventListener);
}

MasterPageObserver::MasterPageObserver (void)
    : mpImpl (new Implementation())
{}

MasterPageObserver::~MasterPageObserver (void)
{}

MasterPageObserver::MasterPageNameSet MasterPageObserver::GetMasterPageNames (
    SdDrawDocument& rDocument)
{
    return mpImpl->GetMasterPageNames (rDocument);
}

//===== MasterPageObserver::Implementation ====================================

void MasterPageObserver::Implementation::RegisterDocument (
    SdDrawDocument& rDocument)
{
    // Gather the names of all the master pages in the given document.
    MasterPageContainer::data_type aMasterPageSet;
    USHORT nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
    for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++)
    {
        SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
        if (pMasterPage != NULL)
            aMasterPageSet.insert (pMasterPage->GetName());
    }

    maUsedMasterPages[&rDocument] = aMasterPageSet;

    StartListening (rDocument);
}

void MasterPageObserver::Implementation::UnregisterDocument (
    SdDrawDocument& rDocument)
{
    EndListening (rDocument);

    MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
    if(aMasterPageDescriptor != maUsedMasterPages.end())
        maUsedMasterPages.erase(aMasterPageDescriptor);
}

void MasterPageObserver::Implementation::AddEventListener (
    const Link& rEventListener)
{
    if (::std::find (
        maListeners.begin(),
        maListeners.end(),
        rEventListener) == maListeners.end())
    {
        maListeners.push_back (rEventListener);

        // Tell the new listener about all the master pages that are
        // currently in use.
        typedef ::std::vector<String> StringList;
        StringList aNewMasterPages;
        StringList aRemovedMasterPages;
        MasterPageContainer::iterator aDocumentIterator;
        for (aDocumentIterator=maUsedMasterPages.begin();
             aDocumentIterator!=maUsedMasterPages.end();
             ++aDocumentIterator)
        {
            ::std::set<String>::reverse_iterator aNameIterator;
            for (aNameIterator=aDocumentIterator->second.rbegin();
                 aNameIterator!=aDocumentIterator->second.rend();
                 ++aNameIterator)
            {
              MasterPageObserverEvent aEvent (
                  MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
                  *aDocumentIterator->first,
                  *aNameIterator);
              SendEvent (aEvent);
            }
        }
    }
}

void MasterPageObserver::Implementation::RemoveEventListener (
    const Link& rEventListener)
{
    maListeners.erase (
        ::std::find (
            maListeners.begin(),
            maListeners.end(),
            rEventListener));
}

MasterPageObserver::MasterPageNameSet
    MasterPageObserver::Implementation::GetMasterPageNames (
        SdDrawDocument& rDocument)
{
    MasterPageContainer::iterator aMasterPageDescriptor (
        maUsedMasterPages.find(&rDocument));
    if (aMasterPageDescriptor != maUsedMasterPages.end())
        return aMasterPageDescriptor->second;
    else
        // Not found so return an empty set.
        return MasterPageObserver::MasterPageNameSet();
}

void MasterPageObserver::Implementation::Notify(
    SfxBroadcaster& rBroadcaster,
    const SfxHint& rHint)
{
    if (rHint.ISA(SdrHint))
    {
        SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint));
        switch (rSdrHint.GetKind())
        {
            case HINT_PAGEORDERCHG:
                // Process the modified set of pages only when the number of
                // standard and notes master pages are equal.  This test
                // filters out events that are sent in between the insertion
                // of a new standard master page and a new notes master
                // page.
                if (rBroadcaster.ISA(SdDrawDocument))
                {
                    SdDrawDocument& rDocument (
                        static_cast<SdDrawDocument&>(rBroadcaster));
                    if (rDocument.GetMasterSdPageCount(PK_STANDARD)
                        == rDocument.GetMasterSdPageCount(PK_NOTES))
                    {
                        AnalyzeUsedMasterPages (rDocument);
                    }
                }
                break;

            default:
                break;
        }
    }
}

void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
    SdDrawDocument& rDocument)
{
    // Create a set of names of the master pages used by the given document.
    USHORT nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
    ::std::set<String> aCurrentMasterPages;
    for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++)
    {
        SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
        if (pMasterPage != NULL)
            aCurrentMasterPages.insert (pMasterPage->GetName());
        OSL_TRACE("currently used master page %d is %s",
            nIndex,
            ::rtl::OUStringToOString(pMasterPage->GetName(),
                RTL_TEXTENCODING_UTF8).getStr());
    }

    typedef ::std::vector<String> StringList;
    StringList aNewMasterPages;
    StringList aRemovedMasterPages;
    MasterPageContainer::iterator aOldMasterPagesDescriptor (
        maUsedMasterPages.find(&rDocument));
    if (aOldMasterPagesDescriptor != maUsedMasterPages.end())
    {
        StringList::iterator I;

        ::std::set<String>::iterator J;
        int i=0;
        for (J=aOldMasterPagesDescriptor->second.begin();
             J!=aOldMasterPagesDescriptor->second.end();
             ++J)
            OSL_TRACE("old used master page %d is %s",
            i++,
            ::rtl::OUStringToOString(*J,
                RTL_TEXTENCODING_UTF8).getStr());

        // Send events about the newly used master pages.
        ::std::set_difference (
            aCurrentMasterPages.begin(),
            aCurrentMasterPages.end(),
            aOldMasterPagesDescriptor->second.begin(),
            aOldMasterPagesDescriptor->second.end(),
            ::std::back_insert_iterator<StringList>(aNewMasterPages));
        for (I=aNewMasterPages.begin(); I!=aNewMasterPages.end(); ++I)
        {
            OSL_TRACE("    added master page %s",
                ::rtl::OUStringToOString(*I,
                    RTL_TEXTENCODING_UTF8).getStr());

            MasterPageObserverEvent aEvent (
                MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
                rDocument,
                *I);
            SendEvent (aEvent);
        }

        // Send events about master pages that are not used any longer.
        ::std::set_difference (
            aOldMasterPagesDescriptor->second.begin(),
            aOldMasterPagesDescriptor->second.end(),
            aCurrentMasterPages.begin(),
            aCurrentMasterPages.end(),
            ::std::back_insert_iterator<StringList>(aRemovedMasterPages));
        for (I=aRemovedMasterPages.begin(); I!=aRemovedMasterPages.end(); ++I)
        {
            OSL_TRACE("    removed master page %s",
                ::rtl::OUStringToOString(*I,
                    RTL_TEXTENCODING_UTF8).getStr());

            MasterPageObserverEvent aEvent (
                MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
                rDocument,
                *I);
            SendEvent (aEvent);
        }

        // Store the new list of master pages.
        aOldMasterPagesDescriptor->second = aCurrentMasterPages;
    }
}

void MasterPageObserver::Implementation::SendEvent (
    MasterPageObserverEvent& rEvent)
{
    ::std::vector<Link>::iterator aLink (maListeners.begin());
    ::std::vector<Link>::iterator aEnd (maListeners.end());
    while (aLink!=aEnd)
    {
        aLink->Call (&rEvent);
        ++aLink;
    }
}

} // end of namespace sd
<commit_msg>INTEGRATION: CWS changefileheader (1.7.166); FILE MERGED 2008/04/01 15:36:09 thb 1.7.166.2: #i85898# Stripping all external header guards 2008/03/31 13:59:02 rt 1.7.166.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: MasterPageObserver.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "MasterPageObserver.hxx"

#include <algorithm>
#include "drawdoc.hxx"
#include "sdpage.hxx"
#include <hash_map>
#include <set>
#include <vector>
#include <svtools/lstner.hxx>
#include <osl/doublecheckedlocking.h>
#include <osl/getglobalmutex.hxx>

namespace sd {

class MasterPageObserver::Implementation
    : public SfxListener
{
public:
    /** The single instance of this class.  It is created on demand when
        Instance() is called for the first time.
    */
    static MasterPageObserver* mpInstance;

    /** The master page observer will listen to events of this document and
        detect changes of the use of master pages.
    */
    void RegisterDocument (SdDrawDocument& rDocument);

    /** The master page observer will stop to listen to events of this
        document.
    */
    void UnregisterDocument (SdDrawDocument& rDocument);

    /** Add a listener that is informed of master pages that are newly
        assigned to slides or become unassigned.
        @param rEventListener
            The event listener to call for future events.  Call
            RemoveEventListener() before the listener is destroyed.
    */
    void AddEventListener (const Link& rEventListener);

    /** Remove the given listener from the list of listeners.
        @param rEventListener
            After this method returns the given listener is not called back
            from this object.  Passing a listener that has not
            been registered before is safe and is silently ignored.
    */
    void RemoveEventListener (const Link& rEventListener);

    /** Return a set of the names of master pages for the given document.
        This convenience method exists because this set is part of the
        internal data structure and thus takes no time to create.
    */
    inline MasterPageObserver::MasterPageNameSet GetMasterPageNames (
        SdDrawDocument& rDocument);

private:
    ::std::vector<Link> maListeners;

    struct DrawDocHash {
        size_t operator()(SdDrawDocument* argument) const
        { return reinterpret_cast<unsigned long>(argument); }
    };
    typedef ::std::hash_map<SdDrawDocument*,
                            MasterPageObserver::MasterPageNameSet,
                            DrawDocHash>
        MasterPageContainer;
    MasterPageContainer maUsedMasterPages;

    virtual void Notify(
        SfxBroadcaster& rBroadcaster,
        const SfxHint& rHint);

    void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);

    void SendEvent (MasterPageObserverEvent& rEvent);
};

MasterPageObserver* MasterPageObserver::Implementation::mpInstance = NULL;

//===== MasterPageObserver ====================================================

MasterPageObserver&  MasterPageObserver::Instance (void)
{
    if (Implementation::mpInstance == NULL)
    {
        ::osl::GetGlobalMutex aMutexFunctor;
        ::osl::MutexGuard aGuard (aMutexFunctor());
        if (Implementation::mpInstance == NULL)
        {
            MasterPageObserver* pInstance = new MasterPageObserver ();
            SdGlobalResourceContainer::Instance().AddResource (
                ::std::auto_ptr<SdGlobalResource>(pInstance));
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            Implementation::mpInstance = pInstance;
        }
    }
    else
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();

    DBG_ASSERT(Implementation::mpInstance!=NULL,
        "MasterPageObserver::Instance(): instance is NULL");
    return *Implementation::mpInstance;
}

void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
{
    mpImpl->RegisterDocument (rDocument);
}

void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
{
    mpImpl->UnregisterDocument (rDocument);
}

void MasterPageObserver::AddEventListener (const Link& rEventListener)
{

    mpImpl->AddEventListener (rEventListener);
}

void MasterPageObserver::RemoveEventListener (const Link& rEventListener)
{
    mpImpl->RemoveEventListener (rEventListener);
}

MasterPageObserver::MasterPageObserver (void)
    : mpImpl (new Implementation())
{}

MasterPageObserver::~MasterPageObserver (void)
{}

MasterPageObserver::MasterPageNameSet MasterPageObserver::GetMasterPageNames (
    SdDrawDocument& rDocument)
{
    return mpImpl->GetMasterPageNames (rDocument);
}

//===== MasterPageObserver::Implementation ====================================

void MasterPageObserver::Implementation::RegisterDocument (
    SdDrawDocument& rDocument)
{
    // Gather the names of all the master pages in the given document.
    MasterPageContainer::data_type aMasterPageSet;
    USHORT nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
    for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++)
    {
        SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
        if (pMasterPage != NULL)
            aMasterPageSet.insert (pMasterPage->GetName());
    }

    maUsedMasterPages[&rDocument] = aMasterPageSet;

    StartListening (rDocument);
}

void MasterPageObserver::Implementation::UnregisterDocument (
    SdDrawDocument& rDocument)
{
    EndListening (rDocument);

    MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
    if(aMasterPageDescriptor != maUsedMasterPages.end())
        maUsedMasterPages.erase(aMasterPageDescriptor);
}

void MasterPageObserver::Implementation::AddEventListener (
    const Link& rEventListener)
{
    if (::std::find (
        maListeners.begin(),
        maListeners.end(),
        rEventListener) == maListeners.end())
    {
        maListeners.push_back (rEventListener);

        // Tell the new listener about all the master pages that are
        // currently in use.
        typedef ::std::vector<String> StringList;
        StringList aNewMasterPages;
        StringList aRemovedMasterPages;
        MasterPageContainer::iterator aDocumentIterator;
        for (aDocumentIterator=maUsedMasterPages.begin();
             aDocumentIterator!=maUsedMasterPages.end();
             ++aDocumentIterator)
        {
            ::std::set<String>::reverse_iterator aNameIterator;
            for (aNameIterator=aDocumentIterator->second.rbegin();
                 aNameIterator!=aDocumentIterator->second.rend();
                 ++aNameIterator)
            {
              MasterPageObserverEvent aEvent (
                  MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
                  *aDocumentIterator->first,
                  *aNameIterator);
              SendEvent (aEvent);
            }
        }
    }
}

void MasterPageObserver::Implementation::RemoveEventListener (
    const Link& rEventListener)
{
    maListeners.erase (
        ::std::find (
            maListeners.begin(),
            maListeners.end(),
            rEventListener));
}

MasterPageObserver::MasterPageNameSet
    MasterPageObserver::Implementation::GetMasterPageNames (
        SdDrawDocument& rDocument)
{
    MasterPageContainer::iterator aMasterPageDescriptor (
        maUsedMasterPages.find(&rDocument));
    if (aMasterPageDescriptor != maUsedMasterPages.end())
        return aMasterPageDescriptor->second;
    else
        // Not found so return an empty set.
        return MasterPageObserver::MasterPageNameSet();
}

void MasterPageObserver::Implementation::Notify(
    SfxBroadcaster& rBroadcaster,
    const SfxHint& rHint)
{
    if (rHint.ISA(SdrHint))
    {
        SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint));
        switch (rSdrHint.GetKind())
        {
            case HINT_PAGEORDERCHG:
                // Process the modified set of pages only when the number of
                // standard and notes master pages are equal.  This test
                // filters out events that are sent in between the insertion
                // of a new standard master page and a new notes master
                // page.
                if (rBroadcaster.ISA(SdDrawDocument))
                {
                    SdDrawDocument& rDocument (
                        static_cast<SdDrawDocument&>(rBroadcaster));
                    if (rDocument.GetMasterSdPageCount(PK_STANDARD)
                        == rDocument.GetMasterSdPageCount(PK_NOTES))
                    {
                        AnalyzeUsedMasterPages (rDocument);
                    }
                }
                break;

            default:
                break;
        }
    }
}

void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
    SdDrawDocument& rDocument)
{
    // Create a set of names of the master pages used by the given document.
    USHORT nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
    ::std::set<String> aCurrentMasterPages;
    for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++)
    {
        SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
        if (pMasterPage != NULL)
            aCurrentMasterPages.insert (pMasterPage->GetName());
        OSL_TRACE("currently used master page %d is %s",
            nIndex,
            ::rtl::OUStringToOString(pMasterPage->GetName(),
                RTL_TEXTENCODING_UTF8).getStr());
    }

    typedef ::std::vector<String> StringList;
    StringList aNewMasterPages;
    StringList aRemovedMasterPages;
    MasterPageContainer::iterator aOldMasterPagesDescriptor (
        maUsedMasterPages.find(&rDocument));
    if (aOldMasterPagesDescriptor != maUsedMasterPages.end())
    {
        StringList::iterator I;

        ::std::set<String>::iterator J;
        int i=0;
        for (J=aOldMasterPagesDescriptor->second.begin();
             J!=aOldMasterPagesDescriptor->second.end();
             ++J)
            OSL_TRACE("old used master page %d is %s",
            i++,
            ::rtl::OUStringToOString(*J,
                RTL_TEXTENCODING_UTF8).getStr());

        // Send events about the newly used master pages.
        ::std::set_difference (
            aCurrentMasterPages.begin(),
            aCurrentMasterPages.end(),
            aOldMasterPagesDescriptor->second.begin(),
            aOldMasterPagesDescriptor->second.end(),
            ::std::back_insert_iterator<StringList>(aNewMasterPages));
        for (I=aNewMasterPages.begin(); I!=aNewMasterPages.end(); ++I)
        {
            OSL_TRACE("    added master page %s",
                ::rtl::OUStringToOString(*I,
                    RTL_TEXTENCODING_UTF8).getStr());

            MasterPageObserverEvent aEvent (
                MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
                rDocument,
                *I);
            SendEvent (aEvent);
        }

        // Send events about master pages that are not used any longer.
        ::std::set_difference (
            aOldMasterPagesDescriptor->second.begin(),
            aOldMasterPagesDescriptor->second.end(),
            aCurrentMasterPages.begin(),
            aCurrentMasterPages.end(),
            ::std::back_insert_iterator<StringList>(aRemovedMasterPages));
        for (I=aRemovedMasterPages.begin(); I!=aRemovedMasterPages.end(); ++I)
        {
            OSL_TRACE("    removed master page %s",
                ::rtl::OUStringToOString(*I,
                    RTL_TEXTENCODING_UTF8).getStr());

            MasterPageObserverEvent aEvent (
                MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
                rDocument,
                *I);
            SendEvent (aEvent);
        }

        // Store the new list of master pages.
        aOldMasterPagesDescriptor->second = aCurrentMasterPages;
    }
}

void MasterPageObserver::Implementation::SendEvent (
    MasterPageObserverEvent& rEvent)
{
    ::std::vector<Link>::iterator aLink (maListeners.begin());
    ::std::vector<Link>::iterator aEnd (maListeners.end());
    while (aLink!=aEnd)
    {
        aLink->Call (&rEvent);
        ++aLink;
    }
}

} // end of namespace sd
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <iostream>
#include "core/driver.h"
#include "core/modmanager.h"
#include "core/value.h"
#include "core/cstring.h"
#include "core/scope.h"
#include "modules/std/std_pkg.h"
#include "modules/db/db_pkg.h"
#include "modules/gui/gui_pkg.h"
#include "core/user.h"

namespace clever {

/// Adds the available packages to be imported
void ModManager::init()
{
	addModule("std",   new modules::Std);
	addModule("db",    new modules::Db);
	addModule("gui",   new modules::Gui);
	addModule("_user", m_user = new UserModule);
}

/// Performs shutdown operation
void ModManager::shutdown()
{
	std::vector<Type*> typevec;
	ModuleMap::const_iterator itm(m_mods.begin()), endm(m_mods.end());

	while (itm != endm) {
		TypeMap& types = itm->second->getTypes();
		TypeMap::const_iterator itt(types.begin()), ite(types.end());

		while (itt != ite) {
			itt->second->deallocMembers();
			typevec.push_back(itt->second);
			++itt;
		}

		clever_delete(itm->second);
		++itm;
	}

	std::for_each(typevec.begin(), typevec.end(), clever_delete<Type>);
}

/// Adds a new module
void ModManager::addModule(const std::string& name, Module* module)
{
	if (m_mods.find(name) != m_mods.end()) {
		return;
	}

	m_mods.insert(ModuleMap::value_type(name, module));
	module->init();
	module->setLoaded();

	if (module->hasModules()) {
		ModuleMap& mods = module->getModules();
		ModuleMap::const_iterator it(mods.begin()), end(mods.end());

		while (it != end) {
			m_mods.insert(ModuleMap::value_type(it->first, it->second));
			++it;
		}
	}
}

/// Loads an specific module type
void ModManager::loadType(Scope* scope, const std::string& name, Type* type) const
{
	Value* tmp = new Value(type, true);

	scope->pushValue(CSTRING(name), tmp);

	type->init();
}

/// Loads an specific module function
void ModManager::loadFunction(Scope* scope, const std::string& name, Function* func) const
{
	Value* fval = new Value();

	fval->setObj(CLEVER_FUNC_TYPE, func);
	fval->setConst(true);

	scope->pushValue(CSTRING(name), fval);
}

void ModManager::loadModuleContent(Scope* scope, Module* module,
	size_t kind, const CString* name, const std::string& ns_prefix) const
{
	if (!name) {
		VarMap& vars = module->getVars();

		if (!vars.empty()) {
			VarMap::const_iterator it(vars.begin()), end(vars.end());

			for (; it != end; ++it) {
				const CString* vname = CSTRING(ns_prefix + it->first);
				scope->pushValue(vname, it->second);
			}
		}
	}

	if (kind & ModManager::FUNCTION) {
		FunctionMap& funcs = module->getFunctions();

		if (name) {
			FunctionMap::const_iterator it(funcs.find(*name));

			if (it == funcs.end()) {
				std::cerr << "Function `" << *name << "' not found!" << std::endl;
			} else {
				loadFunction(scope, it->first, it->second);
			}
		} else {
			FunctionMap::const_iterator itf(funcs.begin()),	endf(funcs.end());

			while (EXPECTED(itf != endf)) {
				const std::string& fname = ns_prefix.empty() ?
					itf->first : ns_prefix + itf->first;

				loadFunction(scope, fname, itf->second);
				++itf;
			}
		}
	}

	if (kind & ModManager::TYPE) {
		TypeMap& types = module->getTypes();

		if (name) {
			TypeMap::const_iterator it(types.find(*name));

			if (it == types.end()) {
				std::cerr << "Type `" << *name << "' not found!" << std::endl;
			} else {
				loadType(scope, it->first, it->second);
			}
		} else {
			TypeMap::const_iterator itt(types.begin()), ite(types.end());

			while (EXPECTED(itt != ite)) {
				const std::string& tname = ns_prefix.empty() ?
					itt->first : ns_prefix + itt->first;

				loadType(scope, tname, itt->second);
				++itt;
			}
		}
	}
}

/// Loads a module if it is not already loaded
void ModManager::loadModule(Scope* scope, Module* module,
	size_t kind, const CString* name) const
{
	// Imports the submodule
	// e.g. import std;   => std:<submodule>:<name>
	// e.g. import std.*; => <submodule>:<name>
	if ((kind & ModManager::ALL)
		&& module->hasModules()) {
		ModuleMap& mods = module->getModules();
		ModuleMap::const_iterator it(mods.begin()), end(mods.end());

		while (it != end) {
			if (it->second->isLoaded()) {
				++it;
				continue;
			}
			it->second->init();
			it->second->setLoaded();

			std::string prefix = it->second->getName() + ":";

			if (kind & ModManager::NAMESPACE) {
				std::replace(prefix.begin(), prefix.end(), '.', ':');
			} else {
				prefix = prefix.substr(prefix.find_last_of(".")+1);
			}

			loadModuleContent(scope, it->second, kind, NULL,  prefix);
			++it;
		}
	}

	if (module->isLoaded()) {
		return;
	}

	module->init();
	module->setLoaded();

	std::string ns_prefix = "";

	if (kind & ModManager::NAMESPACE) {
		ns_prefix = module->getName();

		size_t found = ns_prefix.find_last_of(".");

		if (found != std::string::npos) {
			ns_prefix = ns_prefix.substr(ns_prefix.find_last_of(".")+1) + ":";
		}
	}

	loadModuleContent(scope, module, kind, name, ns_prefix);
}

/// Imports an userland module
ast::Node* ModManager::importFile(Scope* scope,
	const std::string& module, size_t kind, const CString* name) const
{
	std::string mod_name = module;
	std::string ns_name  = kind & ModManager::NAMESPACE ? module : "";

	std::replace(mod_name.begin(), mod_name.end(), '.', '/');

	const std::string& fname = m_include_path + mod_name + ".clv";

	if (!m_driver->loadFile(fname, ns_name)) {
		return m_driver->getCompiler().getAST();
	}

	return NULL;
}

/// Imports a module
ast::Node* ModManager::importModule(Scope* scope,
	const std::string& module, size_t kind, const CString* name) const
{
	ModuleMap::const_iterator it(m_mods.find(module));

	//std::cout << "imp " << module << std::endl;

	if (it == m_mods.end()) {
		ast::Node* tree;

		if ((tree = importFile(scope, module, kind, name)) == NULL) {
			std::cerr << "Module `" << module << "' not found!" << std::endl;
			return NULL;
		}
		return tree;
	}

	loadModule(scope, it->second, kind, name);

	return NULL;
}

} // clever
<commit_msg>- Fixed issue #336<commit_after>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <iostream>
#include "core/driver.h"
#include "core/modmanager.h"
#include "core/value.h"
#include "core/cstring.h"
#include "core/scope.h"
#include "modules/std/std_pkg.h"
#include "modules/db/db_pkg.h"
#include "modules/gui/gui_pkg.h"
#include "core/user.h"

namespace clever {

/// Adds the available packages to be imported
void ModManager::init()
{
	addModule("std",   new modules::Std);
	addModule("db",    new modules::Db);
	addModule("gui",   new modules::Gui);
	addModule("_user", m_user = new UserModule);
}

/// Performs shutdown operation
void ModManager::shutdown()
{
	std::vector<Type*> typevec;
	ModuleMap::const_iterator itm(m_mods.begin()), endm(m_mods.end());

	while (itm != endm) {
		TypeMap& types = itm->second->getTypes();
		TypeMap::const_iterator itt(types.begin()), ite(types.end());

		while (itt != ite) {
			itt->second->deallocMembers();
			typevec.push_back(itt->second);
			++itt;
		}

		clever_delete(itm->second);
		++itm;
	}

	std::for_each(typevec.begin(), typevec.end(), clever_delete<Type>);
}

/// Adds a new module
void ModManager::addModule(const std::string& name, Module* module)
{
	if (m_mods.find(name) != m_mods.end()) {
		return;
	}

	m_mods.insert(ModuleMap::value_type(name, module));
	module->init();
	module->setLoaded();

	if (module->hasModules()) {
		ModuleMap& mods = module->getModules();
		ModuleMap::const_iterator it(mods.begin()), end(mods.end());

		while (it != end) {
			m_mods.insert(ModuleMap::value_type(it->first, it->second));
			++it;
		}
	}
}

/// Loads an specific module type
void ModManager::loadType(Scope* scope, const std::string& name, Type* type) const
{
	Value* tmp = new Value(type, true);

	scope->pushValue(CSTRING(name), tmp);

	type->init();
}

/// Loads an specific module function
void ModManager::loadFunction(Scope* scope, const std::string& name, Function* func) const
{
	Value* fval = new Value();

	fval->setObj(CLEVER_FUNC_TYPE, func);
	fval->setConst(true);

	scope->pushValue(CSTRING(name), fval);
}

void ModManager::loadModuleContent(Scope* scope, Module* module,
	size_t kind, const CString* name, const std::string& ns_prefix) const
{
	if (!name) {
		VarMap& vars = module->getVars();

		if (!vars.empty()) {
			VarMap::const_iterator it(vars.begin()), end(vars.end());

			for (; it != end; ++it) {
				const CString* vname = CSTRING(ns_prefix + it->first);
				scope->pushValue(vname, it->second);
			}
		}
	}

	if (kind & ModManager::FUNCTION) {
		FunctionMap& funcs = module->getFunctions();

		if (name) {
			FunctionMap::const_iterator it(funcs.find(*name));

			if (it == funcs.end()) {
				std::cerr << "Function `" << *name << "' not found!" << std::endl;
			} else {
				loadFunction(scope, it->first, it->second);
			}
		} else {
			FunctionMap::const_iterator itf(funcs.begin()),	endf(funcs.end());

			while (EXPECTED(itf != endf)) {
				const std::string& fname = ns_prefix.empty() ?
					itf->first : ns_prefix + itf->first;

				loadFunction(scope, fname, itf->second);
				++itf;
			}
		}
	}

	if (kind & ModManager::TYPE) {
		TypeMap& types = module->getTypes();

		if (name) {
			TypeMap::const_iterator it(types.find(*name));

			if (it == types.end()) {
				std::cerr << "Type `" << *name << "' not found!" << std::endl;
			} else {
				loadType(scope, it->first, it->second);
			}
		} else {
			TypeMap::const_iterator itt(types.begin()), ite(types.end());

			while (EXPECTED(itt != ite)) {
				const std::string& tname = ns_prefix.empty() ?
					itt->first : ns_prefix + itt->first;

				loadType(scope, tname, itt->second);
				++itt;
			}
		}
	}
}

/// Loads a module if it is not already loaded
void ModManager::loadModule(Scope* scope, Module* module,
	size_t kind, const CString* name) const
{
	// Imports the submodule
	// e.g. import std;   => std:<submodule>:<name>
	// e.g. import std.*; => <submodule>:<name>
	if ((kind & ModManager::ALL)
		&& module->hasModules()) {
		ModuleMap& mods = module->getModules();
		ModuleMap::const_iterator it(mods.begin()), end(mods.end());

		while (it != end) {
			if (it->second->isLoaded()) {
				++it;
				continue;
			}
			it->second->init();
			it->second->setLoaded();

			std::string prefix = it->second->getName() + ":";

			if (kind & ModManager::NAMESPACE) {
				std::replace(prefix.begin(), prefix.end(), '.', ':');
			} else {
				prefix = prefix.substr(prefix.find_last_of(".")+1);
			}

			loadModuleContent(scope, it->second, kind, NULL,  prefix);
			++it;
		}
	}

	if (module->isLoaded()) {
		return;
	}

	module->init();
	module->setLoaded();

	std::string ns_prefix = "";

	if (kind & ModManager::NAMESPACE) {
		ns_prefix = module->getName();

		size_t found = ns_prefix.find_last_of(".");

		if (found != std::string::npos) {
			ns_prefix = ns_prefix.substr(ns_prefix.find_last_of(".")+1) + ":";
		}
	}

	loadModuleContent(scope, module, kind, name, ns_prefix);
}

/// Imports an userland module
ast::Node* ModManager::importFile(Scope* scope,
	const std::string& module, size_t kind, const CString* name) const
{
	std::string mod_name = module;
	std::string ns_name  = kind & ModManager::NAMESPACE ? module : "";

	std::replace(mod_name.begin(), mod_name.end(), '.', '/');

	const std::string& fname = m_include_path + mod_name + ".clv";

	if (!m_driver->loadFile(fname, ns_name)) {
		return m_driver->getCompiler().getAST();
	} else {
		CLEVER_EXIT_FATAL();
	}

	return NULL;
}

/// Imports a module
ast::Node* ModManager::importModule(Scope* scope,
	const std::string& module, size_t kind, const CString* name) const
{
	ModuleMap::const_iterator it(m_mods.find(module));

	//std::cout << "imp " << module << std::endl;

	if (it == m_mods.end()) {
		ast::Node* tree;

		if ((tree = importFile(scope, module, kind, name)) == NULL) {
			std::cerr << "Module `" << module << "' not found!" << std::endl;
			return NULL;
		}
		return tree;
	}

	loadModule(scope, it->second, kind, name);

	return NULL;
}

} // clever
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// Planet - An atmospheric code for planetary bodies, adapted to Titan
//
// Copyright (C) 2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

//Antioch
#include "antioch/physical_constants.h"
#include "antioch/cmath_shims.h"
//Planet
#include "planet/binary_diffusion.h"
#include "planet/planet_constants.h"
//C++
#include <limits>
#include <string>
#include <iomanip>

template<typename Scalar>
int check(const Scalar &test, const Scalar &ref, const Scalar &tol, const std::string &model)
{
  if(Antioch::ant_abs(test - ref)/ref > tol)
  {
     std::cout << std::scientific << std::setprecision(20)
               << "Error in binary diffusion calculations" << std::endl
               << "model is " << model << std::endl
               << "calculated coefficient = " << test << std::endl
               << "solution = " << ref << std::endl
               << "relative error = " << Antioch::ant_abs(test - ref)/ref << std::endl
               << "tolerance = " << tol << std::endl;
     return 1;
  }
  return 0;
}

template<typename Scalar>
int tester()
{

  Scalar p11(0.1783),p12(1.81);
  Scalar p21(1.04e-5),p22(1.76);
  Scalar p31(5.73e16),p32(0.5);

  Planet::BinaryDiffusion<Scalar> N2N2(   0,  0, p11, p12, Planet::DiffusionType::Massman);
  Planet::BinaryDiffusion<Scalar> N2CH4(  0,  1, p21, p22, Planet::DiffusionType::Wakeham);
  Planet::BinaryDiffusion<Scalar> CH4CH4( 1,  1, p31, p32, Planet::DiffusionType::Wilson);

  Scalar T(1500.),P(1e5);
  Scalar n = P / (T * Planet::Constants::Universal::kb<Scalar>());

  Scalar n2n2 = p11 * Planet::Constants::Convention::P_normal<Scalar>() / P * Antioch::ant_pow(T/Planet::Constants::Convention::T_standard<Scalar>(),p12);
  Scalar n2ch4 = p21 * Antioch::ant_pow(T,p22)* Planet::Constants::Convention::P_normal<Scalar>() / P;
  Scalar ch4ch4 = p31 * Antioch::ant_pow(T,p32)/n;

  Scalar nn = N2N2.binary_coefficient(T,P);
  Scalar nc = N2CH4.binary_coefficient(T,P);
  Scalar cc = CH4CH4.binary_coefficient(T,P);

  int return_flag(0);
  const Scalar tol = std::numeric_limits<Scalar>::epsilon() * 100.;
  return_flag = check(nn,n2n2,tol,"Massman")  ||
                check(nc,n2ch4,tol,"Wilson") ||
                check(cc,ch4ch4,tol,"Wakeham");

  return return_flag;
}

int main()
{

  return (tester<float>()  ||
          tester<double>() ||
          tester<long double>());
}
<commit_msg>Test on derivatives added<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// Planet - An atmospheric code for planetary bodies, adapted to Titan
//
// Copyright (C) 2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

//Antioch
#include "antioch/physical_constants.h"
#include "antioch/cmath_shims.h"
#include "antioch/units.h"

//Planet
#include "planet/binary_diffusion.h"
#include "planet/planet_constants.h"

//C++
#include <limits>
#include <string>
#include <iomanip>

template<typename Scalar>
int check(const Scalar &test, const Scalar &ref, const Scalar &tol, const std::string &model)
{
  Scalar dist = (ref < tol)?Antioch::ant_abs(test - ref):
                            Antioch::ant_abs(test - ref)/ref;
  if(dist > tol)
  {
     std::cout << std::scientific << std::setprecision(20)
               << "Error in binary diffusion calculations" << std::endl
               << "model is " << model << std::endl
               << "calculated coefficient = " << test << std::endl
               << "solution = " << ref << std::endl
               << "relative error = " << Antioch::ant_abs(test - ref)/ref << std::endl
               << "tolerance = " << tol << std::endl;
     return 1;
  }
  return 0;
}

template <typename Scalar>
Scalar Dij(const Scalar & T, const Scalar & P, const Scalar & D01, const Scalar & beta)
{
  return D01 * Planet::Constants::Convention::P_normal<Scalar>() / P * Antioch::ant_pow(T/Planet::Constants::Convention::T_standard<Scalar>(),beta);
}

template <typename Scalar>
Scalar dDij_dT(const Scalar & T, const Scalar & P, const Scalar & D01, const Scalar & beta)
{
  return Dij(T,P,D01,beta) * (beta - 1.L)/T;
}

template <typename Scalar>
Scalar dDij_dn(const Scalar & T, const Scalar & P, const Scalar & D01, const Scalar & beta)
{
  return -Dij(T,P,D01,beta) * (T*Planet::Constants::Universal::kb<Scalar>())/(P*P);
}

template<typename Scalar>
int tester()
{

  Scalar p11(0.1783L),p12(1.81L);
  Scalar p21(1.04e-5L),p22(1.76L);
  Scalar p31(5.73e16L),p32(0.5L);

  Planet::BinaryDiffusion<Scalar> N2N2(   0,  0, p11, p12, Planet::DiffusionType::Massman);
  Planet::BinaryDiffusion<Scalar> N2CH4(  0,  1, p21, p22, Planet::DiffusionType::Wakeham);
  Planet::BinaryDiffusion<Scalar> CH4CH4( 1,  1, p31, p32, Planet::DiffusionType::Wilson);

// on range of temperatures, common pressure of
// measurements is 1 atm
  Scalar P(1.L); // in atm
  P *= Antioch::Units<Scalar>("atm").get_SI_factor(); // in Pa

  int return_flag(0);
  const Scalar tol = (std::numeric_limits<Scalar>::epsilon() < 1e-17)?std::numeric_limits<Scalar>::epsilon() * 20.:
                                                                      std::numeric_limits<Scalar>::epsilon() * 10.;
  for(Scalar T = 100.; T < 3500.; T += 100.)
  {

    Scalar n = P / (T * Planet::Constants::Universal::kb<Scalar>());

    Scalar n2n2   = Dij(T,P,p11,p12);
    Scalar n2ch4  = p21 * Antioch::ant_pow(T,p22);
    Scalar ch4ch4 = p31 * Antioch::ant_pow(T,p32) / n;

    Scalar dn2n2_dT   = dDij_dT(T,P,p11,p12);
    Scalar dn2n2_dn   = dDij_dn(T,P,p11,p12);
    Scalar dch4ch4_dT = p32 * p31 / n * Antioch::ant_pow(T,p32 - 1.L);
    Scalar dch4ch4_dn = - p31 * Antioch::ant_pow(T,p32) / (n * n);

    return_flag = check(N2N2.binary_coefficient(T,P),n2n2,tol,"Massman binary coefficient")    ||
                  check(N2CH4.binary_coefficient(T,P),n2ch4,tol,"Wakeham binary coefficient")  ||
                  check(CH4CH4.binary_coefficient(T,P),ch4ch4,tol,"Wilson binary coefficient") ||
                  check(N2N2.binary_coefficient_deriv_T(T,P),dn2n2_dT,tol,"Massman binary coefficient derived to T")    ||
                  check(CH4CH4.binary_coefficient_deriv_T(T,P),dch4ch4_dT,tol,"Wilson binary coefficient derived to T") ||
                  check(N2N2.binary_coefficient_deriv_n(T,P,n),dn2n2_dn,tol,"Massman binary coefficient derived to n")    ||
                  check(CH4CH4.binary_coefficient_deriv_n(T,P,n),dch4ch4_dn,tol,"Wilson binary coefficient derived to n") ||
                  return_flag;
  }

  // golden values
  Scalar T(201.L);
  P = 0.53L;
  Scalar n = P / (T * Planet::Constants::Universal::kb<Scalar>());
  Scalar truth     = 1.95654918135100954675984465985829467e4L;
  Scalar dtruth_dT = 7.88460117857869518843519489793641134e1L;
  Scalar dtruth_dn = -1.0244580436868377275736362395882496e-16L;

  return_flag = check(N2N2.binary_coefficient(T,P),truth,tol,"Massman binary coefficient") ||
                check(N2N2.binary_coefficient_deriv_T(T,P),dtruth_dT,tol,"Massman binary coefficient derived to T") ||
                check(N2N2.binary_coefficient_deriv_n(T,P,n),dtruth_dn,tol,"Massman binary coefficient derived to n") ||
                return_flag;

  return return_flag;
}

int main()
{

  return (tester<float>()  ||
          tester<double>() ||
          tester<long double>());
}
<|endoftext|>


<commit_before>#include "word.h"
#include "kwic.h"
#include "cute.h"
#include "ide_listener.h"
#include "xml_listener.h"
#include "cute_runner.h"

void testWordShouldBeLessComparesInternalValue() {
	//Arrange
	const Word word1("abc");
	const Word word2("bcd");
	//Assert
	ASSERT_LESS(word1, word2);
}

void testWordShouldBeLessComparesCaseInsensitive() {
	//Arrange
	const Word word1("abc");
	const Word word2("BCD");
	//Assert
	ASSERT_LESS(word1, word2);
}

void testWordShiftLeftPrintsInternalValue() {
	//Arrange
	std::ostringstream out { };
	const Word word("hallo");
	//Act
	out << word;
	//Assert
	ASSERT_EQUAL("hallo", out.str());

}

void testConstructWordThrowsInvalidArgumentExceptionForNumber() {
	//Assert
	ASSERT_THROWS(Word("124abd"), std::invalid_argument);
}

void testConstructWordThrowsInvalidArgumentExceptionForSpecialCharacters() {
	//Assert
	ASSERT_THROWS(Word("dsl!*%"), std::invalid_argument);
}

void testWordConsistsOfOnlyLetters() {
	//Arrange
	std::istringstream in { "abc123%" };
	Word word { };
	//Act
	in >> word;
	//Assert
	ASSERT_EQUAL(std::string { "abc" }, word.value);
}

void testWordIsEmptyIfStreamIsEmpty() {
	//Arrange
	std::istringstream in { "              " };
	Word word { };
	//Act
	in >> word;
	//Assert
	ASSERT_EQUAL(0, word.value.length());
}

void testWordsAreDelimitedByNonAlphanumericCharacters() {
	//Arrange
	std::istringstream in { "compl33tely ~ weird !!??!! 4matted in_put" };
	Word word1 { }, word2 { }, word3 { }, word4 { }, word5 { }, word6 { };
	//Act
	in >> word1;
	in >> word2;
	in >> word3;
	in >> word4;
	in >> word5;
	in >> word6;
	//Assert
	ASSERT_EQUAL(std::string { "compl" }, word1.value);
	ASSERT_EQUAL(std::string { "tely" }, word2.value);
	ASSERT_EQUAL(std::string { "weird" }, word3.value);
	ASSERT_EQUAL(std::string { "matted" }, word4.value);
	ASSERT_EQUAL(std::string { "in" }, word5.value);
	ASSERT_EQUAL(std::string { "put" }, word6.value);
}

void testRotateSingleLineReturnsAllMutationsSorted() {
	//Arrange
	const Word mockWord1("this");
	const Word mockWord2("is");
	const Word mockWord3("a");
	const Word mockWord4("test");

	const std::vector<Word> words { Word("this"), Word("is"), Word("a"), Word("test") };

	//Act
	const auto rotatedWords = rotateWords(words);
	auto permuted = std::vector<std::vector<Word>> { };

	for (auto word : rotatedWords) {
		permuted.push_back(word);
	}

	//Assert
	const std::vector<Word> expected1 { mockWord3, mockWord4, mockWord1, mockWord2 };
	ASSERT_EQUAL(expected1, permuted.at(0));

	const std::vector<Word> expected2 { mockWord2, mockWord3, mockWord4, mockWord1 };
	ASSERT_EQUAL(expected2, permuted.at(1));

	const std::vector<Word> expected3 { mockWord4, mockWord1, mockWord2, mockWord3 };
	ASSERT_EQUAL(expected3, permuted.at(2));

	const std::vector<Word> expected4 { mockWord1, mockWord2, mockWord3, mockWord4 };
	ASSERT_EQUAL(expected4, permuted.at(3));
}

void testRotateMultipleLinesReturnsAllMutationsSorted() {
	//Arrange
	std::istringstream in { "this is a test\n"
							"this is another test" };
	std::ostringstream out { };
	//Act
	rotateLines(in, out);
	//Assert
	ASSERT_EQUAL("a test this is \n"
                 "another test this is \n"
                 "is a test this \n"
                 "is another test this \n"
                 "test this is a \n"
                 "test this is another \n"
                 "this is a test \n"
                 "this is another test \n", out.str());
}

void testWordRightShiftPutsWordsIntoSentenceUntilEndOfLine() {
	//Arrange
	std::istringstream in { "this is a test" };
	std::vector<Word> sentence { };
	//Act
	in >> sentence;
	//Assert
	ASSERT_EQUAL(Word("this"), sentence.at(0));
	ASSERT_EQUAL(Word("is"), sentence.at(1));
	ASSERT_EQUAL(Word("a"), sentence.at(2));
	ASSERT_EQUAL(Word("test"), sentence.at(3));
}

void runAllTests(int argc, char const *argv[]) {
	cute::suite s { };

	s.push_back(CUTE(testWordConsistsOfOnlyLetters));
	s.push_back(CUTE(testWordsAreDelimitedByNonAlphanumericCharacters));
	s.push_back(CUTE(testWordIsEmptyIfStreamIsEmpty));
	s.push_back(CUTE(testConstructWordThrowsInvalidArgumentExceptionForNumber));
	s.push_back(CUTE(testConstructWordThrowsInvalidArgumentExceptionForSpecialCharacters));
	s.push_back(CUTE(testWordShiftLeftPrintsInternalValue));
	s.push_back(CUTE(testWordShouldBeLessComparesInternalValue));
	s.push_back(CUTE(testWordShouldBeLessComparesCaseInsensitive));
	s.push_back(CUTE(testRotateSingleLineReturnsAllMutationsSorted));
	s.push_back(CUTE(testRotateMultipleLinesReturnsAllMutationsSorted));
	s.push_back(CUTE(testWordRightShiftPutsWordsIntoSentenceUntilEndOfLine));

	cute::xml_file_opener xmlfile(argc, argv);
	cute::xml_listener<cute::ide_listener<> > lis(xmlfile.out);
	cute::makeRunner(lis, argc, argv)(s, "AllTests");
}

int main(int argc, char const *argv[]) {
	runAllTests(argc, argv);
	return 0;
}
<commit_msg>Better names for test<commit_after>#include "word.h"
#include "kwic.h"
#include "cute.h"
#include "ide_listener.h"
#include "xml_listener.h"
#include "cute_runner.h"

void testWordShouldBeLessComparesInternalValue() {
	//Arrange
	const Word word1("abc");
	const Word word2("bcd");
	//Assert
	ASSERT_LESS(word1, word2);
}

void testWordShouldBeLessComparesCaseInsensitive() {
	//Arrange
	const Word word1("abc");
	const Word word2("BCD");
	//Assert
	ASSERT_LESS(word1, word2);
}

void testWordShiftLeftPrintsInternalValue() {
	//Arrange
	std::ostringstream out { };
	const Word word("hallo");
	//Act
	out << word;
	//Assert
	ASSERT_EQUAL("hallo", out.str());

}

void testConstructWordThrowsInvalidArgumentExceptionForNumber() {
	//Assert
	ASSERT_THROWS(Word("124abd"), std::invalid_argument);
}

void testConstructWordThrowsInvalidArgumentExceptionForSpecialCharacters() {
	//Assert
	ASSERT_THROWS(Word("dsl!*%"), std::invalid_argument);
}

void testWordConsistsOfOnlyLetters() {
	//Arrange
	std::istringstream in { "abc123%" };
	Word word { };
	//Act
	in >> word;
	//Assert
	ASSERT_EQUAL(std::string { "abc" }, word.value);
}

void testWordIsEmptyIfStreamIsEmpty() {
	//Arrange
	std::istringstream in { "              " };
	Word word { };
	//Act
	in >> word;
	//Assert
	ASSERT_EQUAL(0, word.value.length());
}

void testWordsAreDelimitedByNonAlphanumericCharacters() {
	//Arrange
	std::istringstream in { "compl33tely ~ weird !!??!! 4matted in_put" };
	Word word1 { }, word2 { }, word3 { }, word4 { }, word5 { }, word6 { };
	//Act
	in >> word1;
	in >> word2;
	in >> word3;
	in >> word4;
	in >> word5;
	in >> word6;
	//Assert
	ASSERT_EQUAL(std::string { "compl" }, word1.value);
	ASSERT_EQUAL(std::string { "tely" }, word2.value);
	ASSERT_EQUAL(std::string { "weird" }, word3.value);
	ASSERT_EQUAL(std::string { "matted" }, word4.value);
	ASSERT_EQUAL(std::string { "in" }, word5.value);
	ASSERT_EQUAL(std::string { "put" }, word6.value);
}

void testRotateSingleLineReturnsAllRotationsSorted() {
	//Arrange
	const Word mockWord1("this");
	const Word mockWord2("is");
	const Word mockWord3("a");
	const Word mockWord4("test");

	const std::vector<Word> words { Word("this"), Word("is"), Word("a"), Word("test") };

	//Act
	const auto rotatedWords = rotateWords(words);
	auto permuted = std::vector<std::vector<Word>> { };

	for (auto word : rotatedWords) {
		permuted.push_back(word);
	}

	//Assert
	const std::vector<Word> expected1 { mockWord3, mockWord4, mockWord1, mockWord2 };
	ASSERT_EQUAL(expected1, permuted.at(0));

	const std::vector<Word> expected2 { mockWord2, mockWord3, mockWord4, mockWord1 };
	ASSERT_EQUAL(expected2, permuted.at(1));

	const std::vector<Word> expected3 { mockWord4, mockWord1, mockWord2, mockWord3 };
	ASSERT_EQUAL(expected3, permuted.at(2));

	const std::vector<Word> expected4 { mockWord1, mockWord2, mockWord3, mockWord4 };
	ASSERT_EQUAL(expected4, permuted.at(3));
}

void testRotateMultipleLinesReturnsAllRotationsSorted() {
	//Arrange
	std::istringstream in { "this is a test\n"
							"this is another test" };
	std::ostringstream out { };
	//Act
	rotateLines(in, out);
	//Assert
	ASSERT_EQUAL("a test this is \n"
                 "another test this is \n"
                 "is a test this \n"
                 "is another test this \n"
                 "test this is a \n"
                 "test this is another \n"
                 "this is a test \n"
                 "this is another test \n", out.str());
}

void testWordRightShiftPutsWordsIntoSentenceUntilEndOfLine() {
	//Arrange
	std::istringstream in { "this is a test" };
	std::vector<Word> sentence { };
	//Act
	in >> sentence;
	//Assert
	ASSERT_EQUAL(Word("this"), sentence.at(0));
	ASSERT_EQUAL(Word("is"), sentence.at(1));
	ASSERT_EQUAL(Word("a"), sentence.at(2));
	ASSERT_EQUAL(Word("test"), sentence.at(3));
}

void runAllTests(int argc, char const *argv[]) {
	cute::suite s { };

	s.push_back(CUTE(testWordConsistsOfOnlyLetters));
	s.push_back(CUTE(testWordsAreDelimitedByNonAlphanumericCharacters));
	s.push_back(CUTE(testWordIsEmptyIfStreamIsEmpty));
	s.push_back(CUTE(testConstructWordThrowsInvalidArgumentExceptionForNumber));
	s.push_back(CUTE(testConstructWordThrowsInvalidArgumentExceptionForSpecialCharacters));
	s.push_back(CUTE(testWordShiftLeftPrintsInternalValue));
	s.push_back(CUTE(testWordShouldBeLessComparesInternalValue));
	s.push_back(CUTE(testWordShouldBeLessComparesCaseInsensitive));
	s.push_back(CUTE(testRotateSingleLineReturnsAllRotationsSorted));
	s.push_back(CUTE(testRotateMultipleLinesReturnsAllRotationsSorted));
	s.push_back(CUTE(testWordRightShiftPutsWordsIntoSentenceUntilEndOfLine));

	cute::xml_file_opener xmlfile(argc, argv);
	cute::xml_listener<cute::ide_listener<> > lis(xmlfile.out);
	cute::makeRunner(lis, argc, argv)(s, "AllTests");
}

int main(int argc, char const *argv[]) {
	runAllTests(argc, argv);
	return 0;
}
<|endoftext|>


<commit_before>/*
 *  RBDecorators.cpp
 *  golf
 *
 *  Created by Robert Rose on 4/20/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */

#include "RBDecorators.h"

#include "RudeDebug.h"
#include "RudeFile.h"
#include "RudeTextureManager.h"
#include "RudeTweaker.h"

bool gRenderDecos = true;
RUDE_TWEAK(RenderDecos, kBool, gRenderDecos);

RBDecoratorInstance::RBDecoratorInstance()
{
	m_pos[0] = 0.0f;
	m_pos[1] = 0.0f;
	m_pos[2] = 0.0f;
}

void RBDecoratorInstance::Set(float x, float y, float z)
{
	m_pos[0] = x;
	m_pos[1] = y;
	m_pos[2] = z;
}

RBDecorator::RBDecorator()
: m_textureid(0)
, m_numInstances(0)
, m_size(16.0f)
, m_texturesize(128)
{
	SetSize(16.0f);

}

void RBDecorator::SetTexture(const char *file)
{
	m_textureid = RudeTextureManager::GetInstance()->LoadTextureFromPVRTFile(file);
	m_texturesize = RudeTextureManager::GetInstance()->GetTexture(m_textureid)->GetHeight();
}

void RBDecorator::SetSize(float size)
{
	m_size = size;
	float hsize = 0.5f * m_size;

	float uvoffset = 1.0f / m_texturesize;

	// bottom left
	m_verts[0].m_pos[0] = -hsize;
	m_verts[0].m_pos[1] = 0;
	m_verts[0].m_pos[2] = 0;
	m_verts[0].m_uv[0] = 0;
	m_verts[0].m_uv[1] = 0;

	// bottom right
	m_verts[1].m_pos[0] = hsize;
	m_verts[1].m_pos[1] = 0;
	m_verts[1].m_pos[2] = 0;
	m_verts[1].m_uv[0] = 1 - uvoffset;
	m_verts[1].m_uv[1] = 0;

	// top left
	m_verts[2].m_pos[0] = -hsize;
	m_verts[2].m_pos[1] = size;
	m_verts[2].m_pos[2] = 0;
	m_verts[2].m_uv[0] = 0;
	m_verts[2].m_uv[1] = 1 - uvoffset;

	// top left
	m_verts[3].m_pos[0] = -hsize;
	m_verts[3].m_pos[1] = size;
	m_verts[3].m_pos[2] = 0;
	m_verts[3].m_uv[0] = 0;
	m_verts[3].m_uv[1] = 1 - uvoffset;

	// bottom right
	m_verts[4].m_pos[0] = hsize;
	m_verts[4].m_pos[1] = 0;
	m_verts[4].m_pos[2] = 0;
	m_verts[4].m_uv[0] = 1 - uvoffset;
	m_verts[4].m_uv[1] = 0;

	// top right
	m_verts[5].m_pos[0] = hsize;
	m_verts[5].m_pos[1] = size;
	m_verts[5].m_pos[2] = 0;
	m_verts[5].m_uv[0] = 1 - uvoffset;
	m_verts[5].m_uv[1] = 1 - uvoffset;
}

bool RBDecorator::AddInstance(float x, float y, float z)
{
	if(m_numInstances < kMaxInstances)
	{
		m_instances[m_numInstances].Set(x, y, z);

		m_numInstances++;

		return true;
	}
	else
		return false;
}

void RBDecorator::Print()
{
	RUDE_REPORT("\nDECORATOR %s %f\n\n", RudeTextureManager::GetInstance()->GetTexture(m_textureid)->GetName(), m_size);

	for(int i = 0; i < m_numInstances; i++)
	{
		RUDE_REPORT("%f %f %f\n", m_instances[i].m_pos[0], m_instances[i].m_pos[1], m_instances[i].m_pos[2]);
	}
}

void RBDecorator::Render()
{
	glVertexPointer(3, GL_FLOAT, sizeof(RBDecoratorVert), &m_verts[0].m_pos);
	glTexCoordPointer(2, GL_FLOAT, sizeof(RBDecoratorVert), &m_verts[0].m_uv);

	RudeTextureManager::GetInstance()->SetTexture(m_textureid);

	float M[16];

	for(int i = 0; i < m_numInstances; i++)
	{
		glPushMatrix();
		glTranslatef(m_instances[i].m_pos[0], m_instances[i].m_pos[1], m_instances[i].m_pos[2]);

		glGetFloatv(GL_MODELVIEW_MATRIX, M);

		M[0] = 1.0;
		M[1] = 0.0f;
		M[2] = 0.0f;

		M[8] = 0.0f;
		M[9] = 0.0f;
		M[10] = 1.0f;

		/*
		for(int i=0; i<3; i+=2 )
			for(int j=0; j<3; j++ ) {
				if ( i==j )
					M[i*4+j] = 1.0;
				else
					M[i*4+j] = 0.0;
			}*/

		glLoadMatrixf(M);

		glDrawArrays(GL_TRIANGLES, 0, 6);

		glPopMatrix();
	}
}

RBDecoratorCollection::RBDecoratorCollection()
: m_dropTextureNum(0)
{
}

void RBDecoratorCollection::Load(const char *deco)
{
	char filename[512];
	sprintf(filename, "%s.deco", deco);

	char path[512];
	bool found = RudeFileGetFile(filename, path, 512, true);

	if(!found)
		return;

	RUDE_REPORT("RBDecoratorCollection loading %s\n", filename);

	FILE *file = fopen(path, "r");
	RUDE_ASSERT(file, "Could not open file %s", path);

	char buf[256];
	char *line = fgets(buf, 256, file);

	RBDecorator *curdeco = 0;

	while(line)
	{
		char texturename[256];
		float size = 8.0f;

		int result = sscanf(line, "DECORATOR %s %f\n", texturename, &size);

		if(result == 2)
		{
			RUDE_REPORT("  DECORATOR: texture=%s size=%f\n", texturename, size);

			RBDecorator decorator;
			decorator.SetTexture(texturename);
			decorator.SetSize(size);

			m_decorators.push_back(decorator);

			curdeco = &m_decorators[m_decorators.size() - 1];

			AddTexture(texturename);
		}
		else
		{
			float pos[3];
			result = sscanf(line, "%f %f %f\n", &pos[0], &pos[1], &pos[2]);

			if(result == 3)
			{
				RUDE_ASSERT(curdeco, "Failed to parse decorators, DECORATOR not defined");

				RUDE_REPORT("    %f %f %f\n", pos[0], pos[1], pos[2]);
				bool added = curdeco->AddInstance(pos[0], pos[1], pos[2]);

				RUDE_ASSERT(added, "Failed to add decorator instance");

#ifndef NO_DECO_EDITOR
				m_droppedDecorators.push_back(btVector3(pos[0], pos[1], pos[2]));
#endif
			}
		}

		line = fgets(buf, 256, file);
	}

	fclose(file);

}

#ifndef NO_DECO_EDITOR
void RBDecoratorCollection::Drop(const btVector3 &pos, float size)
{
	RUDE_ASSERT(m_textureNames.size() > 0, "No decorators have been loaded so there are no textures to drop with");

	m_dropTextureNum++;
	if(m_dropTextureNum >= m_textureNames.size())
		m_dropTextureNum = 0;

	// Check to make sure there's no already a decorator at this position
	for(unsigned int i = 0; i < m_droppedDecorators.size(); i++)
	{
		if(m_droppedDecorators[i] == pos)
			return;
	}

	m_droppedDecorators.push_back(pos);

	// Check to see if we already have a decorator of the same size and texture
	int curTextureID = RudeTextureManager::GetInstance()->LoadTextureFromPVRTFile(m_textureNames[m_dropTextureNum].c_str());
	for(unsigned int i = 0; i < m_decorators.size(); i++)
	{
		RBDecorator &deco = m_decorators[i];

		if(deco.GetTextureID() == curTextureID)
		{
			if(deco.GetSize() == size)
			{
				bool added = deco.AddInstance(pos.x(), pos.y(), pos.z());

				if(added == false)
				{
					Print();
					RUDE_ASSERT(added, "Failed to add decorator instance");
				}
				return;
			}
		}
	}

	RBDecorator deco;
	deco.SetTexture(m_textureNames[m_dropTextureNum].c_str());
	deco.SetSize(size);
	deco.AddInstance(pos.x(), pos.y(), pos.z());

	m_decorators.push_back(deco);

}
#endif

void RBDecoratorCollection::Print()
{
	RUDE_REPORT("\n\n# Decorator Collection\n#\n#\n#\n");

	for(unsigned int i = 0; i < m_decorators.size(); i++)
	{
		m_decorators[i].Print();
	}
}

void RBDecoratorCollection::Render()
{
	unsigned int numdecos = m_decorators.size();

	if(numdecos == 0 || gRenderDecos == false)
		return;

	// set up draw state

	RGL.Enable(kBackfaceCull, false);

	RGL.EnableClient(kVertexArray, true);
	RGL.EnableClient(kColorArray, false);
	RGL.EnableClient(kTextureCoordArray, true);

	glAlphaFunc(GL_GREATER, 0.5);
    glEnable(GL_ALPHA_TEST);

	// set up GL matrix

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();

	float w = RGL.GetHalfWidth();
	float h = RGL.GetHalfHeight();
	RGL.Frustum(0.0f, 0.0f, w * 2.0f, h * 2.0f, 4.0f, 2500.0f);

	btVector3 eye = RGL.GetEye();
	btVector3 forward = RGL.GetForward();

	btVector3 inup(0, 1, 0);
	btVector3 side = inup.cross(forward);
	side.normalize();

	btVector3 up = forward.cross(side);

	float M[] =
	{
		side.x(), up.x(), forward.x(), 0,
		side.y(), up.y(), forward.y(), 0,
		side.z(), up.z(), forward.z(), 0,
		0, 0, 0, 1
	};

	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(M);
	glTranslatef (-eye.x(), -eye.y(), -eye.z());

	for(unsigned int i = 0; i < numdecos; i++)
	{
		m_decorators[i].Render();
	}

	// restore GL matrix

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	RGL.LoadIdentity();

	// restore draw state
	glDisable(GL_ALPHA_TEST);

}

void RBDecoratorCollection::AddTexture(const char *textureName)
{
	unsigned int size = m_textureNames.size();
	bool found = false;

	for(unsigned int i = 0; i < size; i++)
	{
		if(m_textureNames[i] == std::string(textureName))
			found = true;
	}

	if(!found)
		m_textureNames.push_back(std::string(textureName));
}

<commit_msg>set deco render color to white for windows/macos<commit_after>/*
 *  RBDecorators.cpp
 *  golf
 *
 *  Created by Robert Rose on 4/20/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */

#include "RBDecorators.h"

#include "RudeDebug.h"
#include "RudeFile.h"
#include "RudeTextureManager.h"
#include "RudeTweaker.h"

bool gRenderDecos = true;
RUDE_TWEAK(RenderDecos, kBool, gRenderDecos);

RBDecoratorInstance::RBDecoratorInstance()
{
	m_pos[0] = 0.0f;
	m_pos[1] = 0.0f;
	m_pos[2] = 0.0f;
}

void RBDecoratorInstance::Set(float x, float y, float z)
{
	m_pos[0] = x;
	m_pos[1] = y;
	m_pos[2] = z;
}

RBDecorator::RBDecorator()
: m_textureid(0)
, m_numInstances(0)
, m_size(16.0f)
, m_texturesize(128)
{
	SetSize(16.0f);

}

void RBDecorator::SetTexture(const char *file)
{
	m_textureid = RudeTextureManager::GetInstance()->LoadTextureFromPVRTFile(file);
	m_texturesize = RudeTextureManager::GetInstance()->GetTexture(m_textureid)->GetHeight();
}

void RBDecorator::SetSize(float size)
{
	m_size = size;
	float hsize = 0.5f * m_size;

	float uvoffset = 1.0f / m_texturesize;

	// bottom left
	m_verts[0].m_pos[0] = -hsize;
	m_verts[0].m_pos[1] = 0;
	m_verts[0].m_pos[2] = 0;
	m_verts[0].m_uv[0] = 0;
	m_verts[0].m_uv[1] = 0;

	// bottom right
	m_verts[1].m_pos[0] = hsize;
	m_verts[1].m_pos[1] = 0;
	m_verts[1].m_pos[2] = 0;
	m_verts[1].m_uv[0] = 1 - uvoffset;
	m_verts[1].m_uv[1] = 0;

	// top left
	m_verts[2].m_pos[0] = -hsize;
	m_verts[2].m_pos[1] = size;
	m_verts[2].m_pos[2] = 0;
	m_verts[2].m_uv[0] = 0;
	m_verts[2].m_uv[1] = 1 - uvoffset;

	// top left
	m_verts[3].m_pos[0] = -hsize;
	m_verts[3].m_pos[1] = size;
	m_verts[3].m_pos[2] = 0;
	m_verts[3].m_uv[0] = 0;
	m_verts[3].m_uv[1] = 1 - uvoffset;

	// bottom right
	m_verts[4].m_pos[0] = hsize;
	m_verts[4].m_pos[1] = 0;
	m_verts[4].m_pos[2] = 0;
	m_verts[4].m_uv[0] = 1 - uvoffset;
	m_verts[4].m_uv[1] = 0;

	// top right
	m_verts[5].m_pos[0] = hsize;
	m_verts[5].m_pos[1] = size;
	m_verts[5].m_pos[2] = 0;
	m_verts[5].m_uv[0] = 1 - uvoffset;
	m_verts[5].m_uv[1] = 1 - uvoffset;
}

bool RBDecorator::AddInstance(float x, float y, float z)
{
	if(m_numInstances < kMaxInstances)
	{
		m_instances[m_numInstances].Set(x, y, z);

		m_numInstances++;

		return true;
	}
	else
		return false;
}

void RBDecorator::Print()
{
	RUDE_REPORT("\nDECORATOR %s %f\n\n", RudeTextureManager::GetInstance()->GetTexture(m_textureid)->GetName(), m_size);

	for(int i = 0; i < m_numInstances; i++)
	{
		RUDE_REPORT("%f %f %f\n", m_instances[i].m_pos[0], m_instances[i].m_pos[1], m_instances[i].m_pos[2]);
	}
}

void RBDecorator::Render()
{
	glVertexPointer(3, GL_FLOAT, sizeof(RBDecoratorVert), &m_verts[0].m_pos);
	glTexCoordPointer(2, GL_FLOAT, sizeof(RBDecoratorVert), &m_verts[0].m_uv);

	RudeTextureManager::GetInstance()->SetTexture(m_textureid);

	float M[16];

	for(int i = 0; i < m_numInstances; i++)
	{
		glPushMatrix();
		glTranslatef(m_instances[i].m_pos[0], m_instances[i].m_pos[1], m_instances[i].m_pos[2]);

		glGetFloatv(GL_MODELVIEW_MATRIX, M);

		M[0] = 1.0;
		M[1] = 0.0f;
		M[2] = 0.0f;

		M[8] = 0.0f;
		M[9] = 0.0f;
		M[10] = 1.0f;

		/*
		for(int i=0; i<3; i+=2 )
			for(int j=0; j<3; j++ ) {
				if ( i==j )
					M[i*4+j] = 1.0;
				else
					M[i*4+j] = 0.0;
			}*/

		glLoadMatrixf(M);

		glDrawArrays(GL_TRIANGLES, 0, 6);

		glPopMatrix();
	}
}

RBDecoratorCollection::RBDecoratorCollection()
: m_dropTextureNum(0)
{
}

void RBDecoratorCollection::Load(const char *deco)
{
	char filename[512];
	sprintf(filename, "%s.deco", deco);

	char path[512];
	bool found = RudeFileGetFile(filename, path, 512, true);

	if(!found)
		return;

	RUDE_REPORT("RBDecoratorCollection loading %s\n", filename);

	FILE *file = fopen(path, "r");
	RUDE_ASSERT(file, "Could not open file %s", path);

	char buf[256];
	char *line = fgets(buf, 256, file);

	RBDecorator *curdeco = 0;

	while(line)
	{
		char texturename[256];
		float size = 8.0f;

		int result = sscanf(line, "DECORATOR %s %f\n", texturename, &size);

		if(result == 2)
		{
			RUDE_REPORT("  DECORATOR: texture=%s size=%f\n", texturename, size);

			RBDecorator decorator;
			decorator.SetTexture(texturename);
			decorator.SetSize(size);

			m_decorators.push_back(decorator);

			curdeco = &m_decorators[m_decorators.size() - 1];

			AddTexture(texturename);
		}
		else
		{
			float pos[3];
			result = sscanf(line, "%f %f %f\n", &pos[0], &pos[1], &pos[2]);

			if(result == 3)
			{
				RUDE_ASSERT(curdeco, "Failed to parse decorators, DECORATOR not defined");

				RUDE_REPORT("    %f %f %f\n", pos[0], pos[1], pos[2]);
				bool added = curdeco->AddInstance(pos[0], pos[1], pos[2]);

				RUDE_ASSERT(added, "Failed to add decorator instance");

#ifndef NO_DECO_EDITOR
				m_droppedDecorators.push_back(btVector3(pos[0], pos[1], pos[2]));
#endif
			}
		}

		line = fgets(buf, 256, file);
	}

	fclose(file);

}

#ifndef NO_DECO_EDITOR
void RBDecoratorCollection::Drop(const btVector3 &pos, float size)
{
	RUDE_ASSERT(m_textureNames.size() > 0, "No decorators have been loaded so there are no textures to drop with");

	m_dropTextureNum++;
	if(m_dropTextureNum >= m_textureNames.size())
		m_dropTextureNum = 0;

	// Check to make sure there's no already a decorator at this position
	for(unsigned int i = 0; i < m_droppedDecorators.size(); i++)
	{
		if(m_droppedDecorators[i] == pos)
			return;
	}

	m_droppedDecorators.push_back(pos);

	// Check to see if we already have a decorator of the same size and texture
	int curTextureID = RudeTextureManager::GetInstance()->LoadTextureFromPVRTFile(m_textureNames[m_dropTextureNum].c_str());
	for(unsigned int i = 0; i < m_decorators.size(); i++)
	{
		RBDecorator &deco = m_decorators[i];

		if(deco.GetTextureID() == curTextureID)
		{
			if(deco.GetSize() == size)
			{
				bool added = deco.AddInstance(pos.x(), pos.y(), pos.z());

				if(added == false)
				{
					Print();
					RUDE_ASSERT(added, "Failed to add decorator instance");
				}
				return;
			}
		}
	}

	RBDecorator deco;
	deco.SetTexture(m_textureNames[m_dropTextureNum].c_str());
	deco.SetSize(size);
	deco.AddInstance(pos.x(), pos.y(), pos.z());

	m_decorators.push_back(deco);

}
#endif

void RBDecoratorCollection::Print()
{
	RUDE_REPORT("\n\n# Decorator Collection\n#\n#\n#\n");

	for(unsigned int i = 0; i < m_decorators.size(); i++)
	{
		m_decorators[i].Print();
	}
}

void RBDecoratorCollection::Render()
{
	unsigned int numdecos = m_decorators.size();

	if(numdecos == 0 || gRenderDecos == false)
		return;

	// set up draw state

	RGL.Enable(kBackfaceCull, false);

	RGL.EnableClient(kVertexArray, true);
	RGL.EnableClient(kColorArray, false);
    glColor4f(1.0, 1.0, 1.0, 1.0);
	RGL.EnableClient(kTextureCoordArray, true);

	glAlphaFunc(GL_GREATER, 0.5);
    glEnable(GL_ALPHA_TEST);

	// set up GL matrix

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();

	float w = RGL.GetHalfWidth();
	float h = RGL.GetHalfHeight();
	RGL.Frustum(0.0f, 0.0f, w * 2.0f, h * 2.0f, 4.0f, 2500.0f);

	btVector3 eye = RGL.GetEye();
	btVector3 forward = RGL.GetForward();

	btVector3 inup(0, 1, 0);
	btVector3 side = inup.cross(forward);
	side.normalize();

	btVector3 up = forward.cross(side);

	float M[] =
	{
		side.x(), up.x(), forward.x(), 0,
		side.y(), up.y(), forward.y(), 0,
		side.z(), up.z(), forward.z(), 0,
		0, 0, 0, 1
	};

	glMatrixMode(GL_MODELVIEW);
	glLoadMatrixf(M);
	glTranslatef (-eye.x(), -eye.y(), -eye.z());

	for(unsigned int i = 0; i < numdecos; i++)
	{
		m_decorators[i].Render();
	}

	// restore GL matrix

	glMatrixMode(GL_PROJECTION);
	glPopMatrix();

	RGL.LoadIdentity();

	// restore draw state
	glDisable(GL_ALPHA_TEST);

}

void RBDecoratorCollection::AddTexture(const char *textureName)
{
	unsigned int size = m_textureNames.size();
	bool found = false;

	for(unsigned int i = 0; i < size; i++)
	{
		if(m_textureNames[i] == std::string(textureName))
			found = true;
	}

	if(!found)
		m_textureNames.push_back(std::string(textureName));
}

<|endoftext|>