You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ovdCApplication.cpp 134KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923
  1. #include "ovd_base.h"
  2. #include <boost/filesystem.hpp>
  3. #include <system/ovCTime.h>
  4. #include <system/ovCMemory.h>
  5. #include <vector>
  6. #include <set>
  7. #include <map>
  8. #include <string>
  9. #include <iostream>
  10. #include <sstream>
  11. #include <cstring>
  12. #include <cstdlib>
  13. #include <algorithm>
  14. #include <numeric>
  15. #if defined TARGET_OS_Windows
  16. #include "system/WindowsUtilities.h"
  17. #include "Windows.h"
  18. #endif
  19. #include <communication/ovCMessagingProtocol.h>
  20. #include <visualization-toolkit/ovviz_defines.h>
  21. #include <visualization-toolkit/ovvizIVisualizationContext.h>
  22. #include <ovp_global_defines.h>
  23. #include <fs/Files.h>
  24. #include <json/json.h>
  25. #if defined TARGET_OS_Linux || defined TARGET_OS_MacOS
  26. #include <strings.h>
  27. #define _strcmpi strcasecmp
  28. #endif
  29. #define OVD_GUI_File OpenViBE::Directories::getDataDir() + "/applications/designer/interface.ui"
  30. #define OVD_GUI_AboutDialog_File OpenViBE::Directories::getDataDir() + "/applications/designer/about-dialog.ui"
  31. #define OVD_GUI_Settings_File OpenViBE::Directories::getDataDir() + "/applications/designer/interface-settings.ui"
  32. #define OVD_AttributeId_ScenarioFilename OpenViBE::CIdentifier(0x4C536D0A, 0xB23DC545)
  33. #define OVD_README_File OpenViBE::Directories::getDistRootDir() + "/ReadMe.txt"
  34. #define OVD_SCENARIOS_PATH "${Path_Data}/scenarios"
  35. #define OVD_WORKING_SCENARIOS_PATH "${Designer_DefaultWorkingDirectory}/scenarios"
  36. static const size_t s_RecentFileNumber = 10;
  37. #include "ovdCDesignerVisualization.h"
  38. #include "ovdCPlayerVisualization.h"
  39. #include "ovdCInterfacedObject.h"
  40. #include "ovdCInterfacedScenario.h"
  41. #include "ovdCApplication.h"
  42. #include "ovdAssert.h"
  43. #include "ovdCLogListenerDesigner.h"
  44. #include "visualization/ovdCVisualizationManager.h"
  45. #define OV_ClassId_Selected OpenViBE::CIdentifier(0xC67A01DC, 0x28CE06C1)
  46. // because std::tolower has multiple signatures, it can not be easily used in std::transform this workaround is taken from http://www.gcek.net/ref/books/sw/cpp/ticppv2/
  47. template <class TChar>
  48. static TChar to_lower(TChar c) { return tolower(c); }
  49. namespace OpenViBE {
  50. namespace Designer {
  51. namespace {
  52. struct SBoxProto final : Kernel::IBoxProto
  53. {
  54. explicit SBoxProto(Kernel::ITypeManager& typeManager) : typeManager(typeManager) { }
  55. bool addInput(const CString& /*name*/, const CIdentifier& typeID, const CIdentifier& id, const bool /*notify*/) override
  56. {
  57. uint64_t v = typeID.id();
  58. swap_byte(v, nInputHash);
  59. swap_byte(nInputHash, 0x7936A0F3BD12D936LL);
  60. hash = hash.id() ^ v;
  61. if (id != CIdentifier::undefined())
  62. {
  63. v = id.id();
  64. swap_byte(v, 0x2BD1D158F340014D);
  65. hash = hash.id() ^ v;
  66. }
  67. return true;
  68. }
  69. //
  70. bool addOutput(const CString& /*name*/, const CIdentifier& typeID, const CIdentifier& id, const bool /*notify*/) override
  71. {
  72. uint64_t v = typeID.id();
  73. swap_byte(v, nOutputHash);
  74. swap_byte(nOutputHash, 0xCBB66A5B893AA4E9LL);
  75. hash = hash.id() ^ v;
  76. if (id != CIdentifier::undefined())
  77. {
  78. v = id.id();
  79. swap_byte(v, 0x87CA0F5EFC4FAC68);
  80. hash = hash.id() ^ v;
  81. }
  82. return true;
  83. }
  84. bool addSetting(const CString& /*name*/, const CIdentifier& typeID, const CString& /*defaultValue*/, const bool /*modifiable*/, const CIdentifier& id,
  85. const bool /*notify*/) override
  86. {
  87. uint64_t v = typeID.id();
  88. swap_byte(v, nSettingHash);
  89. swap_byte(nSettingHash, 0x3C87F3AAE9F8303BLL);
  90. hash = hash.id() ^ v;
  91. if (id != CIdentifier::undefined())
  92. {
  93. v = id.id();
  94. swap_byte(v, 0x17185F7CDA63A9FA);
  95. hash = hash.id() ^ v;
  96. }
  97. return true;
  98. }
  99. bool addInputSupport(const CIdentifier& /*typeID*/) override { return true; }
  100. bool addOutputSupport(const CIdentifier& /*typeID*/) override { return true; }
  101. bool addFlag(const Kernel::EBoxFlag flag) override
  102. {
  103. switch (flag)
  104. {
  105. case Kernel::BoxFlag_CanAddInput: hash = hash.id() ^ CIdentifier(0x07507AC8, 0xEB643ACE).id();
  106. break;
  107. case Kernel::BoxFlag_CanModifyInput: hash = hash.id() ^ CIdentifier(0x5C985376, 0x8D74CDB8).id();
  108. break;
  109. case Kernel::BoxFlag_CanAddOutput: hash = hash.id() ^ CIdentifier(0x58DEA69B, 0x12411365).id();
  110. break;
  111. case Kernel::BoxFlag_CanModifyOutput: hash = hash.id() ^ CIdentifier(0x6E162C01, 0xAC979F22).id();
  112. break;
  113. case Kernel::BoxFlag_CanAddSetting: hash = hash.id() ^ CIdentifier(0xFA7A50DC, 0x2140C013).id();
  114. break;
  115. case Kernel::BoxFlag_CanModifySetting: hash = hash.id() ^ CIdentifier(0x624D7661, 0xD8DDEA0A).id();
  116. break;
  117. case Kernel::BoxFlag_IsDeprecated: isDeprecated = true;
  118. break;
  119. default: return false;
  120. }
  121. return true;
  122. }
  123. bool addFlag(const CIdentifier& flag) override
  124. {
  125. const uint64_t value = typeManager.getEnumerationEntryValueFromName(OV_TypeId_BoxAlgorithmFlag, flag.toString());
  126. return value != CIdentifier::undefined().id();
  127. }
  128. void swap_byte(uint64_t& v, const uint64_t s)
  129. {
  130. uint8_t V[sizeof(v)];
  131. uint8_t S[sizeof(s)];
  132. System::Memory::hostToLittleEndian(v, V);
  133. System::Memory::hostToLittleEndian(s, S);
  134. for (size_t i = 0; i < sizeof(s); i += 2)
  135. {
  136. const size_t j = S[i] % sizeof(v);
  137. const size_t k = S[i + 1] % sizeof(v);
  138. const uint8_t t = V[j];
  139. V[j] = V[k];
  140. V[k] = t;
  141. }
  142. System::Memory::littleEndianToHost(V, &v);
  143. }
  144. _IsDerivedFromClass_Final_(IBoxProto, CIdentifier::undefined())
  145. CIdentifier hash;
  146. bool isDeprecated = false;
  147. uint64_t nInputHash = 0x64AC3CB54A35888CLL;
  148. uint64_t nOutputHash = 0x21E0FAAFE5CAF1E1LL;
  149. uint64_t nSettingHash = 0x6BDFB15B54B09F63LL;
  150. Kernel::ITypeManager& typeManager;
  151. };
  152. extern "C" G_MODULE_EXPORT void open_url_mensia_cb(GtkWidget* /*widget*/, gpointer /*data*/)
  153. {
  154. #if defined(TARGET_OS_Windows) && defined(MENSIA_DISTRIBUTION)
  155. system("start http://mensiatech.com");
  156. #endif
  157. }
  158. } // namespace
  159. static guint idle_add_cb(GSourceFunc callback, gpointer data, gint /*priority*/ = G_PRIORITY_DEFAULT_IDLE)
  160. {
  161. GSource* src = g_idle_source_new();
  162. g_source_set_priority(src, G_PRIORITY_LOW);
  163. g_source_set_callback(src, callback, data, nullptr);
  164. return g_source_attach(src, nullptr);
  165. }
  166. static guint timeout_add_cb(const guint interval, GSourceFunc callback, gpointer data, gint /*iPriority*/ = G_PRIORITY_DEFAULT)
  167. {
  168. GSource* src = g_timeout_source_new(interval);
  169. g_source_set_priority(src, G_PRIORITY_LOW);
  170. g_source_set_callback(src, callback, data, nullptr);
  171. return g_source_attach(src, nullptr);
  172. }
  173. static void drag_data_get_cb(GtkWidget* widget, GdkDragContext* dc, GtkSelectionData* selectionData, const guint info, const guint time, const gpointer data)
  174. {
  175. static_cast<CApplication*>(data)->dragDataGetCB(widget, dc, selectionData, info, time);
  176. }
  177. static void menu_undo_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->undoCB(); }
  178. static void menu_redo_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->redoCB(); }
  179. static void menu_focus_search_cb(GtkMenuItem* /*item*/, gpointer data)
  180. {
  181. gtk_widget_grab_focus(GTK_WIDGET(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-box_algorithm_searchbox")));
  182. }
  183. static void menu_copy_selection_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->copySelectionCB(); }
  184. static void menu_cut_selection_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->cutSelectionCB(); }
  185. static void menu_paste_selection_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->pasteSelectionCB(); }
  186. static void menu_delete_selection_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->deleteSelectionCB(); }
  187. static void menu_preferences_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->preferencesCB(); }
  188. static void menu_new_scenario_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->newScenarioCB(); }
  189. static void menu_open_scenario_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->openScenarioCB(); }
  190. static void menu_open_recent_scenario_cb(GtkMenuItem* item, gpointer data)
  191. {
  192. const gchar* fileName = gtk_menu_item_get_label(item);
  193. static_cast<CApplication*>(data)->openScenario(fileName);
  194. }
  195. static void menu_save_scenario_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->saveScenarioCB(); }
  196. static void menu_save_scenario_as_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->saveScenarioAsCB(); }
  197. static void menu_restore_default_scenarios_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->restoreDefaultScenariosCB(); }
  198. static void menu_close_scenario_cb(GtkMenuItem* /*item*/, gpointer data)
  199. {
  200. static_cast<CApplication*>(data)->closeScenarioCB(static_cast<CApplication*>(data)->getCurrentInterfacedScenario());
  201. }
  202. static void menu_quit_application_cb(GtkMenuItem* /*item*/, gpointer data) { if (static_cast<CApplication*>(data)->quitApplicationCB()) { gtk_main_quit(); } }
  203. static void menu_about_scenario_cb(GtkMenuItem* /*item*/, gpointer data)
  204. {
  205. static_cast<CApplication*>(data)->aboutScenarioCB(static_cast<CApplication*>(data)->getCurrentInterfacedScenario());
  206. }
  207. static void menu_about_openvibe_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->aboutOpenViBECB(); }
  208. #if defined(TARGET_OS_Windows)
  209. static void menu_about_link_clicked_cb(GtkAboutDialog* /*dialog*/, const gchar* linkPtr, gpointer data)
  210. {
  211. static_cast<CApplication*>(data)->aboutLinkClickedCB(linkPtr);
  212. }
  213. #endif
  214. static void menu_browse_documentation_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->browseDocumentationCB(); }
  215. #ifdef MENSIA_DISTRIBUTION
  216. static void menu_register_license_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->registerLicenseCB(); }
  217. #endif
  218. static void menu_report_issue_cb(GtkMenuItem* /*item*/, gpointer data) { static_cast<CApplication*>(data)->reportIssueCB(); }
  219. static void menu_display_changelog_cb(GtkMenuItem* /*item*/, gpointer data)
  220. {
  221. if (!static_cast<CApplication*>(data)->displayChangelogWhenAvailable())
  222. {
  223. const std::string version = static_cast<CApplication*>(data)->m_kernelCtx.getConfigurationManager().expand("${Application_Version}").toASCIIString();
  224. GtkWidget* dialog = gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
  225. "No boxes were added or updated in version %s of " DESIGNER_NAME ".",
  226. version != "${Application_Version}" ? version.c_str() : ProjectVersion);
  227. gtk_window_set_title(GTK_WINDOW(dialog), "No new boxes");
  228. gtk_dialog_run(GTK_DIALOG(dialog));
  229. gtk_widget_destroy(dialog);
  230. }
  231. }
  232. static void button_new_scenario_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->newScenarioCB(); }
  233. static void button_open_scenario_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->openScenarioCB(); }
  234. static void button_save_scenario_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->saveScenarioCB(); }
  235. static void button_save_scenario_as_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->saveScenarioAsCB(); }
  236. static void button_close_scenario_cb(GtkButton* /*button*/, gpointer data)
  237. {
  238. static_cast<CApplication*>(data)->closeScenarioCB(static_cast<CApplication*>(data)->getCurrentInterfacedScenario());
  239. }
  240. static void button_undo_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->undoCB(); }
  241. static void button_redo_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->redoCB(); }
  242. #ifdef MENSIA_DISTRIBUTION
  243. static void button_toggle_neurort_engine_configuration_cb(GtkMenuItem* item, gpointer data)
  244. {
  245. static_cast<CApplication*>(data)->m_ArchwayHandlerGUI->toggleNeuroRTEngineConfigurationDialog(
  246. bool(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(item)) == TRUE));
  247. }
  248. #endif
  249. static void delete_designer_visualisation_cb(gpointer data) { static_cast<CApplication*>(data)->deleteDesignerVisualizationCB(); }
  250. static void button_toggle_window_manager_cb(GtkToggleToolButton* /*button*/, gpointer data)
  251. {
  252. static_cast<CApplication*>(data)->toggleDesignerVisualizationCB();
  253. }
  254. static void button_comment_cb(GtkButton* /*button*/, CApplication* app) { app->addCommentCB(app->getCurrentInterfacedScenario()); }
  255. static void button_about_scenario_cb(GtkButton* /*button*/, gpointer data)
  256. {
  257. static_cast<CApplication*>(data)->aboutScenarioCB(static_cast<CApplication*>(data)->getCurrentInterfacedScenario());
  258. }
  259. static void stop_scenario_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->stopScenarioCB(); }
  260. static void play_pause_scenario_cb(GtkButton* button, gpointer data)
  261. {
  262. if (std::string(gtk_tool_button_get_stock_id(GTK_TOOL_BUTTON(button))) == GTK_STOCK_MEDIA_PLAY) { static_cast<CApplication*>(data)->playScenarioCB(); }
  263. else { static_cast<CApplication*>(data)->pauseScenarioCB(); }
  264. }
  265. static void next_scenario_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->nextScenarioCB(); }
  266. static void forward_scenario_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->forwardScenarioCB(); }
  267. static void button_configure_current_scenario_settings_cb(GtkButton* /*button*/, CApplication* app)
  268. {
  269. app->configureScenarioSettingsCB(app->getCurrentInterfacedScenario());
  270. }
  271. static gboolean button_quit_application_cb(GtkWidget* /*widget*/, GdkEvent* /*pEvent*/, gpointer data)
  272. {
  273. if (static_cast<CApplication*>(data)->quitApplicationCB())
  274. {
  275. gtk_main_quit();
  276. return FALSE;
  277. }
  278. return TRUE;
  279. }
  280. static gboolean window_state_changed_cb(GtkWidget* /*widget*/, GdkEventWindowState* event, gpointer data)
  281. {
  282. if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
  283. {
  284. // window has changed from maximized to not maximized or the other way around
  285. static_cast<CApplication*>(data)->windowStateChangedCB((event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0);
  286. }
  287. return TRUE;
  288. }
  289. static void log_level_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->logLevelCB(); }
  290. static void cpu_usage_cb(GtkToggleButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->cpuUsageCB(); }
  291. static gboolean change_current_scenario_cb(GtkNotebook* /*notebook*/, GtkNotebookPage* /*notebookPage*/, const guint pageNumber, gpointer data)
  292. {
  293. static_cast<CApplication*>(data)->changeCurrentScenario(int(pageNumber));
  294. return TRUE;
  295. }
  296. static gboolean reorder_scenario_cb(GtkNotebook* /*notebook*/, GtkNotebookPage* /*notebookPage*/, const guint pageNumber, gpointer data)
  297. {
  298. static_cast<CApplication*>(data)->reorderCurrentScenario(int(pageNumber));
  299. return TRUE;
  300. }
  301. static void box_algorithm_title_button_expand_cb(GtkButton* /*button*/, gpointer data)
  302. {
  303. gtk_tree_view_expand_all(GTK_TREE_VIEW(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-box_algorithm_tree")));
  304. gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-resource_notebook")), 0);
  305. }
  306. static void box_algorithm_title_button_collapse_cb(GtkButton* /*button*/, gpointer data)
  307. {
  308. gtk_tree_view_collapse_all(GTK_TREE_VIEW(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-box_algorithm_tree")));
  309. gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-resource_notebook")), 0);
  310. }
  311. static void algorithm_title_button_expand_cb(GtkButton* /*button*/, gpointer data)
  312. {
  313. gtk_tree_view_expand_all(GTK_TREE_VIEW(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-algorithm_tree")));
  314. gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-resource_notebook")), 1);
  315. }
  316. static void algorithm_title_button_collapse_cb(GtkButton* /*button*/, gpointer data)
  317. {
  318. gtk_tree_view_collapse_all(GTK_TREE_VIEW(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-algorithm_tree")));
  319. gtk_notebook_set_current_page(GTK_NOTEBOOK(gtk_builder_get_object(static_cast<CApplication*>(data)->m_Builder, "openvibe-resource_notebook")), 1);
  320. }
  321. static void clear_messages_cb(GtkButton* /*button*/, gpointer data) { static_cast<CLogListenerDesigner*>(data)->clearMessages(); }
  322. static void add_scenario_input_cb(GtkButton* /*button*/, CApplication* app) { app->getCurrentInterfacedScenario()->addScenarioInputCB(); }
  323. static void add_scenario_output_cb(GtkButton* /*button*/, CApplication* app) { app->getCurrentInterfacedScenario()->addScenarioOutputCB(); }
  324. static void add_scenario_setting_cb(GtkButton* /*button*/, CApplication* app) { app->getCurrentInterfacedScenario()->addScenarioSettingCB(); }
  325. static std::string strtoupper(std::string str)
  326. {
  327. std::transform(str.begin(), str.end(), str.begin(), std::ptr_fun<int, int>(std::toupper));
  328. return str;
  329. }
  330. static gboolean box_algorithm_search_func(GtkTreeModel* model, GtkTreeIter* iter, gpointer data)
  331. {
  332. auto* app = static_cast<CApplication*>(data);
  333. /* Visible if row is non-empty and first column is "HI" */
  334. gboolean visible = false;
  335. gchar* name;
  336. gchar* desc;
  337. gboolean unstable;
  338. gtk_tree_model_get(model, iter, Resource_StringName, &name, Resource_StringShortDescription, &desc, Resource_BooleanIsUnstable, &unstable, -1);
  339. // consider only leaf nodes which match the search term
  340. if (name != nullptr && desc != nullptr)
  341. {
  342. if (!unstable && (std::string::npos != strtoupper(name).find(strtoupper(app->m_SearchTerm))
  343. || std::string::npos != strtoupper(desc).find(strtoupper(app->m_SearchTerm)) || gtk_tree_model_iter_has_child(model, iter)))
  344. {
  345. //std::cout << "value : " << app->m_searchTerm << "\n";
  346. visible = true;
  347. }
  348. g_free(name);
  349. g_free(desc);
  350. }
  351. else { visible = true; }
  352. return visible;
  353. }
  354. static gboolean box_algorithm_prune_empty_folders(GtkTreeModel* model, GtkTreeIter* iter, gpointer /*data*/)
  355. {
  356. gboolean isPlugin;
  357. gtk_tree_model_get(model, iter, Resource_BooleanIsPlugin, &isPlugin, -1);
  358. if (gtk_tree_model_iter_has_child(model, iter) || isPlugin) { return true; }
  359. return false;
  360. }
  361. static gboolean do_refilter(CApplication* app)
  362. {
  363. //if (0 == strcmp(app->m_searchTerm, "")) { gtk_tree_view_set_model(pApplication->m_pBoxAlgorithmTreeView, GTK_TREE_MODEL(app->m_BoxAlgorithmTreeModel)); } // reattach the old model
  364. //else {
  365. app->m_BoxAlgorithmTreeModelFilter = gtk_tree_model_filter_new(GTK_TREE_MODEL(app->m_BoxAlgorithmTreeModel), nullptr);
  366. app->m_BoxAlgorithmTreeModelFilter2 = gtk_tree_model_filter_new(GTK_TREE_MODEL(app->m_BoxAlgorithmTreeModelFilter), nullptr);
  367. app->m_BoxAlgorithmTreeModelFilter3 = gtk_tree_model_filter_new(GTK_TREE_MODEL(app->m_BoxAlgorithmTreeModelFilter2), nullptr);
  368. app->m_BoxAlgorithmTreeModelFilter4 = gtk_tree_model_filter_new(GTK_TREE_MODEL(app->m_BoxAlgorithmTreeModelFilter3), nullptr);
  369. // detach the normal model from the treeview
  370. gtk_tree_view_set_model(app->m_BoxAlgorithmTreeView, nullptr);
  371. // clear the model
  372. // add a filtering function to the model
  373. gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(app->m_BoxAlgorithmTreeModelFilter), box_algorithm_search_func, app, nullptr);
  374. gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(app->m_BoxAlgorithmTreeModelFilter2), box_algorithm_prune_empty_folders, app, nullptr);
  375. gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(app->m_BoxAlgorithmTreeModelFilter3), box_algorithm_prune_empty_folders, app, nullptr);
  376. gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(app->m_BoxAlgorithmTreeModelFilter4), box_algorithm_prune_empty_folders, app, nullptr);
  377. // attach the model to the treeview
  378. gtk_tree_view_set_model(app->m_BoxAlgorithmTreeView, GTK_TREE_MODEL(app->m_BoxAlgorithmTreeModelFilter4));
  379. if (0 == strcmp(app->m_SearchTerm, "")) { gtk_tree_view_collapse_all(app->m_BoxAlgorithmTreeView); }
  380. else { gtk_tree_view_expand_all(app->m_BoxAlgorithmTreeView); }
  381. //}
  382. app->m_FilterTimeout = 0;
  383. return false;
  384. }
  385. static void queue_refilter(CApplication* app)
  386. {
  387. if (app->m_FilterTimeout) { g_source_remove(app->m_FilterTimeout); }
  388. app->m_FilterTimeout = g_timeout_add(300, GSourceFunc(do_refilter), app);
  389. }
  390. static void refresh_search_cb(GtkEntry* textfield, CApplication* app)
  391. {
  392. app->m_SearchTerm = gtk_entry_get_text(textfield);
  393. queue_refilter(app);
  394. }
  395. static void refresh_search_no_data_cb(GtkToggleButton* /*button*/, CApplication* app)
  396. {
  397. app->m_SearchTerm = gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(app->m_Builder, "openvibe-box_algorithm_searchbox")));
  398. queue_refilter(app);
  399. }
  400. static gboolean searchbox_select_all_cb(GtkWidget* widget, GdkEvent* /*event*/, CApplication* /*app*/)
  401. {
  402. // we select the current search
  403. gtk_widget_grab_focus(widget); // we must grab or selection wont work. It also triggers the other CBs.
  404. gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
  405. return false;
  406. }
  407. static gboolean searchbox_focus_in_cb(GtkWidget* /*widget*/, GdkEvent* /*event*/, CApplication* app)
  408. {
  409. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(app->m_Builder, "openvibe-menu_edit")), false);
  410. return false;
  411. }
  412. static gboolean searchbox_focus_out_cb(GtkWidget* widget, GdkEvent* /*event*/, CApplication* app)
  413. {
  414. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(app->m_Builder, "openvibe-menu_edit")), true);
  415. gtk_editable_select_region(GTK_EDITABLE(widget), 0, 0);
  416. return false;
  417. }
  418. #if defined TARGET_OS_Windows
  419. static void about_newversion_button_display_changelog_cb(GtkButton* /*button*/, gpointer /*data*/)
  420. {
  421. System::WindowsUtilities::utf16CompliantShellExecute(nullptr, "open", (OVD_README_File).toASCIIString(), nullptr, nullptr, SHOW_OPENWINDOW);
  422. }
  423. #endif
  424. static gboolean idle_application_loop(gpointer data)
  425. {
  426. auto* app = static_cast<CApplication*>(data);
  427. #ifdef MENSIA_DISTRIBUTION
  428. if (app->m_ArchwayHandler->isEngineStarted()) { app->m_ArchwayHandler->loopEngine(); }
  429. #endif
  430. CInterfacedScenario* scenario = app->getCurrentInterfacedScenario();
  431. if (scenario)
  432. {
  433. if (app->getPlayer() && scenario->m_PlayerStatus != app->getPlayer()->getStatus())
  434. {
  435. switch (app->getPlayer()->getStatus())
  436. {
  437. case Kernel::EPlayerStatus::Stop:
  438. gtk_signal_emit_by_name(GTK_OBJECT(gtk_builder_get_object(app->m_Builder, "openvibe-button_stop")), "clicked");
  439. break;
  440. case Kernel::EPlayerStatus::Pause:
  441. while (scenario->m_PlayerStatus != Kernel::EPlayerStatus::Pause)
  442. {
  443. gtk_signal_emit_by_name(GTK_OBJECT(gtk_builder_get_object(app->m_Builder, "openvibe-button_play_pause")), "clicked");
  444. }
  445. break;
  446. case Kernel::EPlayerStatus::Step: break;
  447. case Kernel::EPlayerStatus::Play:
  448. while (scenario->m_PlayerStatus != Kernel::EPlayerStatus::Play)
  449. {
  450. gtk_signal_emit_by_name(GTK_OBJECT(gtk_builder_get_object(app->m_Builder, "openvibe-button_play_pause")), "clicked");
  451. }
  452. break;
  453. case Kernel::EPlayerStatus::Forward:
  454. gtk_signal_emit_by_name(GTK_OBJECT(gtk_builder_get_object(app->m_Builder, "openvibe-button_forward")), "clicked");
  455. break;
  456. default:
  457. std::cout << "unhandled player status : " << toString(app->getPlayer()->getStatus()) << " :(\n";
  458. break;
  459. }
  460. }
  461. else
  462. {
  463. const double time = (scenario->m_Player ? CTime(scenario->m_Player->getCurrentSimulatedTime()).toSeconds() : 0.0);
  464. if (app->m_LastTimeRefresh != time)
  465. {
  466. app->m_LastTimeRefresh = uint64_t(time);
  467. const size_t milli = (size_t(time * 1000) % 1000);
  468. const size_t seconds = (size_t(time)) % 60;
  469. const size_t minutes = (size_t(time) / 60) % 60;
  470. const size_t hours = (size_t(time) / 60) / 60;
  471. const double cpuUsage = (scenario->m_Player ? scenario->m_Player->getCPUUsage() : 0);
  472. std::stringstream ss("Time : ");
  473. ss.fill('0');
  474. if (hours)
  475. {
  476. ss << std::setw(2) << hours << "h " << std::setw(2) << minutes << "m " << std::setw(2) << seconds << "s " << std::setw(3) << milli << "ms";
  477. }
  478. else if (minutes) { ss << std::setw(2) << minutes << "m " << std::setw(2) << seconds << "s " << std::setw(3) << milli << "ms"; }
  479. else if (seconds) { ss << std::setw(2) << seconds << "s " << std::setw(3) << milli << "ms"; }
  480. else { ss << std::setw(3) << milli << "ms"; }
  481. gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(app->m_Builder, "openvibe-label_current_time")), ss.str().c_str());
  482. ss.str("");
  483. ss.fill('0');
  484. ss.precision(1);
  485. ss << std::fixed << cpuUsage << "%";
  486. gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtk_builder_get_object(app->m_Builder, "openvibe-progressbar_cpu_usage")), cpuUsage * .01);
  487. gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gtk_builder_get_object(app->m_Builder, "openvibe-progressbar_cpu_usage")), ss.str().c_str());
  488. if (scenario->m_Player && scenario->m_DebugCPUUsage)
  489. {
  490. // redraws scenario
  491. scenario->redraw();
  492. }
  493. }
  494. }
  495. }
  496. else
  497. {
  498. gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(app->m_Builder, "openvibe-label_current_time")), "Time : 000ms");
  499. gtk_progress_bar_set_text(GTK_PROGRESS_BAR(gtk_builder_get_object(app->m_Builder, "openvibe-progressbar_cpu_usage")), "");
  500. gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(gtk_builder_get_object(app->m_Builder, "openvibe-progressbar_cpu_usage")), 0);
  501. }
  502. if (!app->hasRunningScenario()) { System::Time::sleep(50); }
  503. return TRUE;
  504. }
  505. static gboolean idle_scenario_loop(gpointer data)
  506. {
  507. auto* scenario = static_cast<CInterfacedScenario*>(data);
  508. const uint64_t time = System::Time::zgetTime();
  509. if (scenario->m_LastLoopTime == uint64_t(-1)) { scenario->m_LastLoopTime = time; }
  510. scenario->m_Player->setFastForwardMaximumFactor(gtk_spin_button_get_value(scenario->m_Application.m_FastForwardFactor));
  511. if (!scenario->m_Player->loop(time - scenario->m_LastLoopTime)) { scenario->m_Application.stopInterfacedScenarioAndReleasePlayer(scenario); }
  512. scenario->m_LastLoopTime = time;
  513. return TRUE;
  514. }
  515. static gboolean timeout_application_loop(gpointer data)
  516. {
  517. auto* app = static_cast<CApplication*>(data);
  518. if (!app->hasRunningScenario() && app->m_CmdLineFlags & CommandLineFlag_NoGui)
  519. {
  520. app->quitApplicationCB();
  521. gtk_main_quit();
  522. return FALSE;
  523. }
  524. return TRUE;
  525. }
  526. #ifdef NDEBUG
  527. /**
  528. * Function called in gtk loop: to check each 0.1second if a message was sent by a second instance of Designer
  529. * (Meaning that someone tried to reopen Designer and this instance has to do something)
  530. **/
  531. static gboolean receiveSecondInstanceMessage(gpointer data)
  532. {
  533. try
  534. { // Open or create ensures that
  535. boost::interprocess::named_mutex mutex(boost::interprocess::open_or_create, MUTEX_NAME);
  536. {
  537. boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(mutex);
  538. CApplication* app = static_cast<CApplication*>(data);
  539. //Tries to open a message, if fails, go to catch
  540. boost::interprocess::message_queue message(boost::interprocess::open_only, MESSAGE_NAME);
  541. app->m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "ovdCApplication::receiveSecondInstanceMessage- A message was detected \n";
  542. // Whatever contains the message the first instance should try to take the focus
  543. gtk_window_present(GTK_WINDOW(app->m_MainWindow));
  544. size_t size;
  545. uint32_t priority = 0;
  546. char buffer[2048];
  547. if (message.try_receive(&buffer, sizeof(buffer), size, priority))
  548. {
  549. boost::interprocess::message_queue::remove(MESSAGE_NAME);
  550. int mode = 0;
  551. char path[2048];
  552. char* msg = strtok(buffer, ";");
  553. while (msg != nullptr)
  554. {
  555. sscanf(msg, "%1d : <%2048[^>]> ", &mode, &path);
  556. switch (mode)
  557. {
  558. case CommandLineFlag_Open:
  559. app->openScenario(path);
  560. break;
  561. case CommandLineFlag_Play:
  562. if (app->openScenario(path)) { app->playScenarioCB(); }
  563. break;
  564. case CommandLineFlag_PlayFast:
  565. if (app->openScenario(path)) { app->forwardScenarioCB(); }
  566. break;
  567. default: break;
  568. }
  569. mode = 0;
  570. msg = strtok(nullptr, ";");
  571. }
  572. }
  573. else { boost::interprocess::message_queue::remove(MESSAGE_NAME); }
  574. }
  575. }
  576. // An interprocess_exception is throwed if no messages could be found, in this case we do nothing
  577. catch (boost::interprocess::interprocess_exception) {}
  578. return TRUE;
  579. }
  580. #endif
  581. static void zoom_in_scenario_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->zoomInCB(); }
  582. static void zoom_out_scenario_cb(GtkButton* /*button*/, gpointer data) { static_cast<CApplication*>(data)->zoomOutCB(); }
  583. static void spinner_zoom_changed_cb(GtkSpinButton* button, gpointer data)
  584. {
  585. static_cast<CApplication*>(data)->spinnerZoomChangedCB(size_t(gtk_spin_button_get_value(button)));
  586. }
  587. static const GtkTargetEntry TARGET_ENTRY[] = { { static_cast<gchar*>("STRING"), 0, 0 }, { static_cast<gchar*>("text/plain"), 0, 0 } };
  588. CApplication::CApplication(const Kernel::IKernelContext& ctx) : m_kernelCtx(ctx)
  589. {
  590. m_PluginMgr = &m_kernelCtx.getPluginManager();
  591. m_ScenarioMgr = &m_kernelCtx.getScenarioManager();
  592. m_ScenarioMgr->registerScenarioImporter(OVD_ScenarioImportContext_OpenScenario, ".xml", OVP_GD_ClassId_Algorithm_XMLScenarioImporter);
  593. m_ScenarioMgr->registerScenarioImporter(OVD_ScenarioImportContext_OpenScenario, ".mxs", OVP_GD_ClassId_Algorithm_XMLScenarioImporter);
  594. m_ScenarioMgr->registerScenarioImporter(OVD_ScenarioImportContext_OpenScenario, ".mxb", OVP_GD_ClassId_Algorithm_XMLScenarioImporter);
  595. m_ScenarioMgr->registerScenarioExporter(OVD_ScenarioExportContext_SaveScenario, ".xml", OVP_GD_ClassId_Algorithm_XMLScenarioExporter);
  596. m_ScenarioMgr->registerScenarioExporter(OVD_ScenarioExportContext_SaveScenario, ".mxs", OVP_GD_ClassId_Algorithm_XMLScenarioExporter);
  597. m_ScenarioMgr->registerScenarioExporter(OVD_ScenarioExportContext_SaveMetabox, ".xml", OVP_GD_ClassId_Algorithm_XMLScenarioExporter);
  598. m_ScenarioMgr->registerScenarioExporter(OVD_ScenarioExportContext_SaveMetabox, ".mxb", OVP_GD_ClassId_Algorithm_XMLScenarioExporter);
  599. m_VisualizationMgr = new CVisualizationManager(m_kernelCtx);
  600. m_visualizationCtx = dynamic_cast<VisualizationToolkit::IVisualizationContext*>(
  601. m_kernelCtx.getPluginManager().createPluginObject(OVP_ClassId_Plugin_VisualizationCtx));
  602. m_visualizationCtx->setManager(m_VisualizationMgr);
  603. m_logListener = nullptr;
  604. m_kernelCtx.getConfigurationManager().createConfigurationToken("Player_ScenarioDirectory", "");
  605. m_kernelCtx.getConfigurationManager().createConfigurationToken("__volatile_ScenarioDir", "");
  606. #ifdef MENSIA_DISTRIBUTION
  607. m_ArchwayHandler = new CArchwayHandler(ctx);
  608. m_ArchwayHandlerGUI = new CArchwayHandlerGUI(*m_ArchwayHandler, this);
  609. #endif
  610. }
  611. CApplication::~CApplication()
  612. {
  613. if (m_Builder)
  614. {
  615. m_kernelCtx.getLogManager().removeListener(m_logListener);
  616. // @FIXME this likely still does not deallocate the actual widgets allocated by add_from_file
  617. g_object_unref(G_OBJECT(m_Builder));
  618. m_Builder = nullptr;
  619. }
  620. m_kernelCtx.getPluginManager().releasePluginObject(m_visualizationCtx);
  621. #ifdef MENSIA_DISTRIBUTION
  622. delete m_ArchwayHandlerGUI;
  623. delete m_ArchwayHandler;
  624. #endif
  625. }
  626. void CApplication::initialize(const ECommandLineFlag cmdLineFlags)
  627. {
  628. m_CmdLineFlags = cmdLineFlags;
  629. m_SearchTerm = "";
  630. // Load metaboxes from metabox path
  631. m_kernelCtx.getMetaboxManager().addMetaboxesFromFiles(m_kernelCtx.getConfigurationManager().expand("${Kernel_Metabox}"));
  632. // Copy recursively default scenario directory to the default working directory if not exists
  633. const CString defaultWorkingDirectory = m_kernelCtx.getConfigurationManager().expand(OVD_WORKING_SCENARIOS_PATH);
  634. const CString defaultScenariosDirectory = m_kernelCtx.getConfigurationManager().expand(OVD_SCENARIOS_PATH);
  635. if (!FS::Files::directoryExists(defaultWorkingDirectory) && FS::Files::directoryExists(defaultScenariosDirectory))
  636. {
  637. if (!FS::Files::copyDirectory(defaultScenariosDirectory, defaultWorkingDirectory))
  638. {
  639. m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "Could not create " << defaultWorkingDirectory << " folder\n";
  640. }
  641. }
  642. // Prepares scenario clipboard
  643. CIdentifier clipboardScenarioID;
  644. if (m_ScenarioMgr->createScenario(clipboardScenarioID)) { m_ClipboardScenario = &m_ScenarioMgr->getScenario(clipboardScenarioID); }
  645. m_Builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "openvibe", nullptr);
  646. gtk_builder_add_from_file(m_Builder, OVD_GUI_File, nullptr);
  647. gtk_builder_connect_signals(m_Builder, nullptr);
  648. std::string version = m_kernelCtx.getConfigurationManager().expand("${Application_Version}").toASCIIString();
  649. if (version == "${Application_Version}")
  650. {
  651. version = m_kernelCtx.getConfigurationManager().expand("${ProjectVersion_Major}.${ProjectVersion_Minor}.${ProjectVersion_Patch}").toASCIIString();
  652. }
  653. const std::string defaultWindowTitle = BRAND_NAME " " DESIGNER_NAME " " + version;
  654. m_MainWindow = GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe"));
  655. gtk_window_set_title(GTK_WINDOW(m_MainWindow), defaultWindowTitle.c_str());
  656. gtk_menu_item_set_label(
  657. GTK_MENU_ITEM(gtk_builder_get_object(m_Builder, "openvibe-menu_display_changelog")),
  658. ("What's new in " + version + " version of " + BRAND_NAME " " DESIGNER_NAME).c_str());
  659. // Catch delete events when close button is clicked
  660. g_signal_connect(m_MainWindow, "delete_event", G_CALLBACK(button_quit_application_cb), this);
  661. // be notified on maximize/minimize events
  662. g_signal_connect(m_MainWindow, "window-state-event", G_CALLBACK(window_state_changed_cb), this);
  663. // Connects menu actions
  664. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_undo")), "activate", G_CALLBACK(menu_undo_cb), this);
  665. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_redo")), "activate", G_CALLBACK(menu_redo_cb), this);
  666. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_focus_search")), "activate", G_CALLBACK(menu_focus_search_cb), this);
  667. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_copy")), "activate", G_CALLBACK(menu_copy_selection_cb), this);
  668. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_cut")), "activate", G_CALLBACK(menu_cut_selection_cb), this);
  669. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_paste")), "activate", G_CALLBACK(menu_paste_selection_cb), this);
  670. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_delete")), "activate", G_CALLBACK(menu_delete_selection_cb), this);
  671. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_preferences")), "activate", G_CALLBACK(menu_preferences_cb), this);
  672. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_new")), "activate", G_CALLBACK(menu_new_scenario_cb), this);
  673. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_open")), "activate", G_CALLBACK(menu_open_scenario_cb), this);
  674. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_save")), "activate", G_CALLBACK(menu_save_scenario_cb), this);
  675. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_save_as")), "activate", G_CALLBACK(menu_save_scenario_as_cb), this);
  676. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_close")), "activate", G_CALLBACK(menu_close_scenario_cb), this);
  677. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_quit")), "activate", G_CALLBACK(menu_quit_application_cb), this);
  678. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_restore_default_scenarios")), "activate",
  679. G_CALLBACK(menu_restore_default_scenarios_cb), this);
  680. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_about")), "activate", G_CALLBACK(menu_about_openvibe_cb), this);
  681. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_scenario_about")), "activate", G_CALLBACK(menu_about_scenario_cb), this);
  682. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_documentation")), "activate", G_CALLBACK(menu_browse_documentation_cb), this);
  683. #ifdef MENSIA_DISTRIBUTION
  684. if (FS::Files::fileExists(Directories::getBinDir() + "/mensia-flexnet-activation.exe"))
  685. {
  686. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_register_license")), "activate", G_CALLBACK(menu_register_license_cb), this);
  687. }
  688. else { gtk_widget_hide(GTK_WIDGET((gtk_builder_get_object(m_Builder, "openvibe-menu_register_license")))); }
  689. #else
  690. gtk_widget_hide(GTK_WIDGET((gtk_builder_get_object(m_Builder, "openvibe-menu_register_license"))));
  691. #endif
  692. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_issue_report")), "activate", G_CALLBACK(menu_report_issue_cb), this);
  693. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-menu_display_changelog")), "activate", G_CALLBACK(menu_display_changelog_cb), this);
  694. // g_signal_connect(G_OBJECT(gtk_builder_get_object(m_builderInterface, "openvibe-menu_test")), "activate", G_CALLBACK(menu_test_cb), this);
  695. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_new")), "clicked", G_CALLBACK(button_new_scenario_cb), this);
  696. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_open")), "clicked", G_CALLBACK(button_open_scenario_cb), this);
  697. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_save")), "clicked", G_CALLBACK(button_save_scenario_cb), this);
  698. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_save_as")), "clicked", G_CALLBACK(button_save_scenario_as_cb), this);
  699. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_close")), "clicked", G_CALLBACK(button_close_scenario_cb), this);
  700. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_undo")), "clicked", G_CALLBACK(button_undo_cb), this);
  701. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_redo")), "clicked", G_CALLBACK(button_redo_cb), this);
  702. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_log_level")), "clicked", G_CALLBACK(log_level_cb), this);
  703. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), "toggled", G_CALLBACK(button_toggle_window_manager_cb),
  704. this);
  705. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_comment")), "clicked", G_CALLBACK(button_comment_cb), this);
  706. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_aboutscenario")), "clicked", G_CALLBACK(button_about_scenario_cb), this);
  707. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), "clicked", G_CALLBACK(stop_scenario_cb), this);
  708. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), "clicked", G_CALLBACK(play_pause_scenario_cb), this);
  709. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_next")), "clicked", G_CALLBACK(next_scenario_cb), this);
  710. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), "clicked", G_CALLBACK(forward_scenario_cb), this);
  711. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_title_button_expand")), "clicked",
  712. G_CALLBACK(box_algorithm_title_button_expand_cb), this);
  713. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_title_button_collapse")), "clicked",
  714. G_CALLBACK(box_algorithm_title_button_collapse_cb), this);
  715. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-algorithm_title_button_expand")), "clicked",
  716. G_CALLBACK(algorithm_title_button_expand_cb), this);
  717. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-algorithm_title_button_collapse")), "clicked",
  718. G_CALLBACK(algorithm_title_button_collapse_cb), this);
  719. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_searchbox")), "icon-press", G_CALLBACK(searchbox_select_all_cb), this);
  720. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_searchbox")), "changed", G_CALLBACK(refresh_search_cb), this);
  721. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_searchbox")), "focus-in-event", G_CALLBACK(searchbox_focus_in_cb),
  722. this);
  723. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_searchbox")), "focus-out-event", G_CALLBACK(searchbox_focus_out_cb),
  724. this);
  725. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-scenario_configuration_button_configure")), "clicked",
  726. G_CALLBACK(button_configure_current_scenario_settings_cb), this);
  727. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_zoomin")), "clicked", G_CALLBACK(zoom_in_scenario_cb), this);
  728. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-button_zoomout")), "clicked", G_CALLBACK(zoom_out_scenario_cb), this);
  729. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-zoom_spinner")), "value-changed", G_CALLBACK(spinner_zoom_changed_cb), this);
  730. #ifdef MENSIA_DISTRIBUTION
  731. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "neurort-toggle_engine_configuration")), "clicked",
  732. G_CALLBACK(button_toggle_neurort_engine_configuration_cb), this);
  733. m_ArchwayHandlerGUI->m_ButtonOpenEngineConfigurationDialog = GTK_WIDGET(gtk_builder_get_object(m_Builder, "neurort-toggle_engine_configuration"));
  734. #endif
  735. // Prepares fast forward feature
  736. const double fastForwardFactor = m_kernelCtx.getConfigurationManager().expandAsFloat("${Designer_FastForwardFactor}", -1);
  737. m_FastForwardFactor = GTK_SPIN_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-spinbutton_fast-forward-factor"));
  738. if (fastForwardFactor == -1) { gtk_spin_button_set_value(m_FastForwardFactor, 100); }
  739. else { gtk_spin_button_set_value(m_FastForwardFactor, fastForwardFactor); }
  740. #if defined(TARGET_OS_Windows)
  741. #if GTK_CHECK_VERSION(2, 24, 0)
  742. // expect it to work */
  743. #else
  744. gtk_about_dialog_set_url_hook((GtkAboutDialogActivateLinkFunc)menu_about_link_clicked_cb, this, nullptr);
  745. #endif
  746. #endif
  747. idle_add_cb(idle_application_loop, this);
  748. timeout_add_cb(1000, timeout_application_loop, this);
  749. #ifdef NDEBUG
  750. timeout_add_cb(100, receiveSecondInstanceMessage, this);
  751. #endif
  752. // Prepares main notebooks
  753. m_scenarioNotebook = GTK_NOTEBOOK(gtk_builder_get_object(m_Builder, "openvibe-scenario_notebook"));
  754. // optional behavior: vertically stacked scenarios (filename trimming mandatory in that case).
  755. if (m_kernelCtx.getConfigurationManager().expandAsBoolean("${Designer_ScenarioTabsVerticalStack}", false))
  756. {
  757. gtk_notebook_set_tab_pos(m_scenarioNotebook, GTK_POS_LEFT);
  758. }
  759. g_signal_connect(G_OBJECT(m_scenarioNotebook), "switch-page", G_CALLBACK(change_current_scenario_cb), this);
  760. g_signal_connect(G_OBJECT(m_scenarioNotebook), "page-reordered", G_CALLBACK(reorder_scenario_cb), this);
  761. m_resourceNotebook = GTK_NOTEBOOK(gtk_builder_get_object(m_Builder, "openvibe-resource_notebook"));
  762. // Creates an empty scnenario
  763. gtk_notebook_remove_page(m_scenarioNotebook, 0);
  764. // Initialize menu open recent
  765. m_menuOpenRecent = GTK_CONTAINER(gtk_builder_get_object(m_Builder, "openvibe-menu_recent_content"));
  766. //newScenarioCB();
  767. {
  768. // Prepares box algorithm view
  769. m_BoxAlgorithmTreeView = GTK_TREE_VIEW(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_tree"));
  770. GtkTreeViewColumn* treeViewColumnName = gtk_tree_view_column_new();
  771. GtkTreeViewColumn* treeViewColumnDesc = gtk_tree_view_column_new();
  772. GtkCellRenderer* cellRendererIcon = gtk_cell_renderer_pixbuf_new();
  773. GtkCellRenderer* cellRendererName = gtk_cell_renderer_text_new();
  774. GtkCellRenderer* cellRendererDesc = gtk_cell_renderer_text_new();
  775. gtk_tree_view_column_set_title(treeViewColumnName, "Name");
  776. gtk_tree_view_column_set_title(treeViewColumnDesc, "Description");
  777. gtk_tree_view_column_pack_start(treeViewColumnName, cellRendererIcon, FALSE);
  778. gtk_tree_view_column_pack_start(treeViewColumnName, cellRendererName, TRUE);
  779. gtk_tree_view_column_pack_start(treeViewColumnDesc, cellRendererDesc, TRUE);
  780. gtk_tree_view_column_set_attributes(treeViewColumnName, cellRendererIcon, "stock-id", Resource_StringStockIcon, nullptr);
  781. gtk_tree_view_column_set_attributes(treeViewColumnName, cellRendererName, "text", Resource_StringName, "foreground", Resource_StringColor, "font",
  782. Resource_StringFont, "background", Resource_BackGroundColor, nullptr);
  783. gtk_tree_view_column_set_attributes(treeViewColumnDesc, cellRendererDesc, "text", Resource_StringShortDescription, "foreground", Resource_StringColor,
  784. "background", Resource_BackGroundColor, nullptr);
  785. gtk_tree_view_column_set_sizing(treeViewColumnName, GTK_TREE_VIEW_COLUMN_FIXED);
  786. gtk_tree_view_column_set_sizing(treeViewColumnDesc, GTK_TREE_VIEW_COLUMN_FIXED);
  787. gtk_tree_view_column_set_expand(treeViewColumnName, FALSE);
  788. gtk_tree_view_column_set_expand(treeViewColumnDesc, FALSE);
  789. gtk_tree_view_column_set_resizable(treeViewColumnName, TRUE);
  790. gtk_tree_view_column_set_resizable(treeViewColumnDesc, TRUE);
  791. gtk_tree_view_column_set_min_width(treeViewColumnName, 64);
  792. gtk_tree_view_column_set_min_width(treeViewColumnDesc, 64);
  793. gtk_tree_view_column_set_fixed_width(treeViewColumnName, 256);
  794. gtk_tree_view_column_set_fixed_width(treeViewColumnDesc, 512);
  795. gtk_tree_view_append_column(m_BoxAlgorithmTreeView, treeViewColumnName);
  796. gtk_tree_view_append_column(m_BoxAlgorithmTreeView, treeViewColumnDesc);
  797. // Prepares box algorithm model
  798. m_BoxAlgorithmTreeModel = gtk_tree_store_new(9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
  799. G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING);
  800. // Tree Storage for the searches
  801. gtk_tree_view_set_model(m_BoxAlgorithmTreeView, GTK_TREE_MODEL(m_BoxAlgorithmTreeModel));
  802. }
  803. {
  804. // Prepares algorithm view
  805. m_algorithmTreeView = GTK_TREE_VIEW(gtk_builder_get_object(m_Builder, "openvibe-algorithm_tree"));
  806. GtkTreeViewColumn* treeViewColumnName = gtk_tree_view_column_new();
  807. GtkTreeViewColumn* treeViewColumnDesc = gtk_tree_view_column_new();
  808. GtkCellRenderer* cellRendererIcon = gtk_cell_renderer_pixbuf_new();
  809. GtkCellRenderer* cellRendererName = gtk_cell_renderer_text_new();
  810. GtkCellRenderer* cellRendererDesc = gtk_cell_renderer_text_new();
  811. gtk_tree_view_column_set_title(treeViewColumnName, "Name");
  812. gtk_tree_view_column_set_title(treeViewColumnDesc, "Description");
  813. gtk_tree_view_column_pack_start(treeViewColumnName, cellRendererIcon, FALSE);
  814. gtk_tree_view_column_pack_start(treeViewColumnName, cellRendererName, TRUE);
  815. gtk_tree_view_column_pack_start(treeViewColumnDesc, cellRendererDesc, TRUE);
  816. gtk_tree_view_column_set_attributes(treeViewColumnName, cellRendererIcon, "stock-id", Resource_StringStockIcon, nullptr);
  817. gtk_tree_view_column_set_attributes(treeViewColumnName, cellRendererName, "text", Resource_StringName, "foreground", Resource_StringColor, nullptr);
  818. gtk_tree_view_column_set_attributes(treeViewColumnDesc, cellRendererDesc, "text", Resource_StringShortDescription, "foreground", Resource_StringColor,
  819. nullptr);
  820. gtk_tree_view_column_set_sizing(treeViewColumnName, GTK_TREE_VIEW_COLUMN_FIXED);
  821. gtk_tree_view_column_set_sizing(treeViewColumnDesc, GTK_TREE_VIEW_COLUMN_FIXED);
  822. gtk_tree_view_column_set_expand(treeViewColumnName, FALSE);
  823. gtk_tree_view_column_set_expand(treeViewColumnDesc, FALSE);
  824. gtk_tree_view_column_set_resizable(treeViewColumnName, TRUE);
  825. gtk_tree_view_column_set_resizable(treeViewColumnDesc, TRUE);
  826. gtk_tree_view_column_set_min_width(treeViewColumnName, 64);
  827. gtk_tree_view_column_set_min_width(treeViewColumnDesc, 64);
  828. gtk_tree_view_column_set_fixed_width(treeViewColumnName, 256);
  829. gtk_tree_view_column_set_fixed_width(treeViewColumnDesc, 512);
  830. gtk_tree_view_append_column(m_algorithmTreeView, treeViewColumnName);
  831. gtk_tree_view_append_column(m_algorithmTreeView, treeViewColumnDesc);
  832. // Prepares algorithm model
  833. m_AlgorithmTreeModel = gtk_tree_store_new(9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN,
  834. G_TYPE_BOOLEAN, G_TYPE_STRING);
  835. gtk_tree_view_set_model(m_algorithmTreeView, GTK_TREE_MODEL(m_AlgorithmTreeModel));
  836. }
  837. m_configureSettingsAddSettingButton = GTK_WIDGET(gtk_builder_get_object(m_Builder, "dialog_scenario_configuration-button_add_setting"));
  838. g_signal_connect(G_OBJECT(m_configureSettingsAddSettingButton), "clicked", G_CALLBACK(add_scenario_setting_cb), this);
  839. // Set up the UI for adding Inputs and Outputs to the scenario
  840. GtkWidget* scenarioLinksVBox = GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-scenario_links_vbox"));
  841. m_Inputs = gtk_table_new(1, 3, FALSE);
  842. m_Outputs = gtk_table_new(1, 3, FALSE);
  843. GtkWidget* scrolledWindowInputs = gtk_scrolled_window_new(nullptr, nullptr);
  844. gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledWindowInputs), GTK_WIDGET(m_Inputs));
  845. gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindowInputs), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
  846. GtkWidget* scrolledWindowOutputs = gtk_scrolled_window_new(nullptr, nullptr);
  847. gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledWindowOutputs), GTK_WIDGET(m_Outputs));
  848. gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindowOutputs), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
  849. GtkWidget* addInputButton = gtk_button_new_with_label("Add Input");
  850. GtkWidget* addOutputButton = gtk_button_new_with_label("Add Output");
  851. g_signal_connect(G_OBJECT(addInputButton), "clicked", G_CALLBACK(add_scenario_input_cb), this);
  852. g_signal_connect(G_OBJECT(addOutputButton), "clicked", G_CALLBACK(add_scenario_output_cb), this);
  853. gtk_box_pack_start(GTK_BOX(scenarioLinksVBox), gtk_label_new("Inputs"), FALSE, FALSE, 4);
  854. gtk_box_pack_start(GTK_BOX(scenarioLinksVBox), scrolledWindowInputs, TRUE, TRUE, 4);
  855. gtk_box_pack_start(GTK_BOX(scenarioLinksVBox), addInputButton, FALSE, FALSE, 4);
  856. gtk_box_pack_start(GTK_BOX(scenarioLinksVBox), gtk_label_new("Outputs"), FALSE, FALSE, 4);
  857. gtk_box_pack_start(GTK_BOX(scenarioLinksVBox), scrolledWindowOutputs, TRUE, TRUE, 4);
  858. gtk_box_pack_start(GTK_BOX(scenarioLinksVBox), addOutputButton, FALSE, FALSE, 4);
  859. gtk_widget_show_all(scenarioLinksVBox);
  860. // Prepares drag& drop for box creation
  861. gtk_drag_source_set(GTK_WIDGET(m_BoxAlgorithmTreeView), GDK_BUTTON1_MASK, TARGET_ENTRY, sizeof(TARGET_ENTRY) / sizeof(GtkTargetEntry), GDK_ACTION_COPY);
  862. g_signal_connect(G_OBJECT(m_BoxAlgorithmTreeView), "drag_data_get", G_CALLBACK(drag_data_get_cb), this);
  863. // Shows main window
  864. gtk_builder_connect_signals(m_Builder, nullptr);
  865. m_isMaximized = false;
  866. const int height = int(m_kernelCtx.getConfigurationManager().expandAsInteger("${Designer_EditorSizeHeight}"));
  867. const int width = int(m_kernelCtx.getConfigurationManager().expandAsInteger("${Designer_EditorSizeWidth}"));
  868. if (height > 0 && width > 0) { gtk_window_resize(GTK_WINDOW(m_MainWindow), width, height); }
  869. if (m_kernelCtx.getConfigurationManager().expandAsBoolean("${Designer_FullscreenEditor}")) { gtk_window_maximize(GTK_WINDOW(m_MainWindow)); }
  870. const int panedPosition = int(m_kernelCtx.getConfigurationManager().expandAsInteger("${Designer_EditorPanedPosition}"));
  871. if (panedPosition > 0) { gtk_paned_set_position(GTK_PANED(gtk_builder_get_object(m_Builder, "openvibe-horizontal_container")), panedPosition); }
  872. GtkNotebook* sidebar = GTK_NOTEBOOK(gtk_builder_get_object(m_Builder, "openvibe-resource_notebook"));
  873. // List the notebook pages, cycle through them in reverse so we can remove pages without modifying indexes
  874. for (int notebookIdx = gtk_notebook_get_n_pages(sidebar) - 1; notebookIdx >= 0; notebookIdx--)
  875. {
  876. GtkWidget* tabWidget = gtk_notebook_get_nth_page(sidebar, notebookIdx);
  877. GtkWidget* tabLabel = gtk_notebook_get_tab_label(sidebar, tabWidget);
  878. if (!m_kernelCtx.getConfigurationManager().expandAsBoolean("${Designer_ShowAlgorithms}"))
  879. {
  880. if (tabLabel == GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-algorithm_title_container")))
  881. {
  882. gtk_notebook_remove_page(sidebar, notebookIdx);
  883. }
  884. }
  885. }
  886. // gtk_window_set_icon_name(GTK_WINDOW(m_MainWindow), "ov-logo");
  887. gtk_window_set_icon_from_file(GTK_WINDOW(m_MainWindow), Directories::getDataDir() + "/applications/designer/designer.ico", nullptr);
  888. gtk_window_set_default_icon_from_file(Directories::getDataDir() + "/applications/designer/designer.ico", nullptr);
  889. if (!(m_CmdLineFlags & CommandLineFlag_NoManageSession))
  890. {
  891. CIdentifier id;
  892. char name[1024];
  893. unsigned i = 0;
  894. do
  895. {
  896. sprintf(name, "Designer_LastScenarioFilename_%03u", ++i);
  897. if ((id = m_kernelCtx.getConfigurationManager().lookUpConfigurationTokenIdentifier(name)) != CIdentifier::undefined())
  898. {
  899. CString filename;
  900. filename = m_kernelCtx.getConfigurationManager().getConfigurationTokenValue(id);
  901. filename = m_kernelCtx.getConfigurationManager().expand(filename);
  902. m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "Restoring scenario [" << filename << "]\n";
  903. if (!this->openScenario(filename.toASCIIString()))
  904. {
  905. m_kernelCtx.getLogManager() << Kernel::LogLevel_ImportantWarning << "Failed to restore scenario [" << filename << "]\n";
  906. }
  907. }
  908. } while (id != CIdentifier::undefined());
  909. }
  910. CIdentifier tokenID;
  911. char str[1024];
  912. unsigned i = 0;
  913. do
  914. {
  915. sprintf(str, "Designer_RecentScenario_%03u", ++i);
  916. if ((tokenID = m_kernelCtx.getConfigurationManager().lookUpConfigurationTokenIdentifier(str)) != CIdentifier::undefined())
  917. {
  918. CString fileName;
  919. fileName = m_kernelCtx.getConfigurationManager().getConfigurationTokenValue(tokenID);
  920. fileName = m_kernelCtx.getConfigurationManager().expand(fileName);
  921. GtkWidget* newRecentItem = gtk_image_menu_item_new_with_label(fileName.toASCIIString());
  922. g_signal_connect(G_OBJECT(newRecentItem), "activate", G_CALLBACK(menu_open_recent_scenario_cb), this);
  923. gtk_menu_shell_append(GTK_MENU_SHELL(m_menuOpenRecent), newRecentItem);
  924. gtk_widget_show(newRecentItem);
  925. m_recentScenarios.push_back(newRecentItem);
  926. }
  927. } while (tokenID != CIdentifier::undefined());
  928. refresh_search_no_data_cb(nullptr, this);
  929. // Add the designer log listener
  930. const CString logLevel = m_kernelCtx.getConfigurationManager().expand("${Kernel_ConsoleLogLevel}");
  931. std::string value(logLevel.toASCIIString());
  932. transform(value.begin(), value.end(), value.begin(), ::to_lower<std::string::value_type>);
  933. Kernel::ELogLevel level = Kernel::LogLevel_Debug;
  934. if (value == "debug") { level = Kernel::LogLevel_Debug; }
  935. if (value == "benchmarking / profiling") { level = Kernel::LogLevel_Benchmark; }
  936. if (value == "trace") { level = Kernel::LogLevel_Trace; }
  937. if (value == "information") { level = Kernel::LogLevel_Info; }
  938. if (value == "warning") { level = Kernel::LogLevel_Warning; }
  939. if (value == "important warning") { level = Kernel::LogLevel_ImportantWarning; }
  940. if (value == "error") { level = Kernel::LogLevel_Error; }
  941. if (value == "fatal error") { level = Kernel::LogLevel_Fatal; }
  942. switch (level)
  943. {
  944. case Kernel::LogLevel_Debug: gtk_toggle_tool_button_set_active(
  945. GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_debug")), true);
  946. case Kernel::LogLevel_Benchmark: gtk_toggle_tool_button_set_active(
  947. GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_bench")), true);
  948. case Kernel::LogLevel_Trace: gtk_toggle_tool_button_set_active(
  949. GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_trace")), true);
  950. case Kernel::LogLevel_Info: gtk_toggle_tool_button_set_active(
  951. GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_info")), true);
  952. case Kernel::LogLevel_Warning: gtk_toggle_tool_button_set_active(
  953. GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_warning")), true);
  954. case Kernel::LogLevel_ImportantWarning: gtk_toggle_tool_button_set_active(
  955. GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_impwarning")), true);
  956. case Kernel::LogLevel_Error: gtk_toggle_tool_button_set_active(
  957. GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_error")), true);
  958. case Kernel::LogLevel_Fatal: gtk_toggle_tool_button_set_active(
  959. GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_fatal")), true);
  960. default: break;
  961. }
  962. gtk_widget_set_sensitive(
  963. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_debug")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Debug));
  964. gtk_widget_set_sensitive(
  965. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_bench")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Benchmark));
  966. gtk_widget_set_sensitive(
  967. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_trace")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Trace));
  968. gtk_widget_set_sensitive(
  969. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_info")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Info));
  970. gtk_widget_set_sensitive(
  971. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_warning")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Warning));
  972. gtk_widget_set_sensitive(
  973. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_impwarning")),
  974. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_ImportantWarning));
  975. gtk_widget_set_sensitive(
  976. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_error")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Error));
  977. gtk_widget_set_sensitive(
  978. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_fatal")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Fatal));
  979. if (!(m_CmdLineFlags & CommandLineFlag_NoGui))
  980. {
  981. m_logListener = new CLogListenerDesigner(m_kernelCtx, m_Builder);
  982. m_logListener->m_CenterOnBoxFun = [this](CIdentifier& id) { this->getCurrentInterfacedScenario()->centerOnBox(id); };
  983. m_kernelCtx.getLogManager().addListener(m_logListener);
  984. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_clear")), "clicked", G_CALLBACK(clear_messages_cb), m_logListener);
  985. gtk_widget_show(m_MainWindow);
  986. }
  987. // If last version of Designer used is anterior or null, then consider it as a new version
  988. const CString lastUsedVersion = m_kernelCtx.getConfigurationManager().expand("${Designer_LastVersionUsed}");
  989. int lastUsedVersionMajor = 0;
  990. int lastUsedVersionMinor = 0;
  991. int lastUsedVersionPatch = 0;
  992. const int currentVersionMajor = int(m_kernelCtx.getConfigurationManager().expandAsInteger("${ProjectVersion_Major}"));
  993. const int currentVersionMinor = int(m_kernelCtx.getConfigurationManager().expandAsInteger("${ProjectVersion_Minor}"));
  994. const int currentVersionPatch = int(m_kernelCtx.getConfigurationManager().expandAsInteger("${ProjectVersion_Patch}"));
  995. sscanf(lastUsedVersion.toASCIIString(), "%d.%d.%d", &lastUsedVersionMajor, &lastUsedVersionMinor, &lastUsedVersionPatch);
  996. if (lastUsedVersionMajor < currentVersionMajor
  997. || (lastUsedVersionMajor == currentVersionMajor && lastUsedVersionMinor < currentVersionMinor)
  998. || (lastUsedVersionMinor == currentVersionMinor && lastUsedVersionPatch < currentVersionPatch)
  999. || (lastUsedVersionMajor == 0 && lastUsedVersionMinor == 0 && lastUsedVersionPatch == 0)) { m_IsNewVersion = true; }
  1000. std::string defaultURLBaseString = std::string(m_kernelCtx.getConfigurationManager().expand("${Designer_HelpBrowserURLBase}"));
  1001. #ifdef MENSIA_DISTRIBUTION
  1002. if (m_ArchwayHandler->initialize() == EEngineInitialisationStatus::NotAvailable)
  1003. {
  1004. gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "neurort-toggle_engine_configuration")));
  1005. }
  1006. #else
  1007. gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(m_Builder, "neurort-toggle_engine_configuration")));
  1008. #endif
  1009. }
  1010. bool CApplication::displayChangelogWhenAvailable()
  1011. {
  1012. // If last version used is ulterior as current version, and at least one box was added/updated, show the list
  1013. if (!m_NewBoxes.empty() || !m_UpdatedBoxes.empty())
  1014. {
  1015. GtkBuilder* builder = gtk_builder_new();
  1016. gtk_builder_add_from_file(builder, OVD_GUI_File, nullptr);
  1017. GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "aboutdialog-newversion"));
  1018. gtk_window_set_title(GTK_WINDOW(dialog), "Changelog");
  1019. std::string version = m_kernelCtx.getConfigurationManager().expand("${Application_Version}").toASCIIString();
  1020. version = (version != "${Application_Version}") ? version
  1021. : m_kernelCtx.getConfigurationManager().expand("${ProjectVersion_Major}.${ProjectVersion_Minor}.${ProjectVersion_Patch}").
  1022. toASCIIString();
  1023. gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), version.c_str());
  1024. std::string labelNewBoxesList = "<big><b>Changes in version " + version + " of the software:</b></big>";
  1025. if (!m_NewBoxes.empty())
  1026. {
  1027. labelNewBoxesList += "\n<big>The following boxes were added:</big>\n";
  1028. for (auto pNewBoxDesc : m_NewBoxes)
  1029. {
  1030. labelNewBoxesList += " <b>" + pNewBoxDesc->getName() + ":</b> " + pNewBoxDesc->getShortDescription() + "\n";
  1031. }
  1032. }
  1033. if (!m_UpdatedBoxes.empty())
  1034. {
  1035. labelNewBoxesList += "\n<big>The following boxes were updated:</big>\n";
  1036. for (auto pUpdatedBoxDesc : m_UpdatedBoxes)
  1037. {
  1038. labelNewBoxesList += " <b>" + pUpdatedBoxDesc->getName() + ":</b> " + pUpdatedBoxDesc->getShortDescription() + "\n";
  1039. }
  1040. }
  1041. #if defined TARGET_OS_Windows // This function makes Windows calls only, hide button on other OSs
  1042. g_signal_connect(G_OBJECT(gtk_builder_get_object(builder, "button-display_changelog")), "clicked",
  1043. G_CALLBACK(about_newversion_button_display_changelog_cb), this);
  1044. #else
  1045. gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "button-display_changelog")));
  1046. #endif
  1047. if (!FS::Files::fileExists((OVD_README_File).toASCIIString()))
  1048. {
  1049. gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "button-display_changelog")));
  1050. }
  1051. GtkLabel* label = GTK_LABEL(gtk_builder_get_object(builder, "label-newversion"));
  1052. gtk_label_set_markup(label, labelNewBoxesList.c_str());
  1053. gtk_dialog_run(GTK_DIALOG(dialog));
  1054. if (m_IsNewVersion)
  1055. {
  1056. gtk_entry_set_text(GTK_ENTRY(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_searchbox")), "(New)");
  1057. gtk_window_set_focus(GTK_WINDOW(m_MainWindow), GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_searchbox")));
  1058. }
  1059. gtk_widget_destroy(dialog);
  1060. g_object_unref(builder);
  1061. }
  1062. else { return false; }
  1063. return true;
  1064. }
  1065. bool CApplication::openScenario(const char* filename)
  1066. {
  1067. // Prevent opening twice the same scenario
  1068. for (size_t i = 0; i < m_Scenarios.size(); ++i)
  1069. {
  1070. const auto scenario = m_Scenarios[i];
  1071. if (scenario->m_Filename == std::string(filename))
  1072. {
  1073. gtk_notebook_set_current_page(m_scenarioNotebook, i);
  1074. return true;
  1075. }
  1076. }
  1077. CIdentifier scenarioID;
  1078. if (m_ScenarioMgr->importScenarioFromFile(scenarioID, OVD_ScenarioImportContext_OpenScenario, filename))
  1079. {
  1080. // Closes first unnamed scenario
  1081. if (m_Scenarios.size() == 1)
  1082. {
  1083. if (!m_Scenarios[0]->m_HasBeenModified && !m_Scenarios[0]->m_HasFileName)
  1084. {
  1085. const CIdentifier tmp = m_Scenarios[0]->m_ScenarioID;
  1086. delete m_Scenarios[0];
  1087. m_ScenarioMgr->releaseScenario(tmp);
  1088. m_Scenarios.clear();
  1089. }
  1090. }
  1091. Kernel::IScenario& scenario = m_ScenarioMgr->getScenario(scenarioID);
  1092. // Creates interfaced scenario
  1093. CInterfacedScenario* interfacedScenario = new CInterfacedScenario(m_kernelCtx, *this, scenario, scenarioID, *m_scenarioNotebook, OVD_GUI_File,
  1094. OVD_GUI_Settings_File);
  1095. // Deserialize the visualization tree from the scenario metadata, if it exists
  1096. // Find the VisualizationTree metadata
  1097. Kernel::IMetadata* vizTreeMetadata = nullptr;
  1098. CIdentifier metadataID = CIdentifier::undefined();
  1099. while ((metadataID = scenario.getNextMetadataIdentifier(metadataID)) != CIdentifier::undefined())
  1100. {
  1101. vizTreeMetadata = scenario.getMetadataDetails(metadataID);
  1102. if (vizTreeMetadata && vizTreeMetadata->getType() == OVVIZ_MetadataIdentifier_VisualizationTree) { break; }
  1103. }
  1104. VisualizationToolkit::IVisualizationTree* vizTree = interfacedScenario->m_Tree;
  1105. if (vizTreeMetadata && vizTree) { vizTree->deserialize(vizTreeMetadata->getData()); }
  1106. CIdentifier id;
  1107. // Ensure visualization widgets contained in the scenario (if any) appear in the window manager
  1108. // even when the VisualizationTree section of a scenario file is missing, erroneous or deprecated
  1109. // no visualization widget was added to visualization tree : ensure there aren't any in scenario
  1110. CIdentifier boxID;
  1111. while ((boxID = scenario.getNextBoxIdentifier(boxID)) != CIdentifier::undefined())
  1112. {
  1113. if (!vizTree->getVisualizationWidgetFromBoxIdentifier(boxID))
  1114. {
  1115. const Kernel::IBox* box = scenario.getBoxDetails(boxID);
  1116. const Plugins::IPluginObjectDesc* boxAlgorithmDesc = m_kernelCtx.getPluginManager().getPluginObjectDescCreating(
  1117. box->getAlgorithmClassIdentifier());
  1118. if (boxAlgorithmDesc && boxAlgorithmDesc->hasFunctionality(Plugins::EPluginFunctionality::Visualization))
  1119. {
  1120. //a visualization widget was found in scenario : manually add it to visualization tree
  1121. vizTree->addVisualizationWidget(id, box->getName(), VisualizationToolkit::EVisualizationWidget::Box,
  1122. CIdentifier::undefined(), 0, box->getIdentifier(), 0, CIdentifier::undefined());
  1123. }
  1124. }
  1125. }
  1126. if (interfacedScenario->m_DesignerVisualization != nullptr)
  1127. {
  1128. interfacedScenario->m_DesignerVisualization->setDeleteEventCB(&delete_designer_visualisation_cb, this);
  1129. interfacedScenario->m_DesignerVisualization->load();
  1130. }
  1131. //interfacedScenario->snapshotCB(); --> a snapshot is already created in CInterfacedScenario builder !
  1132. interfacedScenario->m_Filename = filename;
  1133. interfacedScenario->m_HasFileName = true;
  1134. interfacedScenario->m_HasBeenModified = false;
  1135. interfacedScenario->snapshotCB(false);
  1136. m_Scenarios.push_back(interfacedScenario);
  1137. interfacedScenario->redrawScenarioSettings();
  1138. gtk_notebook_set_current_page(m_scenarioNotebook, gtk_notebook_get_n_pages(m_scenarioNotebook) - 1);
  1139. //this->changeCurrentScenario(gtk_notebook_get_n_pages(m_scenarioNotebook)-1);
  1140. interfacedScenario->updateScenarioLabel();
  1141. this->saveOpenedScenarios();
  1142. return true;
  1143. }
  1144. m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "Importing scenario from file [" << filename << "] failed... "
  1145. << " Current file either is corrupted or is not compatible with the selected scenario importer (ie not an OpenViBE scenario file)\n";
  1146. if (!(m_CmdLineFlags & CommandLineFlag_NoGui))
  1147. {
  1148. std::stringstream ss;
  1149. ss << "The requested file: " << filename << "\n";
  1150. ss << "may either not be an OpenViBE scenario file, \n";
  1151. ss << "a " + std::string(BRAND_NAME) + " scenario file, \n";
  1152. ss << "be corrupted or not compatible with \n";
  1153. ss << "the selected scenario importer...";
  1154. GtkWidget* dialog = gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Scenario importation process failed !");
  1155. gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", ss.str().c_str());
  1156. gtk_dialog_run(GTK_DIALOG(dialog));
  1157. gtk_widget_destroy(dialog);
  1158. }
  1159. return false;
  1160. }
  1161. CString CApplication::getWorkingDirectory()
  1162. {
  1163. CString workingDirectory = m_kernelCtx.getConfigurationManager().expand("${Designer_DefaultWorkingDirectory}/scenarios");
  1164. CInterfacedScenario* scenario = this->getCurrentInterfacedScenario();
  1165. if (scenario)
  1166. {
  1167. if (scenario->m_HasFileName)
  1168. {
  1169. std::string directory = std::string(g_path_get_dirname(scenario->m_Filename.c_str()));
  1170. #if defined TARGET_OS_Windows
  1171. std::replace(directory.begin(), directory.end(), '\\', '/');
  1172. #endif
  1173. workingDirectory = directory.c_str();
  1174. }
  1175. }
  1176. if (!g_path_is_absolute(workingDirectory.toASCIIString()))
  1177. {
  1178. std::string directory = g_get_current_dir();
  1179. #if defined TARGET_OS_Windows
  1180. std::replace(directory.begin(), directory.end(), '\\', '/');
  1181. #endif
  1182. workingDirectory = directory.c_str() + CString("/") + workingDirectory;
  1183. }
  1184. return workingDirectory;
  1185. }
  1186. bool CApplication::hasRunningScenario()
  1187. {
  1188. return std::any_of(m_Scenarios.begin(), m_Scenarios.end(), [](CInterfacedScenario* elem) { return elem->m_Player != nullptr; });
  1189. }
  1190. bool CApplication::hasUnsavedScenario()
  1191. {
  1192. return std::any_of(m_Scenarios.begin(), m_Scenarios.end(), [](CInterfacedScenario* elem) { return elem->m_HasBeenModified; });
  1193. }
  1194. CInterfacedScenario* CApplication::getCurrentInterfacedScenario()
  1195. {
  1196. if (m_currentScenarioIdx < m_Scenarios.size()) { return m_Scenarios[m_currentScenarioIdx]; }
  1197. return nullptr;
  1198. }
  1199. void CApplication::saveOpenedScenarios()
  1200. {
  1201. // Saves opened scenarios
  1202. if (!(m_CmdLineFlags & CommandLineFlag_NoManageSession))
  1203. {
  1204. const CString appConfigFile = m_kernelCtx.getConfigurationManager().expand("${Designer_CustomConfigurationFile}");
  1205. FILE* file = FS::Files::open(appConfigFile.toASCIIString(), "wt");
  1206. if (file)
  1207. {
  1208. size_t i = 1;
  1209. fprintf(file, "# This file is generated\n");
  1210. fprintf(file, "# Do not modify\n");
  1211. fprintf(file, "\n");
  1212. int width, height;
  1213. gtk_window_get_size(GTK_WINDOW(m_MainWindow), &width, &height);
  1214. fprintf(file, "Designer_EditorSizeWidth = %i\n", width);
  1215. fprintf(file, "Designer_EditorSizeHeight = %i\n", height);
  1216. fprintf(file, "Designer_EditorPanedPosition = %i\n",
  1217. gtk_paned_get_position(GTK_PANED(gtk_builder_get_object(m_Builder, "openvibe-horizontal_container"))));
  1218. fprintf(file, "Designer_FullscreenEditor = %s\n", m_isMaximized ? "True" : "False");
  1219. fprintf(file, "# Last files opened in %s\n", std::string(DESIGNER_NAME).c_str());
  1220. for (CInterfacedScenario* scenario : m_Scenarios)
  1221. {
  1222. if (!scenario->m_Filename.empty())
  1223. {
  1224. fprintf(file, "Designer_LastScenarioFilename_%03u = %s\n", i, scenario->m_Filename.c_str());
  1225. i++;
  1226. }
  1227. }
  1228. fprintf(file, "\n");
  1229. const CString projectVersion = m_kernelCtx.getConfigurationManager().expand(
  1230. "${ProjectVersion_Major}.${ProjectVersion_Minor}.${ProjectVersion_Patch}");
  1231. const CString componentVersions = m_kernelCtx.getConfigurationManager().lookUpConfigurationTokenValue("ProjectVersion_Components");
  1232. fprintf(file, "# Last version of " DESIGNER_NAME " used:\n");
  1233. fprintf(file, "Designer_LastVersionUsed = %s\n", projectVersion.toASCIIString());
  1234. fprintf(file, "Designer_LastComponentVersionsUsed = %s\n", componentVersions.toASCIIString());
  1235. fprintf(file, "\n");
  1236. fprintf(file, "# Recently opened scenario\n");
  1237. size_t scenarioID = 1;
  1238. for (const GtkWidget* recentScenario : m_recentScenarios)
  1239. {
  1240. const gchar* recentScenarioPath = gtk_menu_item_get_label(GTK_MENU_ITEM(recentScenario));
  1241. fprintf(file, "Designer_RecentScenario_%03u = %s\n", scenarioID, recentScenarioPath);
  1242. ++scenarioID;
  1243. }
  1244. fprintf(file, "\n");
  1245. fclose(file);
  1246. }
  1247. else { m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "Error writing to '" << appConfigFile << "'\n"; }
  1248. }
  1249. }
  1250. void CApplication::dragDataGetCB(GtkWidget* /*widget*/, GdkDragContext* /*dc*/, GtkSelectionData* selectionData, guint /*info*/, guint /*time*/) const
  1251. {
  1252. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "dragDataGetCB\n";
  1253. GtkTreeView* view = GTK_TREE_VIEW(gtk_builder_get_object(m_Builder, "openvibe-box_algorithm_tree"));
  1254. GtkTreeSelection* selection = gtk_tree_view_get_selection(view);
  1255. GtkTreeModel* model = nullptr;
  1256. GtkTreeIter iter;
  1257. if (gtk_tree_selection_get_selected(selection, &model, &iter))
  1258. {
  1259. const char* boxAlgorithmID = nullptr;
  1260. gtk_tree_model_get(model, &iter, Resource_StringIdentifier, &boxAlgorithmID, -1);
  1261. if (boxAlgorithmID)
  1262. {
  1263. gtk_selection_data_set(selectionData, GDK_SELECTION_TYPE_STRING, 8, reinterpret_cast<const guchar*>(boxAlgorithmID),
  1264. gint(strlen(boxAlgorithmID) + 1));
  1265. }
  1266. }
  1267. }
  1268. void CApplication::undoCB()
  1269. {
  1270. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "undoCB\n";
  1271. CInterfacedScenario* scenario = this->getCurrentInterfacedScenario();
  1272. if (scenario) { scenario->undoCB(); }
  1273. }
  1274. void CApplication::redoCB()
  1275. {
  1276. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "redoCB\n";
  1277. CInterfacedScenario* scenario = this->getCurrentInterfacedScenario();
  1278. if (scenario) { scenario->redoCB(); }
  1279. }
  1280. void CApplication::copySelectionCB()
  1281. {
  1282. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "copySelectionCB\n";
  1283. CInterfacedScenario* scenario = this->getCurrentInterfacedScenario();
  1284. if (scenario) { scenario->copySelection(); }
  1285. }
  1286. void CApplication::cutSelectionCB()
  1287. {
  1288. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "cutSelectionCB\n";
  1289. CInterfacedScenario* scenario = this->getCurrentInterfacedScenario();
  1290. if (scenario) { scenario->cutSelection(); }
  1291. }
  1292. void CApplication::pasteSelectionCB()
  1293. {
  1294. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "pasteSelectionCB\n";
  1295. CInterfacedScenario* scenario = this->getCurrentInterfacedScenario();
  1296. if (scenario) { scenario->pasteSelection(); }
  1297. }
  1298. void CApplication::deleteSelectionCB()
  1299. {
  1300. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "deleteSelectionCB\n";
  1301. CInterfacedScenario* scenario = this->getCurrentInterfacedScenario();
  1302. if (scenario) { scenario->deleteSelection(); }
  1303. }
  1304. void CApplication::preferencesCB() const
  1305. {
  1306. enum { Resource_TokenName, Resource_TokenValue, Resource_TokenExpand };
  1307. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "preferencesCB\n";
  1308. GtkBuilder* builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "configuration_manager", nullptr);
  1309. gtk_builder_add_from_file(builder, OVD_GUI_File, nullptr);
  1310. gtk_builder_connect_signals(builder, nullptr);
  1311. GtkWidget* configMgr = GTK_WIDGET(gtk_builder_get_object(builder, "configuration_manager"));
  1312. GtkTreeView* configMgrTreeView = GTK_TREE_VIEW(gtk_builder_get_object(builder, "configuration_manager-treeview"));
  1313. // Prepares tree view
  1314. GtkTreeViewColumn* treeViewColumnTokenName = gtk_tree_view_column_new();
  1315. GtkTreeViewColumn* treeViewColumnTokenValue = gtk_tree_view_column_new();
  1316. GtkTreeViewColumn* treeViewColumnTokenExpand = gtk_tree_view_column_new();
  1317. GtkCellRenderer* cellRendererTokenName = gtk_cell_renderer_text_new();
  1318. GtkCellRenderer* cellRendererTokenValue = gtk_cell_renderer_text_new();
  1319. GtkCellRenderer* cellRendererTokenExpand = gtk_cell_renderer_text_new();
  1320. gtk_tree_view_column_set_title(treeViewColumnTokenName, "Token name");
  1321. gtk_tree_view_column_set_title(treeViewColumnTokenValue, "Token value");
  1322. gtk_tree_view_column_set_title(treeViewColumnTokenExpand, "Expanded token value");
  1323. gtk_tree_view_column_pack_start(treeViewColumnTokenName, cellRendererTokenName, TRUE);
  1324. gtk_tree_view_column_pack_start(treeViewColumnTokenValue, cellRendererTokenValue, TRUE);
  1325. gtk_tree_view_column_pack_start(treeViewColumnTokenExpand, cellRendererTokenExpand, TRUE);
  1326. gtk_tree_view_column_set_attributes(treeViewColumnTokenName, cellRendererTokenName, "text", Resource_TokenName, nullptr);
  1327. gtk_tree_view_column_set_attributes(treeViewColumnTokenValue, cellRendererTokenValue, "text", Resource_TokenValue, nullptr);
  1328. gtk_tree_view_column_set_attributes(treeViewColumnTokenExpand, cellRendererTokenExpand, "text", Resource_TokenExpand, nullptr);
  1329. gtk_tree_view_column_set_sort_column_id(treeViewColumnTokenName, Resource_TokenName);
  1330. gtk_tree_view_column_set_sort_column_id(treeViewColumnTokenValue, Resource_TokenValue);
  1331. gtk_tree_view_column_set_sort_column_id(treeViewColumnTokenExpand, Resource_TokenExpand);
  1332. gtk_tree_view_column_set_sizing(treeViewColumnTokenName, GTK_TREE_VIEW_COLUMN_FIXED);
  1333. gtk_tree_view_column_set_sizing(treeViewColumnTokenValue, GTK_TREE_VIEW_COLUMN_FIXED);
  1334. gtk_tree_view_column_set_sizing(treeViewColumnTokenExpand, GTK_TREE_VIEW_COLUMN_FIXED);
  1335. gtk_tree_view_column_set_expand(treeViewColumnTokenName, TRUE);
  1336. gtk_tree_view_column_set_expand(treeViewColumnTokenValue, TRUE);
  1337. gtk_tree_view_column_set_expand(treeViewColumnTokenExpand, TRUE);
  1338. gtk_tree_view_column_set_resizable(treeViewColumnTokenName, TRUE);
  1339. gtk_tree_view_column_set_resizable(treeViewColumnTokenValue, TRUE);
  1340. gtk_tree_view_column_set_resizable(treeViewColumnTokenExpand, TRUE);
  1341. gtk_tree_view_column_set_min_width(treeViewColumnTokenName, 256);
  1342. gtk_tree_view_column_set_min_width(treeViewColumnTokenValue, 256);
  1343. gtk_tree_view_column_set_min_width(treeViewColumnTokenExpand, 256);
  1344. gtk_tree_view_append_column(configMgrTreeView, treeViewColumnTokenName);
  1345. gtk_tree_view_append_column(configMgrTreeView, treeViewColumnTokenValue);
  1346. gtk_tree_view_append_column(configMgrTreeView, treeViewColumnTokenExpand);
  1347. gtk_tree_view_column_set_sort_indicator(treeViewColumnTokenName, TRUE);
  1348. // Prepares tree model
  1349. CIdentifier tokenID;
  1350. GtkTreeStore* configMgrTreeModel = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
  1351. while ((tokenID = m_kernelCtx.getConfigurationManager().getNextConfigurationTokenIdentifier(tokenID)) != CIdentifier::undefined())
  1352. {
  1353. GtkTreeIter iter;
  1354. CString name = m_kernelCtx.getConfigurationManager().getConfigurationTokenName(tokenID);
  1355. CString value = m_kernelCtx.getConfigurationManager().getConfigurationTokenValue(tokenID);
  1356. CString expand = m_kernelCtx.getConfigurationManager().expand(value);
  1357. gtk_tree_store_append(configMgrTreeModel, &iter, nullptr);
  1358. gtk_tree_store_set(configMgrTreeModel, &iter, Resource_TokenName, name.toASCIIString(), Resource_TokenValue, value.toASCIIString(),
  1359. Resource_TokenExpand, expand.toASCIIString(), -1);
  1360. }
  1361. gtk_tree_view_set_model(configMgrTreeView, GTK_TREE_MODEL(configMgrTreeModel));
  1362. g_signal_emit_by_name(treeViewColumnTokenName, "clicked");
  1363. gtk_dialog_run(GTK_DIALOG(configMgr));
  1364. gtk_widget_destroy(configMgr);
  1365. g_object_unref(configMgrTreeModel);
  1366. g_object_unref(builder);
  1367. }
  1368. void CApplication::testCB() const { m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "testCB\n"; }
  1369. void CApplication::newScenarioCB()
  1370. {
  1371. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "newScenarioCB\n";
  1372. CIdentifier scenarioID;
  1373. if (m_ScenarioMgr->createScenario(scenarioID))
  1374. {
  1375. Kernel::IScenario& scenario = m_ScenarioMgr->getScenario(scenarioID);
  1376. CInterfacedScenario* interfacedScenario = new CInterfacedScenario(m_kernelCtx, *this, scenario, scenarioID, *m_scenarioNotebook, OVD_GUI_File,
  1377. OVD_GUI_Settings_File);
  1378. if (interfacedScenario->m_DesignerVisualization != nullptr)
  1379. {
  1380. interfacedScenario->m_DesignerVisualization->setDeleteEventCB(&delete_designer_visualisation_cb, this);
  1381. interfacedScenario->m_DesignerVisualization->newVisualizationWindow("Default window");
  1382. }
  1383. interfacedScenario->updateScenarioLabel();
  1384. m_Scenarios.push_back(interfacedScenario);
  1385. gtk_notebook_set_current_page(m_scenarioNotebook, gtk_notebook_get_n_pages(m_scenarioNotebook) - 1);
  1386. //this->changeCurrentScenario(gtk_notebook_get_n_pages(m_scenarioNotebook)-1);
  1387. }
  1388. }
  1389. void CApplication::openScenarioCB()
  1390. {
  1391. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "openScenarioCB\n";
  1392. GtkFileFilter* specific = gtk_file_filter_new();
  1393. GtkFileFilter* all = gtk_file_filter_new();
  1394. std::string allFileFormatsString = "All available formats (";
  1395. CString fileNameExtension = "";
  1396. while ((fileNameExtension = m_kernelCtx.getScenarioManager().getNextScenarioImporter(OVD_ScenarioImportContext_OpenScenario, fileNameExtension)) !=
  1397. CString(""))
  1398. {
  1399. std::string currentFileFormatMask = "*" + std::string(fileNameExtension.toASCIIString());
  1400. gtk_file_filter_add_pattern(specific, currentFileFormatMask.c_str());
  1401. allFileFormatsString += "*" + std::string(fileNameExtension) + ", ";
  1402. }
  1403. allFileFormatsString.erase(allFileFormatsString.size() - 2); // because the loop adds one ", " too much
  1404. allFileFormatsString += ")";
  1405. gtk_file_filter_set_name(specific, allFileFormatsString.c_str());
  1406. gtk_file_filter_set_name(all, "All files");
  1407. gtk_file_filter_add_pattern(all, "*");
  1408. GtkWidget* widgetDialogOpen = gtk_file_chooser_dialog_new("Select scenario to open...", nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
  1409. GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, nullptr);
  1410. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(widgetDialogOpen), specific);
  1411. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(widgetDialogOpen), all);
  1412. gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(widgetDialogOpen), specific);
  1413. // GTK 2 known bug: this won't work if setCurrentFolder is also used on the dialog.
  1414. gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(widgetDialogOpen), true);
  1415. gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(widgetDialogOpen), this->getWorkingDirectory().toASCIIString());
  1416. gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(widgetDialogOpen), true);
  1417. if (gtk_dialog_run(GTK_DIALOG(widgetDialogOpen)) == GTK_RESPONSE_ACCEPT)
  1418. {
  1419. //char* fileName=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widgetDialogOpen));
  1420. GSList* list;
  1421. GSList* file = list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widgetDialogOpen));
  1422. while (file)
  1423. {
  1424. char* filename = static_cast<char*>(file->data);
  1425. char* backslash;
  1426. while ((backslash = strchr(filename, '\\')) != nullptr) { *backslash = '/'; }
  1427. this->openScenario(filename);
  1428. g_free(file->data);
  1429. file = file->next;
  1430. }
  1431. g_slist_free(list);
  1432. }
  1433. gtk_widget_destroy(widgetDialogOpen);
  1434. // g_object_unref(fileFilterSpecific);
  1435. // g_object_unref(fileFilterAll);
  1436. }
  1437. void CApplication::saveScenarioCB(CInterfacedScenario* scenario)
  1438. {
  1439. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "saveScenarioCB\n";
  1440. CInterfacedScenario* currScenario = scenario ? scenario : getCurrentInterfacedScenario();
  1441. if (!currScenario) { return; }
  1442. if (currScenario->m_Scenario.containsBoxWithDeprecatedInterfacors())
  1443. {
  1444. cannotSaveScenarioBeforeUpdate();
  1445. return;
  1446. }
  1447. if (!currScenario->m_HasFileName) { saveScenarioAsCB(scenario); }
  1448. else
  1449. {
  1450. // If the current scenario is a metabox, we will save its prototype hash into an attribute of the scenario
  1451. // that way the standalone scheduler can check whether metaboxes included inside need updating.
  1452. if (currScenario->m_Scenario.isMetabox())
  1453. {
  1454. SBoxProto metaboxProto(m_kernelCtx.getTypeManager());
  1455. Kernel::IScenario& tmp = currScenario->m_Scenario;
  1456. for (size_t i = 0; i < tmp.getInputCount(); ++i)
  1457. {
  1458. CString name;
  1459. CIdentifier typeID;
  1460. CIdentifier id;
  1461. tmp.getInputType(i, typeID);
  1462. tmp.getInputName(i, name);
  1463. tmp.getInterfacorIdentifier(Kernel::Input, i, id);
  1464. metaboxProto.addInput(name, typeID, id, true);
  1465. }
  1466. for (size_t i = 0; i < tmp.getOutputCount(); ++i)
  1467. {
  1468. CString name;
  1469. CIdentifier typeID;
  1470. CIdentifier id;
  1471. tmp.getOutputType(i, typeID);
  1472. tmp.getOutputName(i, name);
  1473. tmp.getInterfacorIdentifier(Kernel::Output, i, id);
  1474. metaboxProto.addOutput(name, typeID, id, true);
  1475. }
  1476. for (size_t i = 0; i < tmp.getSettingCount(); ++i)
  1477. {
  1478. CString name;
  1479. CIdentifier typeID;
  1480. CString value;
  1481. tmp.getSettingName(i, name);
  1482. tmp.getSettingType(i, typeID);
  1483. tmp.getSettingDefaultValue(i, value);
  1484. metaboxProto.addSetting(name, typeID, value, false, CIdentifier::undefined(), true);
  1485. }
  1486. if (tmp.hasAttribute(OV_AttributeId_Scenario_MetaboxHash))
  1487. {
  1488. tmp.setAttributeValue(OV_AttributeId_Scenario_MetaboxHash, metaboxProto.hash.toString());
  1489. }
  1490. else { tmp.addAttribute(OV_AttributeId_Scenario_MetaboxHash, metaboxProto.hash.toString()); }
  1491. if (!tmp.hasAttribute(OVP_AttributeId_Metabox_ID)) { tmp.setAttributeValue(OVP_AttributeId_Metabox_ID, CIdentifier::random().str().c_str()); }
  1492. m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "This metaboxes Hash : " << metaboxProto.hash << "\n";
  1493. }
  1494. const char* scenarioFileName = currScenario->m_Filename.c_str();
  1495. // Remove attributes that were added to links and boxes by the designer and which are used only for interal functionality.
  1496. // This way the scenarios do not change if, for example somebody opens them on a system with different font metrics.
  1497. currScenario->m_Scenario.removeAttribute(OV_AttributeId_ScenarioFilename);
  1498. CIdentifier linkID;
  1499. while ((linkID = currScenario->m_Scenario.getNextLinkIdentifier(linkID)) != CIdentifier::undefined())
  1500. {
  1501. auto link = currScenario->m_Scenario.getLinkDetails(linkID);
  1502. link->removeAttribute(OV_AttributeId_Link_XSrc);
  1503. link->removeAttribute(OV_AttributeId_Link_YSrc);
  1504. link->removeAttribute(OV_AttributeId_Link_XDst);
  1505. link->removeAttribute(OV_AttributeId_Link_YDst);
  1506. link->removeAttribute(OV_ClassId_Selected);
  1507. }
  1508. CIdentifier boxID;
  1509. while ((boxID = currScenario->m_Scenario.getNextBoxIdentifier(boxID)) != CIdentifier::undefined())
  1510. {
  1511. auto box = currScenario->m_Scenario.getBoxDetails(boxID);
  1512. box->removeAttribute(OV_AttributeId_Box_XSize);
  1513. box->removeAttribute(OV_AttributeId_Box_YSize);
  1514. box->removeAttribute(OV_ClassId_Selected);
  1515. }
  1516. CIdentifier commentID;
  1517. while ((commentID = currScenario->m_Scenario.getNextCommentIdentifier(commentID)) != CIdentifier::undefined())
  1518. {
  1519. auto comment = currScenario->m_Scenario.getCommentDetails(commentID);
  1520. comment->removeAttribute(OV_ClassId_Selected);
  1521. }
  1522. // Remove all VisualizationTree type metadata
  1523. // We save the last found identifier if there was one, this allows us to not modify it on subsequent saves
  1524. CIdentifier metadataID = CIdentifier::undefined();
  1525. CIdentifier lastFoundTreeIdentifier = CIdentifier::undefined();
  1526. while ((metadataID = currScenario->m_Scenario.getNextMetadataIdentifier(metadataID)) != CIdentifier::undefined())
  1527. {
  1528. if (currScenario->m_Scenario.getMetadataDetails(metadataID)->getType() == OVVIZ_MetadataIdentifier_VisualizationTree)
  1529. {
  1530. currScenario->m_Scenario.removeMetadata(metadataID);
  1531. lastFoundTreeIdentifier = metadataID;
  1532. metadataID = CIdentifier::undefined();
  1533. }
  1534. }
  1535. // Insert new metadata
  1536. currScenario->m_Scenario.addMetadata(metadataID, lastFoundTreeIdentifier);
  1537. currScenario->m_Scenario.getMetadataDetails(metadataID)->setType(OVVIZ_MetadataIdentifier_VisualizationTree);
  1538. currScenario->m_Scenario.getMetadataDetails(metadataID)->setData(currScenario->m_Tree->serialize());
  1539. CIdentifier scenarioExportContext = OVD_ScenarioExportContext_SaveScenario;
  1540. if (currScenario->m_Scenario.isMetabox()) { scenarioExportContext = OVD_ScenarioExportContext_SaveMetabox; }
  1541. m_kernelCtx.getErrorManager().releaseErrors();
  1542. if (m_ScenarioMgr->exportScenarioToFile(scenarioExportContext, scenarioFileName, currScenario->m_ScenarioID))
  1543. {
  1544. currScenario->snapshotCB();
  1545. currScenario->m_HasFileName = true;
  1546. currScenario->m_HasBeenModified = false;
  1547. currScenario->updateScenarioLabel();
  1548. this->saveOpenedScenarios();
  1549. }
  1550. else
  1551. {
  1552. m_kernelCtx.getLogManager() << Kernel::LogLevel_Warning << "Exporting scenario failed...\n";
  1553. GtkBuilder* builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "about", nullptr);
  1554. gtk_builder_add_from_file(builder, OVD_GUI_File, nullptr);
  1555. gtk_builder_connect_signals(builder, nullptr);
  1556. GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "dialog_error_popup_saving"));
  1557. // Reset the labels
  1558. gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "dialog_error_popup_saving-label1")), "");
  1559. gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder, "dialog_error_popup_saving-label2")), "");
  1560. if (m_kernelCtx.getErrorManager().hasError())
  1561. {
  1562. gtk_label_set_text(
  1563. GTK_LABEL(gtk_builder_get_object(builder, "dialog_error_popup_saving-label1")), m_kernelCtx.getErrorManager().getLastErrorString());
  1564. }
  1565. gtk_builder_connect_signals(builder, nullptr);
  1566. const gint responseId = gtk_dialog_run(GTK_DIALOG(dialog));
  1567. gtk_widget_destroy(dialog);
  1568. g_object_unref(builder);
  1569. switch (responseId)
  1570. {
  1571. case GTK_RESPONSE_OK:
  1572. this->saveScenarioCB(scenario);
  1573. break;
  1574. case GTK_RESPONSE_DELETE_EVENT:
  1575. case GTK_RESPONSE_CANCEL: //return; //useless no loop and default make nothing
  1576. default: break;
  1577. }
  1578. }
  1579. }
  1580. }
  1581. void CApplication::restoreDefaultScenariosCB() const
  1582. {
  1583. const CString defaultScenariosDirectory = m_kernelCtx.getConfigurationManager().expand(OVD_SCENARIOS_PATH);
  1584. const CString defaultWorkingDirectory = m_kernelCtx.getConfigurationManager().expand(OVD_WORKING_SCENARIOS_PATH);
  1585. const CString message = "Default scenarios will be restored in '" + defaultWorkingDirectory + "' folder.\n"
  1586. + "All previous scenarios in this folder will be removed.\n"
  1587. + "Do you want to continue ?\n";
  1588. GtkWidget* widgetDialogRestoreScenarios = gtk_message_dialog_new(nullptr, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s",
  1589. message.toASCIIString());
  1590. const CString backupFolder = defaultWorkingDirectory + m_kernelCtx.getConfigurationManager().expand("-$core{date}-$core{time}");
  1591. if (gtk_dialog_run(GTK_DIALOG(widgetDialogRestoreScenarios)) == GTK_RESPONSE_YES)
  1592. {
  1593. // to avoid to loose old data, make a backup
  1594. FS::Files::removeAll(backupFolder);
  1595. if (FS::Files::copyDirectory(defaultWorkingDirectory, backupFolder))
  1596. {
  1597. m_kernelCtx.getLogManager() << Kernel::LogLevel_Info << "Old scenario folder backed up into "
  1598. << backupFolder << " folder\n";
  1599. // make the copy
  1600. FS::Files::removeAll(defaultWorkingDirectory);
  1601. if (FS::Files::copyDirectory(defaultScenariosDirectory, defaultWorkingDirectory))
  1602. {
  1603. m_kernelCtx.getLogManager() << Kernel::LogLevel_Info << "Default scenarios restored into " << defaultWorkingDirectory << " folder\n";
  1604. }
  1605. else { m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "Could not copy " << defaultWorkingDirectory << " folder\n"; }
  1606. }
  1607. else { m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "Could not back up " << defaultWorkingDirectory << " folder. Copy has aborted.\n"; }
  1608. }
  1609. gtk_widget_destroy(widgetDialogRestoreScenarios);
  1610. }
  1611. void CApplication::saveScenarioAsCB(CInterfacedScenario* scenario)
  1612. {
  1613. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "saveScenarioAsCB\n";
  1614. CInterfacedScenario* currScenario = scenario ? scenario : getCurrentInterfacedScenario();
  1615. if (!currScenario) { return; }
  1616. if (currScenario->m_Scenario.containsBoxWithDeprecatedInterfacors())
  1617. {
  1618. cannotSaveScenarioBeforeUpdate();
  1619. return;
  1620. }
  1621. const bool isCurrentScenarioAMetabox = currScenario->m_Scenario.isMetabox();
  1622. GtkFileFilter* all = gtk_file_filter_new(); // All files
  1623. gtk_file_filter_set_name(all, "All files");
  1624. gtk_file_filter_add_pattern(all, "*");
  1625. GtkFileFilter* allCompatibleFormatsFileFilter = gtk_file_filter_new(); // All compatible files
  1626. std::map<GtkFileFilter*, std::string> fileFilters;
  1627. std::set<std::string> compatibleExtensions;
  1628. CString ext;
  1629. if (!isCurrentScenarioAMetabox)
  1630. {
  1631. while ((ext = m_kernelCtx.getScenarioManager().getNextScenarioExporter(OVD_ScenarioExportContext_SaveScenario, ext)) != CString(""))
  1632. {
  1633. compatibleExtensions.emplace(ext);
  1634. }
  1635. }
  1636. while ((ext = m_kernelCtx.getScenarioManager().getNextScenarioExporter(OVD_ScenarioExportContext_SaveMetabox, ext)) != CString(""))
  1637. {
  1638. compatibleExtensions.emplace(ext);
  1639. }
  1640. std::string allCompatibleFormatsFilterName = "All compatible formats (";
  1641. for (auto& extension : compatibleExtensions)
  1642. {
  1643. GtkFileFilter* fileFilter = gtk_file_filter_new();
  1644. std::string filterName = m_kernelCtx.getConfigurationManager().expand(std::string("${ScenarioFileNameExtension" + extension + "}").c_str()).
  1645. toASCIIString() + std::string(" (*") + extension + ")";
  1646. gtk_file_filter_set_name(fileFilter, filterName.c_str());
  1647. std::string filterWildcard = "*" + extension;
  1648. gtk_file_filter_add_pattern(fileFilter, filterWildcard.c_str());
  1649. fileFilters[fileFilter] = extension;
  1650. allCompatibleFormatsFilterName += filterWildcard + ", ";
  1651. gtk_file_filter_add_pattern(allCompatibleFormatsFileFilter, filterWildcard.c_str());
  1652. }
  1653. allCompatibleFormatsFilterName.erase(allCompatibleFormatsFilterName.size() - 2); // because the loop adds one ", " too much
  1654. allCompatibleFormatsFilterName += ")";
  1655. gtk_file_filter_set_name(allCompatibleFormatsFileFilter, allCompatibleFormatsFilterName.c_str());
  1656. // gtk_file_filter_set_name(fileFilterSVG, "SVG image");
  1657. // gtk_file_filter_add_pattern(fileFilterSVG, "*.svg");
  1658. GtkWidget* widgetDialogSaveAs = gtk_file_chooser_dialog_new("Select scenario to save...", nullptr, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL,
  1659. GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, nullptr);
  1660. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(widgetDialogSaveAs), allCompatibleFormatsFileFilter);
  1661. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(widgetDialogSaveAs), all);
  1662. for (const auto& fileFilter : fileFilters) { gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(widgetDialogSaveAs), fileFilter.first); }
  1663. gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(widgetDialogSaveAs), allCompatibleFormatsFileFilter);
  1664. // gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(l_widgetDialogSaveAs), true);
  1665. if (currScenario->m_HasFileName) { gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(widgetDialogSaveAs), currScenario->m_Filename.c_str()); }
  1666. else
  1667. {
  1668. // Put metaboxes to the User metabox folder by default
  1669. if (isCurrentScenarioAMetabox)
  1670. {
  1671. gtk_file_chooser_set_current_folder(
  1672. GTK_FILE_CHOOSER(widgetDialogSaveAs), m_kernelCtx.getConfigurationManager().expand("${Path_UserData}/metaboxes").toASCIIString());
  1673. }
  1674. else { gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(widgetDialogSaveAs), this->getWorkingDirectory().toASCIIString()); }
  1675. }
  1676. if (gtk_dialog_run(GTK_DIALOG(widgetDialogSaveAs)) == GTK_RESPONSE_ACCEPT)
  1677. {
  1678. char* tmp = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widgetDialogSaveAs));
  1679. // replaces \ with / on windows
  1680. char* backslash;
  1681. while ((backslash = strchr(tmp, '\\')) != nullptr) { *backslash = '/'; }
  1682. // stores filename in a local variable
  1683. char filename[1024];
  1684. int length = sprintf(filename, "%s", tmp);
  1685. g_free(tmp);
  1686. GtkFileFilter* filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(widgetDialogSaveAs));
  1687. if (fileFilters.count(filter) != 0)
  1688. {
  1689. // User chose a specific filter
  1690. const std::string expectedExtension = fileFilters[filter];
  1691. if (_strcmpi(filename + length - 4, (std::string(".") + expectedExtension).c_str()) != 0)
  1692. {
  1693. // If filename already has an extension, remove it
  1694. if (filename[length - 4] == '.')
  1695. {
  1696. length -= 4;
  1697. filename[length] = '\0';
  1698. }
  1699. // When user did not put appropriate extension, append it
  1700. strcat(filename, expectedExtension.c_str());
  1701. //filenameLength += int(1 + expectedExtension.length());
  1702. }
  1703. }
  1704. // Set a default extension in case the current one is not compatible or there is none
  1705. const std::string scenarioFilenameExtension = boost::filesystem::extension(filename);
  1706. if (!compatibleExtensions.count(scenarioFilenameExtension))
  1707. {
  1708. //if (isCurrentScenarioAMetabox) { strcat(filename, ".mxb"); }
  1709. //else { strcat(filename, ".mxs"); }
  1710. //filenameLength += 4;
  1711. strcat(filename, ".xml");
  1712. }
  1713. // We ensure the file does not exist
  1714. bool isSaveActionValid = true;
  1715. FILE* file = FS::Files::open(filename, "r");
  1716. if (file)
  1717. {
  1718. fclose(file);
  1719. GtkDialog* confirmationDialog = GTK_DIALOG(
  1720. ::gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "The file already exists"));
  1721. gtk_message_dialog_format_secondary_text(
  1722. GTK_MESSAGE_DIALOG(confirmationDialog),
  1723. "%s\n\nThe file you are trying to save-as already exists, confirming this action will overwrite the existing file. Please confirm you want to overwrite the existing file.",
  1724. filename);
  1725. isSaveActionValid = (gtk_dialog_run(GTK_DIALOG(confirmationDialog)) == GTK_RESPONSE_OK);
  1726. gtk_widget_destroy(GTK_WIDGET(confirmationDialog));
  1727. }
  1728. // Finally save the scenario
  1729. if (isSaveActionValid)
  1730. {
  1731. currScenario->m_Filename = filename;
  1732. currScenario->m_HasFileName = true;
  1733. currScenario->m_HasBeenModified = false;
  1734. currScenario->updateScenarioLabel();
  1735. saveScenarioCB(currScenario);
  1736. }
  1737. else { m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "Canceled 'save-as' action for filename [" << filename << "]\n"; }
  1738. }
  1739. gtk_widget_destroy(widgetDialogSaveAs);
  1740. // g_object_unref(fileFilterSpecific);
  1741. // g_object_unref(fileFilterAll);
  1742. }
  1743. void CApplication::addRecentScenario(const std::string& scenarioPath)
  1744. {
  1745. bool scenarioFound = false;
  1746. // If scenario path is already in menu, remove it from menu shell and re-add it on top of list
  1747. for (size_t i = 0; i < m_recentScenarios.size(); ++i)
  1748. {
  1749. const gchar* fileName = gtk_menu_item_get_label(GTK_MENU_ITEM(m_recentScenarios[i]));
  1750. if (strcmp(fileName, scenarioPath.c_str()) == 0)
  1751. {
  1752. gtk_container_remove(m_menuOpenRecent, GTK_WIDGET(m_recentScenarios[i]));
  1753. gtk_menu_shell_prepend(GTK_MENU_SHELL(m_menuOpenRecent), GTK_WIDGET(m_recentScenarios[i]));
  1754. scenarioFound = true;
  1755. m_recentScenarios.insert(m_recentScenarios.begin(), m_recentScenarios[i]);
  1756. m_recentScenarios.erase(m_recentScenarios.begin() + i + 1);
  1757. break;
  1758. }
  1759. }
  1760. // If scenario is not in menu, create new widget and add it to menu shell
  1761. if (!scenarioFound)
  1762. {
  1763. GtkWidget* newRecentItem = gtk_image_menu_item_new_with_label(scenarioPath.c_str());
  1764. g_signal_connect(G_OBJECT(newRecentItem), "activate", G_CALLBACK(menu_open_recent_scenario_cb), this);
  1765. gtk_menu_shell_prepend(GTK_MENU_SHELL(m_menuOpenRecent), newRecentItem);
  1766. gtk_widget_show(newRecentItem);
  1767. m_recentScenarios.insert(m_recentScenarios.begin(), newRecentItem);
  1768. }
  1769. if (m_recentScenarios.size() > s_RecentFileNumber)
  1770. {
  1771. for (auto it = m_recentScenarios.begin() + s_RecentFileNumber; it != m_recentScenarios.end(); ++it)
  1772. {
  1773. gtk_container_remove(m_menuOpenRecent, GTK_WIDGET(*it));
  1774. gtk_widget_destroy(GTK_WIDGET(*it));
  1775. }
  1776. m_recentScenarios.erase(m_recentScenarios.begin() + s_RecentFileNumber, m_recentScenarios.end());
  1777. }
  1778. }
  1779. void CApplication::closeScenarioCB(CInterfacedScenario* scenario)
  1780. {
  1781. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "closeScenarioCB\n";
  1782. if (!scenario) { return; }
  1783. if (scenario->isLocked())
  1784. {
  1785. GtkBuilder* builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "about", nullptr);
  1786. gtk_builder_add_from_file(builder, OVD_GUI_File, nullptr);
  1787. gtk_builder_connect_signals(builder, nullptr);
  1788. GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "dialog_running_scenario"));
  1789. gtk_builder_connect_signals(builder, nullptr);
  1790. // gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE, true);
  1791. gtk_dialog_run(GTK_DIALOG(dialog));
  1792. gtk_widget_destroy(dialog);
  1793. g_object_unref(builder);
  1794. return;
  1795. }
  1796. if (scenario->m_HasBeenModified)
  1797. {
  1798. GtkBuilder* builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "about", nullptr);
  1799. gtk_builder_add_from_file(builder, OVD_GUI_File, nullptr);
  1800. gtk_builder_connect_signals(builder, nullptr);
  1801. GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "dialog_unsaved_scenario"));
  1802. gtk_builder_connect_signals(builder, nullptr);
  1803. // gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE, true);
  1804. const gint responseId = gtk_dialog_run(GTK_DIALOG(dialog));
  1805. gtk_widget_destroy(dialog);
  1806. g_object_unref(builder);
  1807. switch (responseId)
  1808. {
  1809. case GTK_RESPONSE_OK:
  1810. this->saveScenarioCB(scenario);
  1811. if (scenario->m_HasBeenModified) { return; }
  1812. break;
  1813. case GTK_RESPONSE_DELETE_EVENT:
  1814. case GTK_RESPONSE_CANCEL:
  1815. return;
  1816. default:
  1817. break;
  1818. }
  1819. }
  1820. // Add scenario to recently opened:
  1821. this->addRecentScenario(scenario->m_Filename);
  1822. const auto it = std::find(m_Scenarios.begin(), m_Scenarios.end(), scenario);
  1823. if (it != m_Scenarios.end())
  1824. {
  1825. // We need to erase the scenario from the list first, because deleting the scenario will launch a "switch-page"
  1826. // callback accessing this array with the identifier of the deleted scenario (if its not the last one) -> boom.
  1827. m_Scenarios.erase(it);
  1828. const CIdentifier id = scenario->m_ScenarioID;
  1829. delete scenario;
  1830. m_ScenarioMgr->releaseScenario(id);
  1831. //when closing last open scenario, no "switch-page" event is triggered so we manually handle this case
  1832. if (m_Scenarios.empty()) { newScenarioCB(); }
  1833. else { changeCurrentScenario(gtk_notebook_get_current_page(m_scenarioNotebook)); }
  1834. }
  1835. this->saveOpenedScenarios();
  1836. }
  1837. void CApplication::deleteDesignerVisualizationCB()
  1838. {
  1839. //untoggle window manager button when its associated dialog is closed
  1840. gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), FALSE);
  1841. CInterfacedScenario* scenario = getCurrentInterfacedScenario();
  1842. if (scenario) { scenario->snapshotCB(); }
  1843. }
  1844. void CApplication::toggleDesignerVisualizationCB()
  1845. {
  1846. CInterfacedScenario* scenario = getCurrentInterfacedScenario();
  1847. if (scenario != nullptr && !scenario->isLocked())
  1848. {
  1849. const auto index = size_t(gtk_notebook_get_current_page(m_scenarioNotebook));
  1850. if (index < m_Scenarios.size()) { m_Scenarios[index]->toggleDesignerVisualization(); }
  1851. }
  1852. }
  1853. void CApplication::aboutOpenViBECB() const
  1854. {
  1855. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "CApplication::aboutOpenViBECB\n";
  1856. GtkBuilder* builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "about", nullptr);
  1857. gtk_builder_add_from_file(builder, OVD_GUI_AboutDialog_File, nullptr);
  1858. gtk_builder_connect_signals(builder, nullptr);
  1859. //gtk_builder_connect_signals(builder, nullptr);
  1860. GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "about"));
  1861. if (dialog == nullptr)
  1862. {
  1863. m_kernelCtx.getLogManager() << Kernel::LogLevel_Warning << "Dialog could not be opened\n";
  1864. return;
  1865. }
  1866. if (m_kernelCtx.getConfigurationManager().expand("${Application_Name}").length() > 0)
  1867. {
  1868. gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), m_kernelCtx.getConfigurationManager().expand("${Application_Name}").toASCIIString());
  1869. }
  1870. if (m_kernelCtx.getConfigurationManager().expand("${Application_Version}").length() > 0)
  1871. {
  1872. gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), m_kernelCtx.getConfigurationManager().expand("${Application_Version}").toASCIIString());
  1873. }
  1874. gchar* strval;
  1875. g_object_get(dialog, "comments", &strval, nullptr);
  1876. // We use a lookup instead of expansion as JSON can contain { } characters
  1877. const std::string componentVersionsJSON = m_kernelCtx.getConfigurationManager().expand("${ProjectVersion_Components}").toASCIIString();
  1878. if (!componentVersionsJSON.empty())
  1879. {
  1880. // This check is necessary because the asignemt operator would fail with an assert
  1881. if (json::Deserialize(componentVersionsJSON).GetType() == json::ObjectVal)
  1882. {
  1883. json::Object components = json::Deserialize(componentVersionsJSON);
  1884. const std::string update = std::accumulate(components.begin(), components.end(), std::string(strval) + "\nComponents :\n",
  1885. [](const std::string& a, const std::pair<std::string, json::Value>& b)
  1886. {
  1887. return a + b.first + " version " + b.second.ToString() + "\n";
  1888. });
  1889. g_object_set(dialog, "comments", update.c_str(), nullptr);
  1890. }
  1891. }
  1892. g_free(strval);
  1893. gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE, true);
  1894. gtk_dialog_run(GTK_DIALOG(dialog));
  1895. gtk_widget_destroy(dialog);
  1896. g_object_unref(builder);
  1897. }
  1898. void CApplication::aboutScenarioCB(CInterfacedScenario* scenario) const
  1899. {
  1900. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "CApplication::aboutScenarioCB\n";
  1901. if (scenario && !scenario->isLocked()) { scenario->contextMenuScenarioAboutCB(); }
  1902. }
  1903. void CApplication::aboutLinkClickedCB(const gchar* url) const
  1904. {
  1905. if (!url) { return; }
  1906. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "CApplication::aboutLinkClickedCB\n";
  1907. const CString command = m_kernelCtx.getConfigurationManager().expand("${Designer_WebBrowserCommand} " + CString(url));
  1908. const int result = system(command.toASCIIString());
  1909. if (result < 0) { m_kernelCtx.getLogManager() << Kernel::LogLevel_Warning << "Could not launch command " << command << "\n"; }
  1910. }
  1911. void CApplication::browseDocumentationCB() const
  1912. {
  1913. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "CApplication::browseDocumentationCB\n";
  1914. const CString command = m_kernelCtx.getConfigurationManager().expand(
  1915. "${Designer_HelpBrowserCommand} \"${Designer_HelpBrowserDocumentationIndex}\" ${Designer_HelpBrowserCommandPostfix}");
  1916. const int result = system(command.toASCIIString());
  1917. OV_WARNING_UNLESS((result == 0), "Could not launch command " << command << "\n", m_kernelCtx.getLogManager());
  1918. }
  1919. void CApplication::registerLicenseCB()
  1920. {
  1921. #if defined TARGET_OS_Windows && defined(MENSIA_DISTRIBUTION)
  1922. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "CApplication::registerLicenseCB\n";
  1923. const std::string cmd = (Directories::getBinDir() + "/mensia-flexnet-activation.exe").toASCIIString();
  1924. STARTUPINFO startupInfo;
  1925. PROCESS_INFORMATION processInfo;
  1926. GetStartupInfo(&startupInfo);
  1927. if (!System::WindowsUtilities::utf16CompliantCreateProcess(nullptr, const_cast<char*>(cmd.c_str()), nullptr, nullptr, 0, 0, nullptr, nullptr, &startupInfo,
  1928. &processInfo)) { exit(1); }
  1929. #elif defined TARGET_OS_Linux && defined(MENSIA_DISTRIBUTION)
  1930. m_kernelCtx.getLogManager() << Kernel::LogLevel_Info << "Register License application's GUI cannot run on Linux. In order to activate your license,"
  1931. << " you can use the tool 'mensia-flexnet-activation' in command line.\n";
  1932. #endif
  1933. }
  1934. void CApplication::reportIssueCB() const
  1935. {
  1936. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "CApplication::reportIssueCB\n";
  1937. const CString command = m_kernelCtx.getConfigurationManager().expand(
  1938. "${Designer_WebBrowserCommand} ${Designer_WebBrowserSupportURL} ${Designer_WebBrowserCommandPostfix}");
  1939. const int result = system(command.toASCIIString());
  1940. OV_WARNING_UNLESS((result == 0), "Could not launch command " << command << "\n", m_kernelCtx.getLogManager());
  1941. }
  1942. void CApplication::addCommentCB(CInterfacedScenario* scenario) const
  1943. {
  1944. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "CApplication::addCommentCB\n";
  1945. if (scenario && !scenario->isLocked()) { scenario->addCommentCB(); }
  1946. }
  1947. void CApplication::configureScenarioSettingsCB(CInterfacedScenario* scenario) const
  1948. {
  1949. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "CApplication::configureScenarioSettingsCB " << m_currentScenarioIdx << "\n";
  1950. if (scenario && !scenario->isLocked()) { scenario->configureScenarioSettingsCB(); }
  1951. }
  1952. Kernel::IPlayer* CApplication::getPlayer()
  1953. {
  1954. CInterfacedScenario* scenario = getCurrentInterfacedScenario();
  1955. return (scenario ? scenario->m_Player : nullptr);
  1956. }
  1957. bool CApplication::createPlayer()
  1958. {
  1959. CInterfacedScenario* scenario = getCurrentInterfacedScenario();
  1960. if (scenario && !scenario->m_Player)
  1961. {
  1962. // create a snapshot so settings override does not modify the scenario !
  1963. scenario->snapshotCB(false);
  1964. // set filename attribute to scenario so delayed configuration can be used
  1965. if (scenario->m_HasFileName)
  1966. {
  1967. if (scenario->m_Scenario.hasAttribute(OV_AttributeId_ScenarioFilename))
  1968. {
  1969. scenario->m_Scenario.setAttributeValue(OV_AttributeId_ScenarioFilename, scenario->m_Filename.c_str());
  1970. }
  1971. else { scenario->m_Scenario.addAttribute(OV_AttributeId_ScenarioFilename, scenario->m_Filename.c_str()); }
  1972. }
  1973. m_kernelCtx.getPlayerManager().createPlayer(scenario->m_PlayerID);
  1974. const CIdentifier scenarioID = scenario->m_ScenarioID;
  1975. const CIdentifier playerID = scenario->m_PlayerID;
  1976. scenario->m_Player = &m_kernelCtx.getPlayerManager().getPlayer(playerID);
  1977. if (!scenario->m_Player->setScenario(scenarioID))
  1978. {
  1979. scenario->m_PlayerID = CIdentifier::undefined();
  1980. scenario->m_Player = nullptr;
  1981. m_kernelCtx.getPlayerManager().releasePlayer(playerID);
  1982. OV_ERROR_DRF("The current scenario could not be loaded by the player.\n", Kernel::ErrorType::BadCall);
  1983. }
  1984. // The visualization manager needs to know the visualization tree in which the widgets should be inserted
  1985. scenario->m_Player->getRuntimeConfigurationManager().
  1986. createConfigurationToken("VisualizationContext_VisualizationTreeId", scenario->m_TreeID.toString());
  1987. // TODO_JL: This should be a copy of the tree containing visualizations from the metaboxes
  1988. scenario->createPlayerVisualization(scenario->m_Tree);
  1989. if (scenario->m_Player->initialize() != Kernel::EPlayerReturnCodes::Success)
  1990. {
  1991. scenario->releasePlayerVisualization();
  1992. m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "The player could not be initialized.\n";
  1993. scenario->m_PlayerID = CIdentifier::undefined();
  1994. scenario->m_Player = nullptr;
  1995. m_kernelCtx.getPlayerManager().releasePlayer(playerID);
  1996. return false;
  1997. }
  1998. scenario->m_LastLoopTime = uint64_t(-1);
  1999. //set up idle function
  2000. idle_add_cb(idle_scenario_loop, scenario);
  2001. // redraws scenario
  2002. scenario->redraw();
  2003. }
  2004. return true;
  2005. }
  2006. void CApplication::stopInterfacedScenarioAndReleasePlayer(CInterfacedScenario* scenario)
  2007. {
  2008. if (!(scenario && scenario->m_Player))
  2009. {
  2010. m_kernelCtx.getLogManager() << Kernel::LogLevel_Warning << "Trying to stop a non-started scenario" << "\n";
  2011. return;
  2012. }
  2013. scenario->stopAndReleasePlayer();
  2014. if (scenario == this->getCurrentInterfacedScenario())
  2015. {
  2016. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), false);
  2017. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), true);
  2018. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_next")), true);
  2019. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), true);
  2020. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), true);
  2021. gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), GTK_STOCK_MEDIA_PLAY);
  2022. }
  2023. }
  2024. void CApplication::stopScenarioCB()
  2025. {
  2026. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "stopScenarioCB\n";
  2027. const Kernel::EPlayerStatus currentState = this->getCurrentInterfacedScenario()->m_PlayerStatus;
  2028. if (currentState == Kernel::EPlayerStatus::Play || currentState == Kernel::EPlayerStatus::Pause || currentState == Kernel::EPlayerStatus::Forward)
  2029. {
  2030. this->stopInterfacedScenarioAndReleasePlayer(this->getCurrentInterfacedScenario());
  2031. if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-toggle_button_loop"))))
  2032. {
  2033. switch (currentState)
  2034. {
  2035. case Kernel::EPlayerStatus::Play:
  2036. playScenarioCB();
  2037. break;
  2038. case Kernel::EPlayerStatus::Forward:
  2039. forwardScenarioCB();
  2040. break;
  2041. default:
  2042. break;
  2043. }
  2044. }
  2045. }
  2046. }
  2047. void CApplication::pauseScenarioCB()
  2048. {
  2049. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "pauseScenarioCB\n";
  2050. this->createPlayer();
  2051. this->getPlayer()->pause();
  2052. this->getCurrentInterfacedScenario()->m_PlayerStatus = this->getPlayer()->getStatus();
  2053. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), true);
  2054. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), true);
  2055. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_next")), true);
  2056. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), true);
  2057. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), false);
  2058. gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), GTK_STOCK_MEDIA_PLAY);
  2059. }
  2060. void CApplication::nextScenarioCB()
  2061. {
  2062. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "nextScenarioCB\n";
  2063. this->createPlayer();
  2064. auto player = this->getPlayer();
  2065. OV_ERROR_UNLESS_DRV(player, "Player did not initialize correctly", Kernel::ErrorType::BadCall);
  2066. player->step();
  2067. this->getCurrentInterfacedScenario()->m_PlayerStatus = this->getPlayer()->getStatus();
  2068. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), true);
  2069. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), true);
  2070. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_next")), true);
  2071. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), true);
  2072. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), false);
  2073. gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), GTK_STOCK_MEDIA_PLAY);
  2074. }
  2075. void CApplication::playScenarioCB()
  2076. {
  2077. if (this->getCurrentInterfacedScenario() != nullptr)
  2078. {
  2079. Kernel::IScenario& scenario = this->getCurrentInterfacedScenario()->m_Scenario;
  2080. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "playScenarioCB\n";
  2081. if (scenario.hasOutdatedBox())
  2082. {
  2083. if (m_kernelCtx.getConfigurationManager().expandAsBoolean("${Kernel_AbortPlayerWhenBoxIsOutdated}", false))
  2084. {
  2085. std::string outdatedBoxesList = "You can not start the scenario because following boxes need to be updated: \n";
  2086. CIdentifier boxID;
  2087. while ((boxID = scenario.getNextOutdatedBoxIdentifier(boxID)) != CIdentifier::undefined())
  2088. {
  2089. const Kernel::IBox* box = scenario.getBoxDetails(boxID);
  2090. outdatedBoxesList += "\t[" + box->getName() + "]\n";
  2091. }
  2092. outdatedBoxesList += "To update a box you need to delete it from scenario, and add it again.";
  2093. GtkWidget* dialog = gtk_message_dialog_new(nullptr, GtkDialogFlags(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), GTK_MESSAGE_INFO,
  2094. GTK_BUTTONS_OK, "%s", outdatedBoxesList.c_str());
  2095. gtk_dialog_run(GTK_DIALOG(dialog));
  2096. gtk_widget_destroy(dialog);
  2097. return;
  2098. }
  2099. if (m_kernelCtx.getConfigurationManager().expandAsBoolean("${Designer_ThrowPopUpWhenBoxIsOutdated}", false))
  2100. {
  2101. std::string outdatedBoxesList = "The following boxes need to be updated: \n";
  2102. CIdentifier boxID;
  2103. while ((boxID = scenario.getNextOutdatedBoxIdentifier(boxID)) != CIdentifier::undefined())
  2104. {
  2105. const Kernel::IBox* box = scenario.getBoxDetails(boxID);
  2106. outdatedBoxesList += "\t[" + box->getName() + "]\n";
  2107. }
  2108. outdatedBoxesList += "Do you still want to play the scenario ?";
  2109. GtkWidget* dialog = gtk_message_dialog_new(nullptr, GtkDialogFlags(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), GTK_MESSAGE_QUESTION,
  2110. GTK_BUTTONS_YES_NO, "%s", outdatedBoxesList.c_str());
  2111. const gint response = gtk_dialog_run(GTK_DIALOG(dialog));
  2112. gtk_widget_destroy(dialog);
  2113. if (response == GTK_RESPONSE_YES)
  2114. {
  2115. m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "CApplication::playScenarioCB - GTK_RESPONSE_YES: the scenario will be played. \n";
  2116. }
  2117. else
  2118. {
  2119. m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "CApplication::playScenarioCB - the scenario will not be played. \n";
  2120. return;
  2121. }
  2122. }
  2123. }
  2124. }
  2125. if (!this->createPlayer())
  2126. {
  2127. m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "The initialization of player failed. Check the above log messages to get the issue.\n";
  2128. return;
  2129. }
  2130. if (!this->getPlayer()->play())
  2131. {
  2132. this->stopInterfacedScenarioAndReleasePlayer(this->getCurrentInterfacedScenario());
  2133. return;
  2134. }
  2135. this->getCurrentInterfacedScenario()->m_PlayerStatus = this->getPlayer()->getStatus();
  2136. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), true);
  2137. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), true);
  2138. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_next")), true);
  2139. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), true);
  2140. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), false);
  2141. gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), GTK_STOCK_MEDIA_PAUSE);
  2142. if (m_CmdLineFlags & CommandLineFlag_NoVisualization) { for (auto& iScenario : m_Scenarios) { iScenario->hideCurrentVisualization(); } }
  2143. }
  2144. void CApplication::forwardScenarioCB()
  2145. {
  2146. m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "forwardScenarioCB\n";
  2147. if (!this->createPlayer())
  2148. {
  2149. m_kernelCtx.getLogManager() << Kernel::LogLevel_Error << "CreatePlayer failed\n";
  2150. return;
  2151. }
  2152. if (!this->getPlayer()->forward())
  2153. {
  2154. this->stopInterfacedScenarioAndReleasePlayer(this->getCurrentInterfacedScenario());
  2155. return;
  2156. }
  2157. this->getCurrentInterfacedScenario()->m_PlayerStatus = this->getPlayer()->getStatus();
  2158. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), true);
  2159. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), true);
  2160. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_next")), true);
  2161. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), false);
  2162. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), false);
  2163. gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), GTK_STOCK_MEDIA_PLAY);
  2164. if (m_CmdLineFlags & CommandLineFlag_NoVisualization) { for (auto& iScenario : m_Scenarios) { iScenario->hideCurrentVisualization(); } }
  2165. }
  2166. bool CApplication::quitApplicationCB()
  2167. {
  2168. CIdentifier id;
  2169. m_kernelCtx.getLogManager() << Kernel::LogLevel_Debug << "quitApplicationCB\n";
  2170. // can't quit while scenarios are running
  2171. if (this->hasRunningScenario())
  2172. {
  2173. GtkBuilder* builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "about", nullptr);
  2174. gtk_builder_add_from_file(builder, OVD_GUI_File, nullptr);
  2175. gtk_builder_connect_signals(builder, nullptr);
  2176. GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "dialog_running_scenario_global"));
  2177. gtk_builder_connect_signals(builder, nullptr);
  2178. // gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE, true);
  2179. gtk_dialog_run(GTK_DIALOG(dialog));
  2180. gtk_widget_destroy(dialog);
  2181. g_object_unref(builder);
  2182. // prevent Gtk from handling delete_event and killing app
  2183. return false;
  2184. }
  2185. // can't quit while scenarios are unsaved
  2186. if (this->hasUnsavedScenario())
  2187. {
  2188. GtkBuilder* builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "about", nullptr);
  2189. gtk_builder_add_from_file(builder, OVD_GUI_File, nullptr);
  2190. gtk_builder_connect_signals(builder, nullptr);
  2191. GtkWidget* dialog = GTK_WIDGET(gtk_builder_get_object(builder, "dialog_unsaved_scenario_global"));
  2192. gtk_builder_connect_signals(builder, nullptr);
  2193. const gint responseId = gtk_dialog_run(GTK_DIALOG(dialog));
  2194. gtk_widget_destroy(dialog);
  2195. g_object_unref(builder);
  2196. switch (responseId)
  2197. {
  2198. case GTK_RESPONSE_OK:
  2199. for (auto i = m_Scenarios.begin(); i != m_Scenarios.end(); ++i) { this->saveScenarioCB(*i); }
  2200. if (this->hasUnsavedScenario())
  2201. {
  2202. // prevent Gtk from handling delete_event and killing app
  2203. return false;
  2204. }
  2205. break;
  2206. case GTK_RESPONSE_DELETE_EVENT:
  2207. case GTK_RESPONSE_CANCEL:
  2208. // prevent Gtk from handling delete_event and killing app
  2209. return false;
  2210. default:
  2211. break;
  2212. }
  2213. }
  2214. // Switch to quitting mode
  2215. m_IsQuitting = true;
  2216. // Saves opened scenarios
  2217. this->saveOpenedScenarios();
  2218. // Clears all existing interfaced scenarios
  2219. for (auto interfacedScenario : m_Scenarios) { delete interfacedScenario; }
  2220. // Clears all existing scenarios
  2221. std::vector<CIdentifier> scenarioIDs;
  2222. while ((id = m_kernelCtx.getScenarioManager().getNextScenarioIdentifier(id)) != CIdentifier::undefined()) { scenarioIDs.push_back(id); }
  2223. for (auto& scenario : scenarioIDs) { m_kernelCtx.getScenarioManager().releaseScenario(scenario); }
  2224. // release the log manager and free the memory
  2225. if (m_logListener)
  2226. {
  2227. m_kernelCtx.getLogManager().removeListener(m_logListener);
  2228. delete m_logListener;
  2229. m_logListener = nullptr;
  2230. }
  2231. // OK to kill app
  2232. return true;
  2233. }
  2234. void CApplication::windowStateChangedCB(const bool isMaximized)
  2235. {
  2236. if (m_isMaximized != isMaximized && !isMaximized) // we switched to not maximized
  2237. {
  2238. //gtk_paned_set_position(GTK_PANED(gtk_builder_get_object(m_builderInterface, "openvibe-horizontal_container")), 640);
  2239. gtk_window_resize(GTK_WINDOW(m_MainWindow), 1024, 768);
  2240. }
  2241. m_isMaximized = isMaximized;
  2242. }
  2243. void CApplication::logLevelCB() const
  2244. {
  2245. // Loads log level dialog
  2246. GtkBuilder* builder = gtk_builder_new(); // glade_xml_new(OVD_GUI_File, "loglevel", nullptr);
  2247. gtk_builder_add_from_file(builder, OVD_GUI_File, nullptr);
  2248. gtk_builder_connect_signals(builder, nullptr);
  2249. gtk_toggle_button_set_active(
  2250. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_fatal")),
  2251. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Fatal));
  2252. gtk_toggle_button_set_active(
  2253. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_error")),
  2254. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Error));
  2255. gtk_toggle_button_set_active(
  2256. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_important_warning")),
  2257. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_ImportantWarning));
  2258. gtk_toggle_button_set_active(
  2259. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_warning")),
  2260. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Warning));
  2261. gtk_toggle_button_set_active(
  2262. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_info")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Info));
  2263. gtk_toggle_button_set_active(
  2264. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_trace")),
  2265. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Trace));
  2266. gtk_toggle_button_set_active(
  2267. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_benchmark")),
  2268. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Benchmark));
  2269. gtk_toggle_button_set_active(
  2270. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_debug")),
  2271. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Debug));
  2272. GtkDialog* logLevelDialog = GTK_DIALOG(gtk_builder_get_object(builder, "loglevel"));
  2273. const gint result = gtk_dialog_run(logLevelDialog);
  2274. if (result == GTK_RESPONSE_APPLY)
  2275. {
  2276. m_kernelCtx.getLogManager().activate(
  2277. Kernel::LogLevel_Fatal,
  2278. gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_fatal"))) != 0);
  2279. m_kernelCtx.getLogManager().activate(
  2280. Kernel::LogLevel_Error,
  2281. gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_error"))) != 0);
  2282. m_kernelCtx.getLogManager().activate(Kernel::LogLevel_ImportantWarning,
  2283. gtk_toggle_button_get_active(
  2284. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_important_warning"))) != 0);
  2285. m_kernelCtx.getLogManager().activate(Kernel::LogLevel_Warning,
  2286. gtk_toggle_button_get_active(
  2287. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_warning"))) != 0);
  2288. m_kernelCtx.getLogManager().activate(
  2289. Kernel::LogLevel_Info,
  2290. gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_info"))) != 0);
  2291. m_kernelCtx.getLogManager().activate(
  2292. Kernel::LogLevel_Trace,
  2293. gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_trace"))) != 0);
  2294. m_kernelCtx.getLogManager().activate(Kernel::LogLevel_Benchmark,
  2295. gtk_toggle_button_get_active(
  2296. GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_benchmark"))) != 0);
  2297. m_kernelCtx.getLogManager().activate(
  2298. Kernel::LogLevel_Debug,
  2299. gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "loglevel-checkbutton_loglevel_debug"))) != 0);
  2300. gtk_widget_set_sensitive(
  2301. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_debug")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Debug));
  2302. gtk_widget_set_sensitive(
  2303. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_bench")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Benchmark));
  2304. gtk_widget_set_sensitive(
  2305. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_trace")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Trace));
  2306. gtk_widget_set_sensitive(
  2307. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_info")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Info));
  2308. gtk_widget_set_sensitive(
  2309. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_warning")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Warning));
  2310. gtk_widget_set_sensitive(
  2311. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_impwarning")),
  2312. m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_ImportantWarning));
  2313. gtk_widget_set_sensitive(
  2314. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_error")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Error));
  2315. gtk_widget_set_sensitive(
  2316. GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-messages_tb_fatal")), m_kernelCtx.getLogManager().isActive(Kernel::LogLevel_Fatal));
  2317. }
  2318. gtk_widget_destroy(GTK_WIDGET(logLevelDialog));
  2319. g_object_unref(builder);
  2320. }
  2321. void CApplication::cpuUsageCB()
  2322. {
  2323. CInterfacedScenario* scenario = getCurrentInterfacedScenario();
  2324. if (scenario)
  2325. {
  2326. scenario->m_DebugCPUUsage = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage"))) != 0
  2327. );
  2328. scenario->redraw();
  2329. }
  2330. }
  2331. void CApplication::changeCurrentScenario(const int pageIdx)
  2332. {
  2333. if (m_IsQuitting) { return; }
  2334. //hide window manager of previously active scenario, if any
  2335. const int i = gtk_notebook_get_current_page(m_scenarioNotebook);
  2336. if (i >= 0 && i < int(m_Scenarios.size())) { m_Scenarios[i]->hideCurrentVisualization(); }
  2337. //closing last open scenario
  2338. if (pageIdx == -1)
  2339. {
  2340. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), false);
  2341. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), false);
  2342. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_next")), false);
  2343. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), false);
  2344. gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), GTK_STOCK_MEDIA_PLAY);
  2345. g_signal_handlers_disconnect_by_func(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), G_CALLBACK2(cpu_usage_cb), this);
  2346. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), false);
  2347. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), false);
  2348. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), "toggled", G_CALLBACK(cpu_usage_cb), this);
  2349. //toggle off window manager button
  2350. GtkWidget* windowManagerButton = GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager"));
  2351. g_signal_handlers_disconnect_by_func(windowManagerButton, G_CALLBACK2(button_toggle_window_manager_cb), this);
  2352. gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(windowManagerButton), false);
  2353. g_signal_connect(windowManagerButton, "toggled", G_CALLBACK(button_toggle_window_manager_cb), this);
  2354. // toggle off and reset scenario settings
  2355. GtkWidget* settingsVBox = GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-scenario_configuration_vbox"));
  2356. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-scenario_configuration_button_configure")), false);
  2357. GList* settingWidgets = gtk_container_get_children(GTK_CONTAINER(gtk_builder_get_object(m_Builder, "openvibe-scenario_configuration_vbox")));
  2358. for (GList* settingIterator = settingWidgets; settingIterator != nullptr; settingIterator = g_list_next(settingIterator))
  2359. {
  2360. gtk_widget_destroy(GTK_WIDGET(settingIterator->data));
  2361. }
  2362. g_list_free(settingWidgets);
  2363. GtkWidget* settingPlaceholderLabel = gtk_label_new("This scenario has no settings");
  2364. gtk_box_pack_end_defaults(GTK_BOX(settingsVBox), settingPlaceholderLabel);
  2365. gtk_widget_show_all(settingsVBox);
  2366. // current scenario is the current notebook page.
  2367. m_currentScenarioIdx = i;
  2368. }
  2369. //switching to an existing scenario
  2370. else if (pageIdx < m_Scenarios.size())
  2371. {
  2372. CInterfacedScenario* scenario = m_Scenarios[pageIdx];
  2373. const Kernel::EPlayerStatus playerStatus = (scenario->m_Player ? scenario->m_Player->getStatus() : Kernel::EPlayerStatus::Stop);
  2374. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), playerStatus != Kernel::EPlayerStatus::Stop);
  2375. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), true);
  2376. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_next")), true);
  2377. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), playerStatus != Kernel::EPlayerStatus::Forward);
  2378. gtk_tool_button_set_stock_id(
  2379. GTK_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")),
  2380. (playerStatus == Kernel::EPlayerStatus::Stop || playerStatus == Kernel::EPlayerStatus::Pause) ? GTK_STOCK_MEDIA_PLAY : GTK_STOCK_MEDIA_PAUSE);
  2381. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_undo")), scenario->m_StateStack->isUndoPossible());
  2382. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_redo")), scenario->m_StateStack->isRedoPossible());
  2383. g_signal_handlers_disconnect_by_func(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), G_CALLBACK2(cpu_usage_cb), this);
  2384. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), playerStatus == Kernel::EPlayerStatus::Stop);
  2385. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), scenario->m_DebugCPUUsage);
  2386. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), "toggled", G_CALLBACK(cpu_usage_cb), this);
  2387. // gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_builderInterface, "openvibe-button_save")), scenario->m_hasFileName && scenario->m_hasBeenModified);
  2388. // gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_builderInterface, "openvibe-menu_save")), scenario->m_hasFileName && scenario->m_hasBeenModified);
  2389. //don't show window manager if in offline mode and it is toggled off
  2390. if (playerStatus == Kernel::EPlayerStatus::Stop && !m_Scenarios[pageIdx]->isDesignerVisualizationToggled())
  2391. {
  2392. m_Scenarios[pageIdx]->hideCurrentVisualization();
  2393. // we are in edition mode, updating internal configuration token
  2394. std::string path = m_Scenarios[pageIdx]->m_Filename;
  2395. path = path.substr(0, path.rfind('/'));
  2396. m_kernelCtx.getConfigurationManager().setConfigurationTokenValue(
  2397. m_kernelCtx.getConfigurationManager().lookUpConfigurationTokenIdentifier("Player_ScenarioDirectory"), path.c_str());
  2398. m_kernelCtx.getConfigurationManager().setConfigurationTokenValue(
  2399. m_kernelCtx.getConfigurationManager().lookUpConfigurationTokenIdentifier("__volatile_ScenarioDir"), path.c_str());
  2400. }
  2401. else { m_Scenarios[pageIdx]->showCurrentVisualization(); }
  2402. //update window manager button state
  2403. GtkWidget* windowMgrButton = GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager"));
  2404. g_signal_handlers_disconnect_by_func(windowMgrButton, G_CALLBACK2(button_toggle_window_manager_cb), this);
  2405. gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(windowMgrButton), m_Scenarios[pageIdx]->isDesignerVisualizationToggled());
  2406. g_signal_connect(windowMgrButton, "toggled", G_CALLBACK(button_toggle_window_manager_cb), this);
  2407. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-scenario_configuration_button_configure")), true);
  2408. m_Scenarios[pageIdx]->redrawScenarioSettings();
  2409. m_Scenarios[pageIdx]->redrawScenarioInputSettings();
  2410. m_Scenarios[pageIdx]->redrawScenarioOutputSettings();
  2411. // current scenario is the selected one
  2412. m_currentScenarioIdx = pageIdx;
  2413. }
  2414. //first scenario is created (or a scenario is opened and replaces first unnamed unmodified scenario)
  2415. else
  2416. {
  2417. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_stop")), false);
  2418. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), true);
  2419. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_next")), true);
  2420. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_forward")), true);
  2421. gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-button_play_pause")), GTK_STOCK_MEDIA_PLAY);
  2422. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_undo")), false);
  2423. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_redo")), false);
  2424. g_signal_handlers_disconnect_by_func(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), G_CALLBACK2(cpu_usage_cb), this);
  2425. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager")), true);
  2426. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), false);
  2427. g_signal_connect(G_OBJECT(gtk_builder_get_object(m_Builder, "openvibe-togglebutton_cpu_usage")), "toggled", G_CALLBACK(cpu_usage_cb), this);
  2428. //toggle off window manager button
  2429. GtkWidget* windowMgrButton = GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-button_windowmanager"));
  2430. g_signal_handlers_disconnect_by_func(windowMgrButton, G_CALLBACK2(button_toggle_window_manager_cb), this);
  2431. gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(windowMgrButton), false);
  2432. g_signal_connect(windowMgrButton, "toggled", G_CALLBACK(button_toggle_window_manager_cb), this);
  2433. gtk_widget_set_sensitive(GTK_WIDGET(gtk_builder_get_object(m_Builder, "openvibe-scenario_configuration_button_configure")), true);
  2434. // we have a new notebook page
  2435. m_currentScenarioIdx = pageIdx;
  2436. // we are in edition mode, updating internal configuration token
  2437. m_kernelCtx.getConfigurationManager().setConfigurationTokenValue(
  2438. m_kernelCtx.getConfigurationManager().lookUpConfigurationTokenIdentifier("Player_ScenarioDirectory"), "");
  2439. m_kernelCtx.getConfigurationManager().setConfigurationTokenValue(
  2440. m_kernelCtx.getConfigurationManager().lookUpConfigurationTokenIdentifier("__volatile_ScenarioDir"), "");
  2441. }
  2442. // updates the trimming if need be
  2443. for (auto& scenario : m_Scenarios) { scenario->updateScenarioLabel(); }
  2444. // Reset zoom
  2445. if (getCurrentInterfacedScenario())
  2446. {
  2447. gtk_spin_button_set_value(
  2448. GTK_SPIN_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-zoom_spinner")), round(getCurrentInterfacedScenario()->getScale() * 100.0));
  2449. }
  2450. else { gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-zoom_spinner")), 100); }
  2451. }
  2452. void CApplication::reorderCurrentScenario(const size_t newPageIdx)
  2453. {
  2454. CInterfacedScenario* scenario = m_Scenarios[m_currentScenarioIdx];
  2455. m_Scenarios.erase(m_Scenarios.begin() + m_currentScenarioIdx);
  2456. m_Scenarios.insert(m_Scenarios.begin() + newPageIdx, scenario);
  2457. this->changeCurrentScenario(newPageIdx);
  2458. }
  2459. //Increase the zoom of the current scenario
  2460. void CApplication::zoomInCB()
  2461. {
  2462. gtk_spin_button_set_value(
  2463. GTK_SPIN_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-zoom_spinner")), round(getCurrentInterfacedScenario()->getScale() * 100.0) + 5);
  2464. }
  2465. //Decrease the zoom of the current scenario
  2466. void CApplication::zoomOutCB()
  2467. {
  2468. gtk_spin_button_set_value(
  2469. GTK_SPIN_BUTTON(gtk_builder_get_object(m_Builder, "openvibe-zoom_spinner")), round(getCurrentInterfacedScenario()->getScale() * 100.0) - 5);
  2470. }
  2471. void CApplication::spinnerZoomChangedCB(const size_t scaleDelta)
  2472. {
  2473. if (getCurrentInterfacedScenario() != nullptr) { getCurrentInterfacedScenario()->setScale(double(scaleDelta) / 100.0); }
  2474. }
  2475. void CApplication::cannotSaveScenarioBeforeUpdate()
  2476. {
  2477. const CString message = "Cannot save a scenario if deprecated I/O or Settings are still pending.\n"
  2478. "Please handle or delete all pending deprecated I/O before saving scenario.";
  2479. GtkWidget* dialog = gtk_message_dialog_new(nullptr, GtkDialogFlags(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
  2480. "%s", message.toASCIIString());
  2481. gtk_dialog_run(GTK_DIALOG(dialog));
  2482. gtk_widget_destroy(dialog);
  2483. }
  2484. } //namespace Designer
  2485. } //namespace OpenViBE