// Description   : Editing forms for NANO OS $Revision: 29 $

// Copyright     : Proxima Centauri Romania SRL, ALL RIGHTS RESERVED. (http://www.ProximaCentauri.org)

// Author        : Alexander Ioan Mihail

 

#include "ourapp.h"

 

#ifdef USE_QT

  #include "GUI/Edit_Generic/ui_Edit_Generic.h"

  #include "GUI/Edit_Folder/ui_Edit_Folder.h"

  #include <QStringListModel>

#else

  #include <windows.h>

#endif

 

bool AppCreatesWindow()

{

#ifdef USE_QT

    return true;

#else

    return false;

#endif

}

 

void Ring1CloseEditor(ELEMENT*element)

{

  ELEMENT*proxy=(ELEMENT*)element->SetEditor(nullptr);

  if (!proxy)

    return;

  GControl*widget=(GControl*)proxy->TSLPIO[0].Object;

  if (!widget)

    return;

  ELEMENT*app=CORE_APP(widget);

  if (app)

    delete app;

  delete widget;

}

int Ring1CreateEditor(void*app,ELEMENT* obj,int flags,BOND* aspect)

{

  if (!obj->TSLPIO[0].POYC[0])

    return 0;

  OurApplication*our_app=(OurApplication*)app;

  GControl*w=nullptr;

  if (obj->TSLPIO[3].POYC[3])

    Ring1CloseEditor(obj);

  our_app->CreateWidget(nullptr,obj,obj,&w);

  return (int)w;

}

int (*SaveTrace)(void*app,ETraceFlags flags,int,PSTRING msg);

int Ring1Trace(void*app,ETraceFlags flags,int,PSTRING msg)

{

 #ifndef USE_QT

  if (app)

  {

    ELEMENT*proxy=(ELEMENT*)app;

    OurApplication*application=(OurApplication*)proxy->TSLPIO[0].Object;

    if (application->main_window)

      return application->main_window->Log->Access(+1,0,msg,0,flags);

  }

#endif

  printf(msg);

  return 0;

}

 

GenericWindow::GenericWindow (OurApplication* app, ELEMENT* node, int resid)

  #ifndef USE_QT

   :GTabPage(app?(GTabControl*)app->main_window->Splitter->B:0,resid)

  #else

   :GTabPage(0,0)

  #endif

  ,ui(nullptr)

{

 #ifdef USE_QT

  setAttribute(Qt::WA_DeleteOnClose);

 #endif

  if (app)

  {

    ELEMENT*parent=CORE_APP(app);

    setUserData(0,(GObjectUserData*)ELEMENT::INIT((ELEMENT*)this,parent,"edit_generic",node,&node->GetKernel()->Types[CAT_CORE::em_PROXY],nullptr,0));

    node->SetEditor(CORE_APP(this));

  }

  else

    node->SetEditor(nullptr);

}

GenericWindow::~GenericWindow()

{

  ELEMENT*e=CORE_APP(this);

  if (e)

  {

    e->TSLPIO[0].Object=nullptr;

    delete e;

  }

  setUserData(0,0);

}

 

OurApplication::OurApplication (int& argc, char** argv)

  :GApplication(argc,argv)

  ,main_window(nullptr)

{

  ELEMENT*thread=ELEMENT::GetThread();

  ELEMENT*proc=thread->GetProcess();

  CAT_CORE*core=proc->GetKernel();

  ELEMENT*app=ELEMENT::INIT(nullptr,proc,"Application",nullptr,&core->Types[CAT_CORE::em_PROXY],nullptr,0);

  app->TSLPIO[0].Object=(ELEMENT*)this;

  setUserData(0,(GObjectUserData*)app);

  CORE_APP(this)->TSLPIO[5].POYC[0]=&core->TSLPIO[4];

  #ifdef USE_QT

  if (!connect(this, SIGNAL(sig_CreateWidget(QWidget*,ELEMENT*,ELEMENT*,QWidget**)), this, SLOT(CreateWidget(QWidget*,ELEMENT*,ELEMENT*,QWidget**)),Qt::ConnectionType::BlockingQueuedConnection))

    TRACE((ETraceFlags::NORMAL,0,"Error"));

  if (!connect(this, SIGNAL(sig_DeleteWidget(QWidget*)), this, SLOT(DeleteWidget(QWidget*)),Qt::ConnectionType::BlockingQueuedConnection))

    TRACE((ETraceFlags::NORMAL,0,"Error"));

  #endif

  ELEMENT::fEdit=Ring1CreateEditor;

  SaveTrace=ELEMENT::fTrace;

  ELEMENT::fTrace=Ring1Trace;

}

OurApplication::~OurApplication ()

{

  ELEMENT::fTrace=SaveTrace;

  if (main_window)

  {

    delete main_window;

    main_window=nullptr;

  }

  ELEMENT*proxy=CORE_APP(this);

  proxy->TSLPIO[0].Object=nullptr;

  delete proxy;

  setUserData(0,nullptr);

}

void OurApplication::Dock (GTabPage* w)

{

  ELEMENT*wa=(ELEMENT*)w->userData(0);

  char*name=wa->TSLPIO[5].POYC[0]->Object->Name;

 #ifdef USE_QT

  main_window->tab_Edits->addTab(w,name);

  main_window->tab_Edits->setCurrentWidget(w);

 #else

  GTabControl*tab=(GTabControl*)main_window->Splitter->B;

  GWindow*gw=((GTabControl*)main_window->Splitter->B)->AddPage(name,w);

 #endif

}

using namespace NANO_RING1;

void OurApplication::CreateWidget (GControl* parent, ELEMENT* node, ELEMENT* browse, GControl** result)

{

  *result=nullptr;

  ELEMENT*app=CORE_APP(this);

  CAT_RING1*core=(CAT_RING1*)app->GetKernel();

  ELEMENT*meta=node->TypeOf();

  if (meta==core)

    *result=new DockWindow(this,node,browse);

  else

  {

    if (node->IsOfType(&core->Types[CAT_RING1::em_DIRECTORY]))

      *result=new Edit_Folder(this,node);

    else

      *result=new Edit_Generic(this,node);

    if (*result)

        Dock((GTabPage*)*result);

  }

}

void OurApplication::DeleteWidget (GControl* widget)

{

  delete widget;

}

 

DockWindow::DockWindow (OurApplication* app, ELEMENT* node, ELEMENT* path)

  :GenericWindow(nullptr,node)

  #ifndef USE_QT

  ,Splitter(0)

  ,Log(nullptr)

  #endif

{

 #ifdef USE_QT

  ui=new Ui_MainWindow();

  app->main_window=(Ui_MainWindow*)ui;

  ((Ui_MainWindow*)ui)->setupUi(this);

  char buf[100];

  sprintf(buf,"%s %s %s","NANO","2.0",path->GetVersion());

  ((Ui_MainWindow*)ui)->Version->setText(buf);

  GControl*browser=new Browser("noname",path,0);

  CORE_APP(browser)->Insert(CORE_APP(app));

  ((Ui_MainWindow*)ui)->gridLayout->addWidget(browser,1,0,1,1);

  statusBar()->showMessage("NANO OS running...");

  if (!connect(((Ui_MainWindow*)ui)->actionEdit, SIGNAL(triggered()), browser, SLOT(onEdit()),Qt::ConnectionType::QueuedConnection))

    TRACE((ETraceFlags::NORMAL,0,"Error"));

 #else

   GSplitter*vert=new GSplitter(this,0);

   vert->Horizontal=true;

   Log=new GEdit(vert);

   Splitter=new GSplitter(vert,0);

   vert->SetWnds(Splitter,Log);

   GWindow*browser=new Browser("noname",path,Splitter);

   GWindow*tabs=new GTabControl(Splitter);

   Splitter->SetWnds(browser,tabs);

   CORE_APP(browser)->Insert(CORE_APP(app));

   ((OurApplication*)qApp)->main_window=this;

   tabs->onCreate();

   About=(GTabPage*)tabs->POYC[3];

 #endif

   show();

   if (!AppCreatesWindow())

     qApp->exec();

}

 

#pragma optimize( "", off )

void DockWindow::Notify(GWindow*Sender,int ctrlid)

{

  STACK_FRAME

  void*dummy2;

 #ifndef USE_QT

  if (Sender==About)

  {

    Browser*browser=(Browser*)Splitter->A;

    ELEMENT*proxy=CORE_APP(browser);

    CAT_CORE*core=proxy->GetKernel();

    if (ctrlid==1005)

    {

      if (!ELEMENT::GetThread()->Fork("TH.Walk"))

      {

        core->Walk();

        delete ELEMENT::GetThread();

      }

    }

    else if (ctrlid==1006)

    {

      if (!ELEMENT::GetThread()->Fork("TH.Listing"))

      {

        char path[500];

        path[0]=0;

        TRACE((ETraceFlags::NORMAL,0,"Listing of %s:\r\n",core->Name));

        int sz=core->GetSize(path,0);

        TRACE((ETraceFlags::NORMAL,0,"Size of %s is %d\r\n",core->Name,sz));

        delete ELEMENT::GetThread();

      }

    }

  }

#endif

}

#pragma optimize( "", on )

 

Edit_Generic::Edit_Generic (OurApplication* app, ELEMENT* node)

  :GenericWindow(app,node,104)

{

  #ifdef USE_QT

  Ui_Edit_Generic*edit=new Ui_Edit_Generic();

  ui=edit;

  edit->setupUi(this);

  #endif

}

 

Edit_Folder::Edit_Folder (OurApplication* app, ELEMENT* node)

  :GenericWindow(app,node,105)

{

 #ifdef USE_QT

  Ui_Edit_Folder*edit=new Ui_Edit_Folder();

  ui=edit;

  edit->setupUi(this);

  QStringListModel *model = new QStringListModel();

  ELEMENT*var=nullptr;

  QStringList list;

  FOR_CHILDREN_OF(node)

    list << var->Name;

  FOREND

  model->setStringList(list);

  edit->listView->setModel(model);

 #endif

}

 

BrowserItem::BrowserItem (GTreeItem* parent, BOND* st, ELEMENT* target, char* info)

  :GTreeItem(parent,GTreeItem::UserType)

  ,Tag(st)

{

  SetTarget(st,(ELEMENT*)target,info);

}

BrowserItem::BrowserItem (Browser* parent, BOND* st, ELEMENT* target, char* info)

  :GTreeItem(parent,GTreeItem::UserType)

  ,Tag(st)

{

  SetTarget(st,(ELEMENT*)target,info);

}

BrowserItem::~BrowserItem ()

{

  ELEMENT*target=this->GetTarget();

  if (!target)

    return;

  if (target->IsSelector())

    if (Tag==&target->TSLPIO[1])

      target=target->GetEndpoint();

    else

      target=target->GetParent();

  Ring1CloseEditor(target);

}

void BrowserItem::SetTarget (BOND* sb, ELEMENT* target, GString info)

{

  if (target->IsSelector())

    if (sb==&target->TSLPIO[1])

    {

      target=target->GetEndpoint();

      info="to";

    }

    else

    {

      target=target->GetParent();

      info="from";

    }

  BrowserItem*parent=nullptr;

  if (target)

  {

   ELEMENT*meta=target->TypeOf();

   if (meta&&!HasLabel(0))

   {

    #ifdef USE_QT

     void*data;

     int size;

     meta->GetBitmapData(data,size);

     QPixmap pixmap;

     pixmap.loadFromData((uchar*)data,size);

     this->setIcon(0, QIcon(pixmap));

    #else

     SetMeta(meta);

    #endif

   }

   char buf[256];

   target->Translate(-1,0,buf,sizeof(buf),0);

   setText(0,buf);

   setText(1,info);

   ELEMENT*p;

   if (target->TSLPIO[3].POYC[3] && (p=target->TSLPIO[3].POYC[3]->Object) && (p=p->GetParent()) && (p=p->GetParent()) && (p=p->GetParent()))

     setText(2,p->Name);

   else

     setText(2,nullptr);

   SetButton();

  }

  else

   setText(0,"..");

}

ELEMENT* BrowserItem::GetTarget ()

{

  if (text(1)=="instance")

   return (ELEMENT*)((char*)Tag-(char*)&(*((ELEMENT*)0)).TSLPIO[0]);

  return (ELEMENT*)Tag->Object;

}

void BrowserItem::SetButton ()

{

 #ifdef USE_QT

  setChildIndicatorPolicy(GTreeItem::ShowIndicator);

 #endif

}

bool BrowserItem::HasLabel(int aspect)

{

  #ifdef USE_QT

    return text(aspect)!="";

  #else

    char buf[100];

    GetText(aspect,buf,sizeof(buf));

    return buf[0]!=0;

  #endif

}

 

Browser::Browser (char* name, ELEMENT* target, GWindow* parent)

  :GTreeView(parent)

{

  CAT_CORE*core=target->GetKernel();

  ELEMENT*process=core->GetProcess();

  ELEMENT*proxy=ELEMENT::INIT((ELEMENT*)this,process,"Browser",nullptr,&core->Types[CAT_CORE::em_PROXY],nullptr,0);

  setUserData(0,(GObjectUserData*)proxy);

 #ifdef USE_QT

  connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(onExpanded(const QModelIndex&)));

  connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(onCollapsed(const QModelIndex&)));

  connect(this, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(onItemDoubleClicked(const QModelIndex&)));

  QStringList list;

  list << "Name" << "Role" << "locked by";

  setHeaderLabels(list);

  setColumnWidth(1,50);

  setColumnWidth(0,150);

 #endif

  SetTarget(target);

  RefreshTimer=new GTimer(this);

 #ifdef USE_QT

  connect(RefreshTimer, SIGNAL(timeout()), this, SLOT(onRefreshTimer()));

 #else

  __hook(&GTimer::timeout, RefreshTimer, &Browser::onRefreshTimer);

 #endif

  RefreshTimer->start(1000);

}

Browser::~Browser ()

{

  ELEMENT*e=(ELEMENT*)userData(0);

  if (e)

  {

    e->TSLPIO[0].Object=nullptr;

    delete e;

  }

  setUserData(0,nullptr);

}

void Browser::SetTarget (ELEMENT* target)

{

  CORE_APP(this)->TSLPIO[5].POYC[0]=&target->TSLPIO[4];

}

void Browser::Edit (BOND* tag)

{

  ELEMENT*e=tag->Object;

  if (!e||e==e->GetKernel())

    e=(ELEMENT*)((char*)tag-(char*)&(*((ELEMENT*)0)).TSLPIO[0]);

  if (e->IsSelector())

    e=((ELEMENT*)e)->GetEndpoint();

  if (e->TSLPIO[3].POYC[3])

    Ring1CloseEditor(e);

  else

  {

    ELEMENT*meta=e->TypeOf();

    ELEMENT::Edit(qApp,e,0,tag);

  }

}

void Browser::RefreshTree (ELEMENT* endpoint, int depth)

{

  try

  {

    BrowserItem*bitem=(BrowserItem*)invisibleRootItem();

    ELEMENT*e=CORE_APP(this);

    LogForest(bitem,e->TSLPIO[5].POYC[0]->Object,0);

  }

  catch (...)

  {

    ELEMENT::Trace(ETraceFlags::RED,0,"Navigator refresh error: ");

  }

}

void Browser::LogForest (BrowserItem* branch, ELEMENT* ent, int flags)

{

  int bcount=branch->childCount();

  BrowserItem*tn;

  BOND* sbc=ent->TSLPIO[1].get_First();

  while (sbc)

  {

    if (sbc->Object->IsSelector()&&sbc==&((ELEMENT*)sbc->Object)->TSLPIO[5])

      BreakPoint();

    else

    {

      int found;

      // Should get rid of bcount and loop over the items.

      for (found=0;found<bcount;found++)

      {

        tn=(BrowserItem*)branch->child(found);

        if ((BOND*)tn->Tag==sbc)

          break;

      }

      if (branch==invisibleRootItem()||branch->isExpanded())

        if (found==bcount)

          if (branch==invisibleRootItem())

            tn=new BrowserItem(this,sbc,(ELEMENT*)sbc->Object,"scope");

          else

            tn=new BrowserItem(branch,sbc,(ELEMENT*)sbc->Object,"scope");

        else

          LogTreeAspects((BrowserItem*)tn,flags,(ELEMENT*)sbc->Object);

    }

    sbc=sbc->POYC[1];

    if (sbc==ent->TSLPIO[1].get_First())

      sbc=nullptr;

  }

  sbc=ent->TSLPIO[1].get_First();

  for (int i=0;i<bcount;)

  {

    tn=(BrowserItem*)branch->child(i);

    int found=0;

    for (;found<bcount&&sbc;)

    {

      if ((BOND*)tn->Tag==sbc)

        break;

      if (sbc->Object->IsSelector()&&sbc==&((ELEMENT*)sbc->Object)->TSLPIO[5])

        BreakPoint();

      else

        found++;

      sbc=sbc->POYC[1];

    }

    if (found==bcount)

    {

      delete tn;

      bcount--;

      continue;

    }

    i++;

  }

}

void Browser::LogTreeAspects (BrowserItem* branch, int flags, ELEMENT* ent)

{

  BOND*sb=branch->Tag;

  if (!sb)

    return;

  if (!ent)

    return;

  branch->SetTarget (branch->Tag,ent,branch->text(1));

  int bcount=branch->childCount();

  if (!flags)

  {

    BrowserItem*tn;

    if (branch->isExpanded())

    {

      BOND* sbc;

      sbc=ent->TSLPIO[1].get_First();

      while (sbc)

      {

        if (sbc->Object->IsSelector()&&sbc==&sbc->Object->TSLPIO[5])

          BreakPoint();

        else

        {

          int found;

          // Should get rid of bcount and loop over the items.

          for (found=0;found<bcount;found++)

          {

            tn=(BrowserItem*)branch->child(found);

            if ((BOND*)tn->Tag==sbc)

              break;

          }

          if (found==bcount)

            tn=new BrowserItem(branch, sbc,(ELEMENT*)sbc->Object,"scope");

          else

            LogTreeAspects((BrowserItem*)tn,flags,(ELEMENT*)sbc->Object);

        }

        sbc=sbc->POYC[1];

        if (sbc==ent->TSLPIO[1].get_First())

          sbc=nullptr;

      }

      sbc=ent->TSLPIO[0].get_First();

      while (sbc)

      {

        int found;

        // Should get rid of bcount and loop over the items.

        for (found=0;found<bcount;found++)

        {

          tn=(BrowserItem*)branch->child(found);

          if ((BOND*)tn->Tag==sbc)

            break;

        }

        ELEMENT*instance=(ELEMENT*)((char*)sbc-(char*)&(*((ELEMENT*)0)).TSLPIO[0]);

        if (found==bcount)

          tn=new BrowserItem(branch,sbc,instance,"instance");

        else

          LogTreeAspects((BrowserItem*)tn,flags,instance);

        sbc=sbc->POYC[1];

        if (sbc==ent->TSLPIO[0].get_First())

          sbc=nullptr;

      }

    }

    // Should get rid of bcount and loop over the items.

    for (int i=0;i<bcount;)

    {

      BrowserItem*tn=(BrowserItem*)branch->child(i);

      BOND*child=(BOND*)tn->Tag;

      bool do_remove=false;

      if (branch->isExpanded())

        if (child->POYC[0]!=(BOND*)branch->Tag)

          if (child->Object==ent)

            do_remove=false;

          else

          {

            do_remove=true;

            ELEMENT*obj=(ELEMENT*)branch->Tag->Object;

            if (obj&&obj->IsSelector())

            {

              if (obj->GetParent()==ent)

                do_remove=false;

              else

                if (child->POYC[0]&&obj->GetEndpoint()==child->POYC[0]->Object)

                  do_remove=false;

            }

          }

        else

          do_remove=false;

      else

        do_remove=true;

      if (do_remove&&child->POYC[0]==&ent->TSLPIO[0])

        do_remove=false;

      if (do_remove&&child->POYC[0])

      {

        BrowserItem*parent=(BrowserItem*)tn->parent();

        if (child->POYC[0]->Object==parent->Tag->Object)

          do_remove=false;

        if (child->POYC[0]->Object==(ELEMENT*)((char*)parent->Tag-(char*)&(*((ELEMENT*)0)).TSLPIO[0]))

          do_remove=false;

      }

      if (do_remove)

      {

        delete tn;

        bcount--;

      }

      else

        i++;

    }

  }

  if (!flags)

  {

  #define EXPAND_SELECTORS 1

  #if EXPAND_SELECTORS

    if (ent->IsSelector())

    {

      if (sb==&ent->TSLPIO[1])

        LogForest(branch,ent->GetEndpoint(),0);

      if (sb==&ent->TSLPIO[5])

        LogAspect(branch,&ent->TSLPIO[1],1,ent);

    }

  #endif

  }

}

void Browser::LogAspect (BrowserItem* branch, BOND* sbent, int flags, ELEMENT* ent)

{

  if (!ent)

    return;

  int found;

  BrowserItem*tn;

  for (found=0;found<branch->childCount();found++)

  {

    tn=(BrowserItem*)branch->child(found);

    if (tn->Tag==sbent)

      break;

  }

  if (found==branch->childCount())

  {

    if (!branch->isExpanded())

    {

      if (branch->childCount()==0)

      {

        branch->SetButton();

        return;

      }

    }

    else

    {

      int ecount=ent->TSLPIO[1].Count();

      if (found<ecount)

      {

        BrowserItem*pn=new BrowserItem(branch,sbent,ent,"scope");

        LogTreeAspects(pn,flags,ent);

      }

    }

  }

}

 

void Browser::onEdit()

{

  BrowserItem* item=(BrowserItem*)currentItem();

  if (!item)

    return;

  Edit(item->Tag);

}

void Browser::onExpanded(const QModelIndex& index)

{

  BrowserItem* item=(BrowserItem*)index.internalPointer();

  if (!item->Tag->Object)

    return;

  ((ELEMENT*)item->Tag->Object)->Expand(item->Tag,true);

  return;

}

void Browser::onCollapsed(const QModelIndex& index)

{

  BrowserItem* item=(BrowserItem*)index.internalPointer();

  //TRACE((ETraceFlags::NORMAL,0,"Collapsing %s.\r\n",item->Tag->Object->Name));

  while (item->childCount())

  {

    GTreeItem* ch=item->child(0);

    delete ch;

  }

  item->SetButton();

  if (item->Tag->Object)

    ((ELEMENT*)item->Tag->Object)->Expand(item->Tag,false);

}

void Browser::onItemDoubleClicked(const QModelIndex& index)

{

  BrowserItem* item=(BrowserItem*)index.internalPointer();

  Edit(item->Tag);

}

void Browser::onRefreshTimer()

{

  static int semaphore=false;

  if (semaphore)

    return;

  semaphore=true;

  RefreshTree(nullptr,0);

  semaphore=false;

}

 

extern int qInitResources_dock();

int GUI_WinMain(void* hInstance, void* hPrevInstance, char* szCmdLine, int iCmdShow);

 

void CreateApplication(int argc, char**argv,void**app)

{

 #ifdef USE_QT

      qInitResources_dock();

 #endif

  *app=new OurApplication(argc,argv);

}

void RunApplication(void*application)

{

  ((OurApplication*)application)->exec();

}

void CloseApplication(void*application)

{

  delete ((OurApplication*)application);

}

void AppCreateWindow(void* app,ELEMENT*cat,ELEMENT*node)

{

      GControl*br;

 #ifdef USE_QT

      emit ((OurApplication*)app)->sig_CreateWidget(nullptr,cat,node,(GControl**)&br);

 #else

  ((OurApplication*)app)->CreateWidget(nullptr,cat,node,&br);

 #endif

}