diff options
author | Rodrigo Arias Mallo <rodarima@gmail.com> | 2024-12-10 22:30:12 +0100 |
---|---|---|
committer | Rodrigo Arias Mallo <rodarima@gmail.com> | 2024-12-10 22:30:12 +0100 |
commit | 429d5f88b94ff28416cbfc6420b6389fa284df97 (patch) | |
tree | fb6fdaf7731de1ef396f98b748c56f3149801c84 /objects/objcount_window.cc |
Import RTFL 0.1.1v0.1.1
Diffstat (limited to 'objects/objcount_window.cc')
-rw-r--r-- | objects/objcount_window.cc | 445 |
1 files changed, 445 insertions, 0 deletions
diff --git a/objects/objcount_window.cc b/objects/objcount_window.cc new file mode 100644 index 0000000..d7adf06 --- /dev/null +++ b/objects/objcount_window.cc @@ -0,0 +1,445 @@ +/* + * RTFL + * + * Copyright 2013-2015 Sebastian Geerken <sgeerken@dillo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 <http://www.gnu.org/licenses/>. + */ + +#include "objcount_window.hh" +#include "common/about.hh" + +#include <FL/Fl_Menu_Bar.H> +#include <FL/Fl_Menu_Item.H> +#include <FL/fl_draw.H> + +using namespace lout::container::typed; +using namespace lout::object; +using namespace lout::misc; + +namespace rtfl { + +namespace objects { + +ObjCountTable::Class::Class (const char *name) +{ + this->name = strdup (name); + count = new lout::misc::SimpleVector<int> (1); + count->increase (); + *(count->getLastRef()) = 0; +} + + +ObjCountTable::Class::~Class () +{ + free (name); + delete count; +} + + +int ObjCountTable::Class::compareTo(Comparable *other) +{ + return strcmp (name, ((Class*)other)->name); +} + + +void ObjCountTable::Class::create () +{ + (*(count->getLastRef()))++; +} + + +void ObjCountTable::Class::remove () +{ + (*(count->getLastRef()))--; +} + + +void ObjCountTable::Class::newSnapshot () +{ + int c = *(count->getLastRef()); + count->increase (); + *(count->getLastRef()) = c; +} + + +// ---------------------------------------------------------------------- + + +int ObjCountTable::Object::classSernoGlobal = 0; + + +ObjCountTable::Object::Object (Class *klass) +{ + setClass (klass); + refCount = 0; +} + + +ObjCountTable::Object::~Object () +{ +} + + +void ObjCountTable::Object::setClass (Class *klass) +{ + this->klass = klass; + classSerno = classSernoGlobal++; +} + + +// ---------------------------------------------------------------------- + + +ObjCountTable::ObjectRef::ObjectRef (rtfl::objects::ObjCountTable::Object + *object) +{ + this->object = object; + object->ref (); +} + + +ObjCountTable::ObjectRef::~ObjectRef () +{ + object->unref (); +} + + +// ---------------------------------------------------------------------- + + +ObjCountTable::ObjCountTable (int x, int y, int width, int height, + const char *label) : + Fl_Table (x, y, width, height, label) +{ + rows (0); + row_header (true); + row_height_all (20); + row_resize (false); + + cols (1); + col_header (false); + row_header_width (200); + col_width_all (80); + col_resize (true); + + end(); + + objects = new HashTable<String, ObjectRef> (true, true); + identities = new HashTable<String, String> (true, true); + identitiesRev = new HashTable<String, String> (false, false); + classes = new HashTable<String, Class> (true, false); + classesList = new Vector<Class> (1, true); + + ensureClass ("<unknown>"); +} + + +ObjCountTable::~ObjCountTable() +{ + delete objects; + delete identitiesRev; + delete identities; + delete classes; + delete classesList; +} + + +void ObjCountTable::draw_cell (TableContext context, int row, int col, int x, + int y, int width, int height) +{ + switch (context) { + case CONTEXT_COL_HEADER: + break; + + case CONTEXT_ROW_HEADER: + fl_push_clip (x, y, width, height); + fl_draw_box (FL_THIN_UP_BOX, x, y, width, height, row_header_color ()); + fl_color (FL_BLACK); + fl_draw (classesList->get(row)->name, x, y, width, height, FL_ALIGN_LEFT); + fl_pop_clip (); + break; + + case CONTEXT_CELL: + fl_push_clip (x, y, width, height); + fl_color (FL_WHITE); + fl_rectf (x, y, width, height); + fl_color (FL_BLACK); + char buf[6]; + snprintf (buf, 6, "%d", classesList->get(row)->count->get (col)); + fl_draw (buf, x, y, width, height, FL_ALIGN_RIGHT); + fl_pop_clip (); + break; + + default: + // compiler happyness + break; + } +} + + +ObjCountTable::Class *ObjCountTable::ensureClass (const char *className) +{ + String key (className); + Class *klass = classes->get (&key); + + if (klass == NULL) { + klass = new Class (className); + classes->put (new String (className), klass); + + int i = classesList->bsearch (klass, false); + classesList->insert (klass, i); + for (int j = i; j < classesList->size (); j++) + classesList->get(j)->index = j; + + rows (rows () + 1); + } + + return klass; +} + +void ObjCountTable::createObject (const char *id, const char *className) +{ + Class *klass = ensureClass (className); + + String key (id); + ObjectRef *objectRef = objects->get (&key); + + if (objectRef != NULL) { + objectRef->object->getClass()->remove (); + objectRef->object->setClass (klass); + } else { + rtfl::objects::ObjCountTable::Object *object; + String *id2 = identities->get (&key); + if (id2) { + ObjectRef *objRef2 = objects->get (id2); + assert (objRef2 != NULL); + object = objRef2->object; + } else + object = new rtfl::objects::ObjCountTable::Object (klass); + + objectRef = new ObjectRef (object); + objects->put (new String (id), objectRef); + } + + klass->create (); + damage_zone(klass->index, cols () - 1, klass->index, cols () - 1); +} + + +void ObjCountTable::deleteObject (const char *id) +{ + String key (id); + ObjectRef *objectRef = objects->get (&key); + if (objectRef != NULL) { + objectRef->object->getClass()->remove (); + damage_zone(objectRef->object->getClass()->index,cols () - 1, + objectRef->object->getClass()->index, cols () - 1); + + objects->remove (&key); + + String *key2 = identities->get (&key); + if (key2) { + identitiesRev->remove (key2); + identities->remove (&key); + } else { + key2 = identitiesRev->get (&key); + if (key2) { + identitiesRev->remove (&key); + identities->remove (key2); + } + } + } +} + + +void ObjCountTable::registerObject (const char *id) +{ + String key (id); + if (!objects->contains (&key)) + createObject (id, "<unknown>"); +} + + +void ObjCountTable::addIdentity (const char *id1, const char *id2) +{ + if (strcmp (id1, id2) != 0) { + // Note: An ObjectRef (which is != NULL) points always to an Object. + String key1 (id1), key2 (id2); + ObjectRef *objRef1 = objects->get (&key1), + *objRef2 = objects->get (&key2); + + if (objRef1 == NULL && objRef2 == NULL) { + // Neither defined: create both. + registerObject (id1); + insertIdentity (id2, id1); + registerObject (id2); + } else if (objRef1 == NULL) { + // First not defined, but second: create from second. + insertIdentity (id2, id1); + registerObject (id2); + } else if (objRef2 == NULL) { + // Vice versa. + insertIdentity (id1, id2); + registerObject (id1); + } else { + // Both already defined ... + if (objRef1->object == objRef2->object) + // ... for same object: caller's fault. + fprintf (stderr, "WARNING: Identity of '%s' and '%s' added twice.", + id1, id2); + else { + // ... for different objects. + if (objRef1->object->getClassSerno () > + objRef2->object->getClassSerno ()) { + // Class definition of first object more recent, so assign it to + // second. + objRef2->object->getClass()->remove (); + damage_zone(objRef2->object->getClass()->index,cols () - 1, + objRef2->object->getClass()->index, cols () - 1); + objRef2->object->unref (); + objRef2->object = objRef1->object; + objRef2->object->ref (); + } else { + // Vice versa. + objRef1->object->getClass()->remove (); + damage_zone(objRef1->object->getClass()->index,cols () - 1, + objRef1->object->getClass()->index, cols () - 1); + objRef1->object->unref (); + objRef1->object = objRef2->object; + objRef1->object->ref (); + } + } + } + } +} + + +void ObjCountTable::insertIdentity (const char *id1, const char *id2) +{ + String *s1 = new String (id1), *s2 = new String (id2); + identities->put (s1, s2); + identitiesRev->put (s2, s1); +} + + +void ObjCountTable::setClassColor (const char *klass, const char *color) +{ +} + + +void ObjCountTable::newSnapshot () +{ + for (int i = 0; i < classesList->size (); i++) + classesList->get(i)->newSnapshot (); + + cols (cols () + 1); +} + + +void ObjCountTable::removeOldestSnapshot () +{ +} + + +// ---------------------------------------------------------------------- + + +ObjCountWindow::ObjCountWindow (int width, int height, const char *title) : + Fl_Window (width, height, title) +{ + int menuHeight = 24; + + callback(windowCallback, NULL); + box(FL_NO_BOX); + + Fl_Menu_Bar *menu = new Fl_Menu_Bar(0, 0, width, menuHeight); + + table = new ObjCountTable (0, menuHeight, width, height - menuHeight); + + Fl_Menu_Item menuItems[] = { + { "&File", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 }, + { "Quit", FL_COMMAND + 'q', quit, this, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + + { "&Snapshot", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 }, + { "New &snapshot", FL_COMMAND + 's', newSnapshot, this, 0, 0, 0, 0, 0 }, + { "&Delete oldest", FL_COMMAND + 'd', removeOldestSnapshot, this, + 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + + { "&Help", 0, 0, 0, FL_SUBMENU, 0, 0, 0, 0 }, + { "&About RTFL", 0, about, this, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } + }; + menu->copy(menuItems); + + resizable(table); + + aboutWindow = NULL; +} + + +ObjCountWindow::~ObjCountWindow () +{ + if (aboutWindow) + delete aboutWindow; +} + + +void ObjCountWindow::windowCallback (Fl_Widget *widget, void *data) +{ + // Ignore escape key. TODO Looks rather hackish to me. + if (Fl::event_key() != FL_Escape) + quit (widget, data); +} + + +void ObjCountWindow::quit (Fl_Widget *widget, void *data) +{ + exit (0); +} + + +void ObjCountWindow::newSnapshot (Fl_Widget *widget, void *data) +{ + ObjCountWindow *window = (ObjCountWindow*)data; + window->table->newSnapshot (); +} + + +void ObjCountWindow::removeOldestSnapshot (Fl_Widget *widget, void *data) +{ + ObjCountWindow *window = (ObjCountWindow*)data; + window->table->removeOldestSnapshot (); +} + + +void ObjCountWindow::about (Fl_Widget *widget, void *data) +{ + ObjCountWindow *window = (ObjCountWindow*)data; + + if (window->aboutWindow == NULL) + window->aboutWindow = + new common::AboutWindow("rtfl-objcount", "", + common::AboutWindow::HEIGHT_SIMPLE); + window->aboutWindow->show (); +} + + +} // namespace objects + +} // namespace rtfl |