Graphics: fix handle.tag / gca() / clf() crash
[scilab.git] / scilab / modules / graphic_objects / src / cpp / ScilabView.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2011-2011 - DIGITEO - Bruno JOFRET
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 #include <algorithm>
17 #include <iostream>
18 #include <map>
19 #include <list>
20 #include <cstring>
21 #include <limits.h>
22
23 #include "internal.hxx"
24 #include "ScilabView.hxx"
25 #include "CallGraphicController.hxx"
26 #include "returnProperty.h"
27
28 extern "C"
29 {
30 #include "CurrentObject.h"
31 #include "createGraphicObject.h"
32 #include "setGraphicObjectProperty.h"
33 #include "getGraphicObjectProperty.h"
34 #include "graphicObjectProperties.h"
35 #include "getScilabJavaVM.h"
36 #include "deleteGraphicObject.h"
37 #include "sci_malloc.h"
38 }
39
40 /**
41  * C Wrapping functions
42  * \{
43  */
44 void ScilabNativeView__createObject(int iUID)
45 {
46     ScilabView::createObject(iUID);
47 }
48
49 void ScilabNativeView__deleteObject(int iUID)
50 {
51     ScilabView::deleteObject(iUID);
52 }
53
54 void ScilabNativeView__updateObject(int iUID, int iProperty)
55 {
56     ScilabView::updateObject(iUID, iProperty);
57 }
58
59 void ScilabNativeView__setCurrentFigure(int iUID)
60 {
61     ScilabView::setCurrentFigure(iUID);
62 }
63
64 void ScilabNativeView__setCurrentSubWin(int iUID)
65 {
66     ScilabView::setCurrentSubWin(iUID);
67 }
68
69 void ScilabNativeView__setCurrentObject(int iUID)
70 {
71     ScilabView::setCurrentObject(iUID);
72 }
73
74 int ScilabNativeView__getValidDefaultFigureId()
75 {
76     return ScilabView::getValidDefaultFigureId();
77 }
78
79 int ScilabNativeView__getFigureFromIndex(int figNum)
80 {
81     return ScilabView::getFigureFromIndex(figNum);
82 }
83
84 /**
85  * \}
86  */
87
88 int ScilabView::getValidDefaultFigureId()
89 {
90     if (m_figureList.empty())
91     {
92         return 0;
93     }
94     else
95     {
96         int max = INT_MIN;
97         for (__figureList_iterator it = m_figureList.begin(); it != m_figureList.end(); ++it)
98         {
99             if (it->second > max)
100             {
101                 max = it->second;
102             }
103         }
104
105         return max + 1;
106     }
107 }
108
109 bool ScilabView::isEmptyFigureList()
110 {
111     return m_figureList.empty();
112 }
113
114 int ScilabView::getFigureFromIndex(int figNum)
115 {
116     __figureList_iterator it;
117
118     for (it = m_figureList.begin(); it != m_figureList.end(); ++it)
119     {
120         if (it->second == figNum)
121         {
122             return it->first;
123         }
124     }
125     return 0;
126 }
127
128 bool ScilabView::existsFigureId(int id)
129 {
130     __figureList_iterator it;
131
132     for (it = m_figureList.begin(); it != m_figureList.end(); ++it)
133     {
134         if (it->second == id)
135         {
136             return true;
137         }
138     }
139     return false;
140 }
141
142 void ScilabView::getFiguresId(int ids[])
143 {
144     //__figureList_iterator it;
145     //int i = (int)(m_figureList.size() - 1);
146
147     //for (it = m_figureList.begin(); it != m_figureList.end(); ++it, --i)
148     //{
149     //    //std::cerr << "[ScilabView] DEBUG " << it->first << " <-> " << it->second << std::endl;
150     //    ids[i] = it->second;
151     //}
152
153     __figureList_reverse_iterator it;
154     int i = (int)(m_figureList.size() - 1);
155
156     for (it = m_figureList.rbegin(); it != m_figureList.rend(); ++it, --i)
157     {
158         //std::cerr << "[ScilabView] DEBUG " << it->first << " <-> " << it->second << std::endl;
159         ids[i] = it->second;
160     }
161 }
162
163 int ScilabView::getNbFigure(void)
164 {
165     return (int)m_figureList.size();
166 }
167
168 void ScilabView::createObject(int iUID)
169 {
170     //std::cerr << "[ScilabView] ++ createObject UID=" << iUID << std::endl;
171     int iType = -1;
172     int *piType = &iType;
173
174     getGraphicObjectProperty(iUID, __GO_TYPE__, jni_int, (void **)&piType);
175     if (iType != -1 && iType == __GO_FIGURE__)
176     {
177         m_figureList[iUID] = -1;
178         setCurrentFigure(iUID);
179     }
180
181     // Register object handle.
182     getObjectHandle(iUID);
183
184     PathItem* item = new PathItem();
185     item->uid = iUID;
186
187     m_pathList[iUID] = item;
188
189     m_userdata[iUID]; //create an empty vector<int>
190
191     //get existing information from current object
192     updateObject(iUID, __GO_PARENT__);
193     updateObject(iUID, __GO_CHILDREN__);
194     updateObject(iUID, __GO_TAG__);
195 }
196
197 void ScilabView::deleteObject(int iUID)
198 {
199     //std::cerr << "[ScilabView] -- deleteObject UID=" << iUID << std::endl;
200     int iType = -1;
201     int *piType = &iType;
202     int iParentUID = 0;
203
204     /* get USEr_DATA property and free it*/
205     int iUserDataSize = 0;
206     int *piUserDataSize = &iUserDataSize;
207     int *piUserData = NULL;
208     getGraphicObjectProperty(iUID, __GO_USER_DATA_SIZE__, jni_int, (void **)&piUserDataSize);
209     getGraphicObjectProperty(iUID, __GO_USER_DATA__, jni_int_vector, (void **)&piUserData);
210
211     if (piUserData && piUserDataSize)
212     {
213         types::InternalType* pUD = (types::InternalType*)sciReturnUserData(piUserData, iUserDataSize);
214         pUD->DecreaseRef();
215         pUD->killMe();
216     }
217     /*
218     ** If deleting a figure, remove from figure list.
219     */
220     m_figureList.erase(iUID);
221
222     /*
223     ** If deleting current figure find another current one,
224     ** if there is no more figure : NULL
225     */
226     if (m_currentFigure == iUID) // Deleting current figure
227     {
228         int iAxesUID = 0;
229         int* piAxesUID = &iAxesUID;
230
231         if (getNbFigure() != 0)
232         {
233             m_currentFigure = m_figureList.begin()->first;
234             getGraphicObjectProperty(m_currentFigure, __GO_SELECTED_CHILD__, jni_int,  (void**)&piAxesUID);
235             setCurrentSubWin(iAxesUID);
236         }
237         else
238         {
239             setCurrentFigure(0);
240             setCurrentSubWin(0);
241         }
242     }
243
244     /*
245     ** If deleting current entity, set parent as new current.
246     */
247     if (m_currentObject == iUID) // Deleting current object
248     {
249         iParentUID = getParentObject(iUID);
250         setCurrentObject(iParentUID);
251     }
252
253     // Remove the corresponding handle.
254     __handleList_iterator it = m_handleList.find(iUID);
255     if (it != m_handleList.end())
256     {
257         m_uidList.erase(it->second);
258         m_handleList.erase(it);
259     }
260
261     deleteDataObject(iUID);
262
263     /*clear userdata object*/
264     m_userdata.erase(iUID);
265
266     //clear path object
267     __pathList_iterator itPath = m_pathList.find(iUID);
268     if (itPath != m_pathList.end())
269     {
270         delete itPath->second; //destroy PathItem object
271         m_pathList.erase(itPath); //remove entry
272     }
273 }
274
275 void ScilabView::updateObject(int iUID, int iProperty)
276 {
277     //std::cerr << "[ScilabView] == updateObject UID=" << iUID << " PROPERTY=" << pstProperty << std::endl;
278
279     /*
280     ** Take care of update if the value update is ID and object type is a Figure I manage.
281     */
282     switch (iProperty)
283     {
284         case __GO_ID__ :
285         {
286             if (m_figureList.find(iUID) != m_figureList.end())
287             {
288                 int iNewId = 0;
289                 int *piNewId = &iNewId;
290
291                 getGraphicObjectProperty(iUID, __GO_ID__, jni_int, (void **)&piNewId);
292
293                 m_figureList[iUID] = iNewId;
294                 //std::cerr << "### [ScilabView] updateMap UID=" << iUID << " id=" << iNewId << std::endl;
295             }
296             break;
297         }
298         case __GO_CHILDREN__ :
299         {
300             int childrenCount = 0;
301             int* pChildrenCount = &childrenCount;
302             getGraphicObjectProperty(iUID, __GO_CHILDREN_COUNT__, jni_int, (void**)&pChildrenCount);
303
304             __pathList_iterator it = m_pathList.find(iUID);
305             if (it != m_pathList.end())
306             {
307                 //update existing item
308
309                 PathItem* item = (*it).second;
310                 //reset children
311                 item->children.clear();
312                 if (childrenCount != 0)
313                 {
314                     int* children = NULL;
315                     getGraphicObjectProperty(iUID, __GO_CHILDREN__, jni_int_vector, (void**)&children);
316                     item->children.assign(children, children + childrenCount);
317                     releaseGraphicObjectProperty(__GO_CHILDREN__, children, jni_int_vector, childrenCount);
318                 }
319             }
320             break;
321         }
322         case __GO_PARENT__ :
323         {
324             int iParent = 0;
325             int* piParent = &iParent;
326             getGraphicObjectProperty(iUID, __GO_PARENT__, jni_int, (void**)&piParent);
327
328             __pathList_iterator it = m_pathList.find(iUID);
329
330             if (it != m_pathList.end())
331             {
332                 //update existing item
333
334                 PathItem* item = (*it).second;
335                 item->parent = iParent;
336             }
337             break;
338         }
339         case __GO_TAG__ :
340         {
341             int iType = 0;
342             int* piType = &iType;
343             getGraphicObjectProperty(iUID, __GO_TYPE__, jni_int, (void**)&piType);
344
345             char* tag = NULL;
346             getGraphicObjectProperty(iUID, __GO_TAG__, jni_string, (void**)&tag);
347
348             if (tag[0] != 0 && iType == __GO_FIGURE__)
349             {
350                 //not empty string
351
352                 //add figure in list of path starter
353                 m_pathFigList[tag] = iUID;
354             }
355
356             __pathList_iterator it = m_pathList.find(iUID);
357
358             if (it != m_pathList.end())
359             {
360                 //update existing item
361
362                 PathItem* item = (*it).second;
363                 item->tag = tag;
364                 delete[] tag;
365             }
366             break;
367         }
368         default:
369             break;
370     }
371 }
372
373 /*
374 ** Register ScilabView to Controller.
375 ** Must be done after Graphics models are created.
376 */
377 void ScilabView::registerToController(void)
378 {
379     org_scilab_modules_graphic_objects::CallGraphicController::registerScilabView(getScilabJavaVM());
380 }
381
382 /*
383 ** Reove ScilabView from Controller.
384 */
385 void ScilabView::unregisterToController(void)
386 {
387     org_scilab_modules_graphic_objects::CallGraphicController::unregisterScilabView(getScilabJavaVM());
388 }
389
390 /*
391 ** Set Current Figure UID
392 */
393 void ScilabView::setCurrentFigure(int UID)
394 {
395     m_currentFigure = UID;
396 }
397
398 /*
399 ** Get Current Figure UID
400 */
401 int ScilabView::getCurrentFigure()
402 {
403     //std::cerr << "[ScilaView] currentFigure = " << (m_currentFigure == 0 ? "NULL !!" : m_currentFigure) << std::endl;
404     return m_currentFigure;
405 }
406
407 /*
408 ** Set Current Object UID
409 */
410 void ScilabView::setCurrentObject(int UID)
411 {
412     m_currentObject = UID;
413 }
414
415 /*
416 ** Get Current Figure UID
417 */
418 int ScilabView::getCurrentObject()
419 {
420     //std::cerr << "[ScilaView] currentObject = " << m_currentObject << std::endl;
421     return m_currentObject;
422 }
423
424 /*
425 ** Set Current SubWin UID
426 */
427 void ScilabView::setCurrentSubWin(int UID)
428 {
429     m_currentSubWin = UID;
430 }
431
432 /*
433 ** Get Current Figure UID
434 */
435 int ScilabView::getCurrentSubWin()
436 {
437     //std::cerr << "[ScilaView] currentSubWin = " << m_currentSubWin << std::endl;
438     return m_currentSubWin;
439 }
440
441 /*
442 ** Scilab only can store long as handle
443 */
444 long ScilabView::getObjectHandle(int UID)
445 {
446     /*
447      * if (UID != NULL)
448      * {
449      * std::cerr << "UID = " << UID << std::endl;
450      * }
451      * else
452      * {
453      * std::cerr << "UID is null :-S" << std::endl;
454      * }
455      * __handleList_iterator it2;
456      * std::cerr << "[DEBUG] +++ handleMap +++" << std::endl;
457      * for (it2 = m_handleList.begin() ; it2 != m_handleList.end() ; ++it2)
458      * {
459      * std::cerr << "UID " << it2->first << " <-> handle " << it2->second << std::endl;
460      * }
461      * std::cerr << "[DEBUG] +++ handleMap +++" << std::endl;
462      */
463     __handleList_iterator it = m_handleList.find(UID);
464
465     if (it != m_handleList.end())
466     {
467         return it->second;
468     }
469
470     // increase maximum value
471     // register new handle and return it.
472     m_topHandleValue++;
473     m_handleList[UID] = m_topHandleValue;
474     m_uidList[m_topHandleValue] = UID;
475
476     return m_topHandleValue;
477 }
478
479 int ScilabView::getObjectFromHandle(long handle)
480 {
481     __uidList_iterator it = m_uidList.find(handle);
482     if (it == m_uidList.end())
483     {
484         return 0;
485     }
486
487     return it->second;
488 }
489
490 int ScilabView::getFigureModel(void)
491 {
492     //std::cerr << "[ScilabView] getFigureModel = " << (m_figureModel == 0 ? "!! NULL !!" : m_figureModel) << std::endl;
493     return m_figureModel;
494 }
495
496 void ScilabView::setFigureModel(int UID)
497 {
498     m_figureModel = UID;
499 }
500
501 int ScilabView::getAxesModel(void)
502 {
503     //std::cerr << "[ScilabView] getAxesModel = " << (m_axesModel == 0 ? "!! NULL !!" : m_axesModel) << std::endl;
504     return m_axesModel;
505 }
506
507 void ScilabView::setAxesModel(int UID)
508 {
509     m_axesModel = UID;
510 }
511
512 PathItem* ScilabView::getItem(int uid)
513 {
514     __pathList_iterator it = m_pathList.find(uid);
515     if (it != m_pathList.end())
516     {
517         return it->second;
518     }
519
520     return NULL;
521 }
522
523 PathItem* ScilabView::getItem(std::string _pstTag)
524 {
525     std::list<int> ignored;
526     return getItem(_pstTag, ignored);
527 }
528
529 PathItem* ScilabView::getItem(std::string _pstTag, std::list<int>& _ignoredList)
530 {
531     __pathList_iterator it = m_pathList.begin();
532     for (; it != m_pathList.end(); it++)
533     {
534         PathItem * item = it->second;
535         if (item->tag == _pstTag)
536         {
537             if (std::find(_ignoredList.begin(), _ignoredList.end(), item->uid) == _ignoredList.end())
538             {
539                 return item;
540             }
541         }
542     }
543     return NULL;
544 }
545
546 PathItem* ScilabView::getFigureItem(std::string _pstTag)
547 {
548
549     __pathFigList_iterator it = m_pathFigList.find(_pstTag);
550     if (it != m_pathFigList.end())
551     {
552         return getItem(it->second);
553     }
554
555     return NULL;
556 }
557
558 int ScilabView::search_path(char* _pstPath)
559 {
560     //copy string to protect it against strtok
561     char* pstPath = strdup(_pstPath);
562     std::list<int> ignoredList;
563     PathItem* path = NULL;
564     char* pstSubPath = strtok(pstPath, "/");
565     bool bDeep = false;
566     while (pstSubPath != NULL)
567     {
568         if (pstSubPath[0] == 0)
569         {
570             //"" ?
571             break;
572         }
573
574         if (pstSubPath[0] != '*')
575         {
576             //search in direct children
577             if (path == NULL)
578             {
579                 path = ScilabView::getFigureItem(pstSubPath);
580                 if (path == NULL)
581                 {
582                     path = ScilabView::getItem(pstSubPath, ignoredList);
583                     if (path == NULL)
584                     {
585                         break;
586                     }
587                 }
588
589                 //if figure is in ignore list, reeturn not found
590                 if (std::find(ignoredList.begin(), ignoredList.end(), path->uid) != ignoredList.end())
591                 {
592                     return 0;
593                 }
594             }
595             else
596             {
597                 PathItem* newPath = search_children(path, pstSubPath, bDeep, ignoredList);
598                 if (newPath == NULL)
599                 {
600                     //flag handle to ignore and restart parsing
601                     ignoredList.push_back(path->uid);
602                     pstPath = strdup(_pstPath);
603                     pstSubPath = strtok(pstPath, "/");
604                     path = NULL;
605                     continue;
606                 }
607                 else
608                 {
609                     path = newPath;
610                 }
611
612                 bDeep = false;
613             }
614         }
615         else
616         {
617             //search in all path children
618             bDeep = true;
619         }
620
621         pstSubPath = strtok(NULL, "/");
622     }
623
624     if (path == NULL)
625     {
626         return 0;
627     }
628
629     free(pstPath);
630     return path->uid;
631 }
632
633 PathItem* ScilabView::search_children(PathItem* _path, std::string _subPath, bool _bDeep, std::list<int>& _ignoredList)
634 {
635     PathItem::__child_iterator it = _path->children.begin();
636     for (; it != _path->children.end() ; it++)
637     {
638         PathItem* child = ScilabView::getItem(*it);
639         if (child->tag == _subPath)
640         {
641             bool ignored = false;
642             //check if this handle is not in ignoredList
643             if (std::find(_ignoredList.begin(), _ignoredList.end(), child->uid) == _ignoredList.end())
644             {
645                 return child;
646             }
647         }
648         else if (_bDeep)
649         {
650             PathItem *item = search_children(child, _subPath, _bDeep, _ignoredList);
651             if (item)
652             {
653                 return item;
654             }
655         }
656     }
657
658     return NULL;
659 }
660
661 std::string ScilabView::get_path(int uid)
662 {
663     PathItem* item = getItem(uid);
664     if (item->tag == "")
665     {
666         //impossible to create a useful path from object without tag
667         return "";
668     }
669
670     std::string path = item->tag;
671
672     while (item->parent != 0)
673     {
674         item = getItem(item->parent);
675         if (item->tag == "")
676         {
677             if (path[0] == '*')
678             {
679                 //we have already */ just continue
680                 continue;
681             }
682             else
683             {
684                 //add */ instead of /
685                 path = "*/" + path;
686             }
687         }
688         else
689         {
690             path = item->tag + "/" + path;
691         }
692     }
693
694     if (path[0] == '*')
695     {
696         //path must start by mane
697         return "";
698     }
699
700     return path;
701 }
702
703 void ScilabView::setUserdata(int _id, int* _data, int _datasize)
704 {
705     m_userdata[_id] = std::vector<int>(_data, _data + _datasize);
706 }
707
708 int ScilabView::getUserdataSize(int _id)
709 {
710     return (int)m_userdata[_id].size();
711 }
712
713 int* ScilabView::getUserdata(int _id)
714 {
715     std::vector<int> &vect = m_userdata[_id];
716     int size = (int)vect.size();
717
718     if (size != 0)
719     {
720         return &(vect[0]);
721     }
722
723     //empty userdata must be == NULL
724     return NULL;
725 }
726
727 /*
728 ** Allocate static class variable.
729 */
730 ScilabView::__figureList ScilabView::m_figureList;
731 ScilabView::__handleList ScilabView::m_handleList;
732 ScilabView::__uidList ScilabView::m_uidList;
733 long ScilabView::m_topHandleValue = 0;
734 int ScilabView::m_currentFigure;
735 int ScilabView::m_currentObject;
736 int ScilabView::m_currentSubWin;
737 int ScilabView::m_figureModel;
738 int ScilabView::m_axesModel;
739 ScilabView::__pathList ScilabView::m_pathList;
740 ScilabView::__pathFigList ScilabView::m_pathFigList;
741 ScilabView::__userdata ScilabView::m_userdata;