/************************************************************************
* fobject.cpp - Object container base class of all widget objects *
* *
* This file is part of the Final Cut widget toolkit *
* *
* Copyright 2015-2017 Markus Gans *
* *
* The Final Cut is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* The Final Cut 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
************************************************************************/
#include "final/fobject.h"
// static class attributes
bool FObject::timer_modify_lock;
FObject::TimerList* FObject::timer_list = 0;
const FString* fc::empty_string = 0;
//----------------------------------------------------------------------
// class FObject
//----------------------------------------------------------------------
// constructors and destructor
//----------------------------------------------------------------------
FObject::FObject (FObject* parent)
: widget_object(false)
, parent_obj(parent)
, children_list() // no children yet
, has_parent(false)
{
if ( parent_obj ) // add object to parent
parent_obj->addChild(this);
if ( parent == 0 )
{
timer_modify_lock = false;
if ( ! timer_list )
{
try
{
timer_list = new TimerList();
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
return;
}
}
if ( ! fc::empty_string )
{
try
{
fc::empty_string = new FString("");
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
return;
}
}
}
else
has_parent = true;
}
//----------------------------------------------------------------------
FObject::~FObject() // destructor
{
if ( parent_obj )
parent_obj->delChild(this);
parent_obj = 0;
delOwnTimer(); // delete all timers of this object
if ( ! has_parent && timer_list )
{
delete timer_list;
timer_list = 0;
}
if ( ! has_parent && fc::empty_string )
{
delete fc::empty_string;
fc::empty_string = 0;
}
// delete children objects
if ( hasChildren() )
{
constFObjectIterator iter, last;
FObjectList delete_list = children_list;
iter = delete_list.begin();
last = delete_list.end();
while ( iter != last )
{
delete (*iter);
++iter;
}
}
}
// public methods of FObject
//----------------------------------------------------------------------
FObject* FObject::getChild (int index) const
{
index--;
if ( ! hasChildren() )
return 0;
if ( index < 0 || index >= numOfChildren() )
return 0;
constFObjectIterator iter;
iter = begin();
std::advance (iter, index);
return *iter;
}
//----------------------------------------------------------------------
bool FObject::isChild (FObject* obj) const
{
while ( FObject* p_obj = obj->getParent() )
{
obj = p_obj;
if ( obj == this )
return true;
}
return false;
}
//----------------------------------------------------------------------
void FObject::addChild (FObject* obj)
{
if ( ! obj )
return;
if ( obj->parent_obj )
obj->parent_obj->delChild(obj);
obj->parent_obj = this;
obj->has_parent = true;
children_list.push_back(obj);
}
//----------------------------------------------------------------------
void FObject::delChild (FObject* obj)
{
if ( ! obj )
return;
if ( hasChildren() )
{
obj->removeParent();
children_list.remove(obj);
}
}
//----------------------------------------------------------------------
void FObject::getCurrentTime (timeval* time)
{
gettimeofday(time, 0);
// NTP fix
while ( time->tv_usec >= 1000000 )
{
time->tv_usec -= 1000000;
time->tv_sec++;
}
while ( time->tv_usec < 0 )
{
if ( time->tv_sec > 0 )
{
time->tv_usec += 1000000;
time->tv_sec--;
}
else
{
time->tv_usec = 0;
break;
}
}
}
//----------------------------------------------------------------------
int FObject::addTimer (int interval)
{
FObject::TimerList::iterator iter, last;
timeval time_interval;
timeval currentTime;
int id = 1;
timer_modify_lock = true;
if ( ! timer_list )
{
try
{
timer_list = new TimerList();
}
catch (const std::bad_alloc& ex)
{
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
return -1;
}
}
// find an unused timer id
if ( ! timer_list->empty() )
{
iter = timer_list->begin();
last = timer_list->end();
while ( iter != last )
{
if ( (*iter).id == id )
{
iter = timer_list->begin();
id++;
continue;
}
++iter;
}
}
if ( id <= 0 || id > int(timer_list->size() + 1) )
return 0;
time_interval.tv_sec = interval / 1000;
time_interval.tv_usec = (interval % 1000) * 1000;
getCurrentTime (¤tTime);
timeval timeout = currentTime + time_interval;
timer_data t = { id, time_interval, timeout, this };
// insert in list sorted by timeout
iter = timer_list->begin();
last = timer_list->end();
while ( iter != last && (*iter).timeout < t.timeout )
++iter;
timer_list->insert (iter, t);
timer_modify_lock = false;
return id;
}
//----------------------------------------------------------------------
bool FObject::delTimer (int id)
{
FObject::TimerList::iterator iter, last;
if ( id <= 0 || id > int(timer_list->size()) )
return false;
timer_modify_lock = true;
iter = timer_list->begin();
last = timer_list->end();
while ( iter != last && (*iter).id != id )
++iter;
if ( iter != last )
{
timer_list->erase(iter);
timer_modify_lock = false;
return true;
}
timer_modify_lock = false;
return false;
}
//----------------------------------------------------------------------
bool FObject::delOwnTimer()
{
FObject::TimerList::iterator iter;
if ( ! timer_list )
return false;
if ( timer_list->empty() )
return false;
timer_modify_lock = true;
iter = timer_list->begin();
while ( iter != timer_list->end() )
{
if ( (*iter).object == this )
iter = timer_list->erase(iter);
else
++iter;
}
timer_modify_lock = false;
return true;
}
//----------------------------------------------------------------------
bool FObject::delAllTimer()
{
if ( ! timer_list )
return false;
if ( timer_list->empty() )
return false;
timer_modify_lock = true;
timer_list->clear();
timer_modify_lock = false;
return true;
}
// protected methods of FObject
//----------------------------------------------------------------------
bool FObject::event (FEvent* ev)
{
if ( ev->type() == fc::Timer_Event )
{
onTimer ( const_cast(static_cast(ev)) );
return true;
}
return false;
}
//----------------------------------------------------------------------
void FObject::onTimer (FTimerEvent*)
{ }