2005/5/9

     
 

NotifyObjectEvent.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// 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 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/ref/NotifyObjectEvent.cpp,v 1.13 2005/04/09 19:26:55 kommer Exp $

#include <acdk.h>
#include <map>
#include <vector>
#include "NotifyObjectEvent.h"
#include <acdk/lang/sys/core_fastmutex.h>
#include <acdk/lang/sys/core_vector.h>
#include <acdk/lang/sys/core_hashmap.h>


#if defined(ACDK_LOCAL_DEBUG)
#define DOUT(msg) do { sys::coreout << msg << sys::eofl; } while(false)
#else
/FONT>
/// @internal
#define DOUT(msg)
#endif
/FONT>
/// @internal
int hash(acdk::lang::Object* k, int maxsize)
{
  return int(k) % maxsize;
}


namespace acdk {
namespace lang {
namespace ref {
/// @internal
typedef std::vector<NotifyObjectEventListener*> NotifyListenerList ;
/// @internal
typedef NotifyListenerList::iterator NotifyListenerListIterator ;
/// @internal
typedef std::map<acdk::lang::Object*, NotifyListenerList> NotifierMap;
/// @internal
typedef NotifierMap::iterator NotifierMapIterator;


namespace {
/// @internal
static NotifierMap __elements;
/// @internal
NotifierMap& elements()
{
  //crash at exit in vc6: static NotifierMap __elements;
  return __elements;
}

/// @internal
sys::core_fastmutex __elementMutex;

} // anon namespace
//static 
void 
NotifyObjectEvent::add(acdk::lang::Object* obj, NotifyObjectEventListener* el)
{
  sys::core_lock_guard<sys::core_fastmutex> _lock(__elementMutex);
  DOUT("Add listener: " << (void*)el << " to element " << (void*)obj);
  NotifierMapIterator it = elements().find(obj);
  if (it != elements().end()) {
    (*it).second.push_back(el);
  } else {
    NotifyListenerList vec;
    vec.push_back(el);
    elements().insert(NotifierMap::value_type(obj, vec));
    obj->setExternalRecorded(true);
  }
}


//static 
void 
NotifyObjectEvent::removeListener(NotifyObjectEventListener* el)
{
  sys::core_lock_guard<sys::core_fastmutex> _lock(__elementMutex);
//restart_first:
  DOUT("remove listener: " << (void*)el);
  NotifierMapIterator it = elements().begin();
  NotifierMapIterator end = elements().end();
  while (it != end) 
  {
restart:
    NotifyListenerListIterator vit = (*it).second.begin();
    NotifyListenerListIterator vend = (*it).second.end();
    while (vit != vend) {
      if ((*vit) == el) {
        (*it).second.erase(vit);
        /*
        if ((*it).second.begin() == (*it).second.end())
        {
          elements().erase(it);
          goto restart_first;
        }*/
        goto restart;
      }
      ++vit;
    }
    ++it;
  }
}
 


//static 
void 
NotifyObjectEvent::remove(acdk::lang::Object* obj, NotifyObjectEventListener* el)
{
  sys::core_lock_guard<sys::core_fastmutex> _lock(__elementMutex);
  DOUT("remove object listener: " << (void*)el << " to element " << (void*)obj);
  NotifierMapIterator it = elements().find(obj);
  NotifierMapIterator  end = elements().end();
  if (it == end)
  {
    DOUT("cannot find any listener: " << (void*)el << " to element " << (void*)obj);
    return;
  }
  bool found = false;
restart:
  NotifyListenerList& l = (*it).second;
  NotifyListenerListIterator vit = l.begin();
  NotifyListenerListIterator vend = l.end();
  for (; vit != vend; ++vit) 
  {
    if ((*vit) == el) {
      (*it).second.erase(vit);
      DOUT("removed listener: " << (void*)el << " to element " << (void*)obj);
      found = true;
      goto restart;
    }
  }
  if (found == false)
  {
     DOUT("cannot find listener: " << (void*)el << " to element " << (void*)obj);
  }
  //elements().erase(it);
}

//static 
void 
NotifyObjectEvent::removeObject(acdk::lang::Object* obj)
{
  sys::core_lock_guard<sys::core_fastmutex> _lock(__elementMutex);
  NotifierMapIterator it = elements().find(obj);
  if (it == elements().end())
    return;
  elements().erase(it);
}

//static 
bool 
NotifyObjectEvent::notifyBeforeDestruction(acdk::lang::Object* obj)
{
  sys::core_lock_guard<sys::core_fastmutex> _lock(__elementMutex);
  NotifierMapIterator it = elements().find(obj);
  NotifierMapIterator  end = elements().end();
  if (it == end) 
    return true;
  NotifyListenerList& l = (*it).second;
  NotifyListenerListIterator vit = l.begin();
  NotifyListenerListIterator vend = l.end();
  while (vit != vend) {
    if ((*vit)) {
      if ((*vit)->notifyBeforeDestruction(obj) == false)
        return false;
    }
    ++vit;
  }
  return true;
}


//static 
void 
NotifyObjectEvent::notifyWhileDestruction(acdk::lang::Object* obj)
{
  {
    sys::core_lock_guard<sys::core_fastmutex> _lock(__elementMutex);// ### not needed (other too)
    NotifierMapIterator it = elements().find(obj);
    NotifierMapIterator end = elements().end();
    if (it == end) 
      return;

    NotifyListenerListIterator vit = (*it).second.begin();
    NotifyListenerListIterator vend = (*it).second.end();
    while (vit != vend) 
    {
      if ((*vit))
        (*vit)->notifyWhileDestruction(obj);
      ++vit;
    }
  }
  removeObject(obj);
}

} // namespace ref
} // namespace lang 
} // namespace acdk