Author Topic: [SOLVED]request for a new CodeblocksEvent type : end of a 'multiple files add'  (Read 18103 times)

Offline orel

  • Multiple posting newcomer
  • *
  • Posts: 96
Hi CB developers !!

I am requesting a new CodeblocksEvent type since i can't find a correct way to do one thing, i don't know if this new type would be useful to other plugin developers. I give myself the permission to request it because for sure it would be very easy to implement!

I am currently developing SVNInside, an plugin integrating svn in CB and i fall on the following problem :

I registered cbEVT_PROJECT_FILE_ADDED in SVNInside because i need to refresh the svn tree of the project when a file is added, then i must execute an 'svn status' command asynchronously on the newly added file in order to display its current svn status. What i am actually doing is calling 'svn status' on every file of the project, thus refreshing the whole svn tree while having the status of the newly added file.
The difference in time between calling 'svn status' on one file or on all project files is relatively the same because the most time is taken by creating a new process and waiting for its output. That's why i am refreshing the whole project.

As executing such a command asyncronously takes a relatively long time, it really freezes CB when the user add multiple files because i have no clue when all files are added!!

I have 2 solutions for the moment :
     
  • refreshing the whole tree after receiving each cbEVT_PROJECT_FILE_ADDED --> very long
  • finding a hack that gets the time between each cbEVT_PROJECT_FILE_ADDED event and then calling 'svn status' when this value is more than a well-chosen step !! but this solution won't work each case and like i said it is really a hack and bad programming


What would really change my life :D would be to register against a new CB_evt telling me when all files as been added. Its little name could be something like cbEVT_PROJECT_ALL_FILES_ADDED !!
You see, i event found a name for you !! This event would be sent at the end of the for loop sending each cbEVT_PROJECT_FILE_ADDED in ProjectManager::AddMultipleFilesToProject ().

What do you CB developers think of that, or any solution i could implement to make this trick easier?
« Last Edit: December 10, 2007, 11:44:25 am by orel »
windows XP SP2
mingw gcc 3.4.5
svn Code::Blocks and M$ Visual Studio 2005 and .NET to eat!! SVNInside plugin :http://forums.codeblocks.org/index.php/topic,7063.0.html

Offline kkez

  • Almost regular
  • **
  • Posts: 153
    • WinapiZone
If it's not hard to add the event, then i would go that way.

If it's not so easy, this is my solution:
1) start a timer each time a file is added (5 seconds can be the time span)
2) if a file is added and the timer is on, cancel the timer and recreate it (or simply reset it)
3) at the end of the timer, refresh the svn tree

I don't know if there's a timer/countdown class in wxwidgets, i hope so..

Offline Pecan

  • Plugin developer
  • Lives here!
  • ****
  • Posts: 2778
I've found these hooks to be helpful:

    // -- Project events
    // EVT_PROJECT_OPEN(       BrowseTracker::OnProjectOpened)
    ////Manager::Get()->RegisterEventSink(cbEVT_PROJECT_OPEN, new cbEventFunctor<BrowseTracker, CodeBlocksEvent>(this, &BrowseTracker::OnProjectOpened));
    // EVT_PROJECT_ACTIVATE(   BrowseTracker::OnProjectActivated)
    Manager::Get()->RegisterEventSink(cbEVT_PROJECT_ACTIVATE, new cbEventFunctor<BrowseTracker, CodeBlocksEvent>(this, &BrowseTracker::OnProjectActivated));

Offline orel

  • Multiple posting newcomer
  • *
  • Posts: 96
Kkez :

your solution with the timer is exactly the same than my second one :D. That's not that bad but i don't like those sort of hack because my svn command won't be executed before the timer ends. It is really a loss of time, even in an asynchronous process. Maybe you will find i am little bit dandy with that !

I've found these hooks to be helpful:

    // -- Project events
    // EVT_PROJECT_OPEN(       BrowseTracker::OnProjectOpened)
    ////Manager::Get()->RegisterEventSink(cbEVT_PROJECT_OPEN, new cbEventFunctor<BrowseTracker, CodeBlocksEvent>(this, &BrowseTracker::OnProjectOpened));
    // EVT_PROJECT_ACTIVATE(   BrowseTracker::OnProjectActivated)
    Manager::Get()->RegisterEventSink(cbEVT_PROJECT_ACTIVATE, new cbEventFunctor<BrowseTracker, CodeBlocksEvent>(this, &BrowseTracker::OnProjectActivated));

How will this help me with my problem?? :shock:
windows XP SP2
mingw gcc 3.4.5
svn Code::Blocks and M$ Visual Studio 2005 and .NET to eat!! SVNInside plugin :http://forums.codeblocks.org/index.php/topic,7063.0.html

Offline kkez

  • Almost regular
  • **
  • Posts: 153
    • WinapiZone
your solution with the timer is exactly the same than my second one :D. That's not that bad but i don't like those sort of hack because my svn command won't be executed before the timer ends. It is really a loss of time, even in an asynchronous process. Maybe you will find i am little bit dandy with that !
Well, no. I don't "get the time between each cbEVT_PROJECT_FILE_ADDED event", i hardcode it (which is easier and safe, why should a file take 5 seconds to be added?)

Quote
That's not that bad but i don't like those sort of hack because my svn command won't be executed before the timer ends. Maybe you will find i am little bit dandy with that !
:)
« Last Edit: November 30, 2007, 12:02:00 pm by kkez »

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Nasty hack, I think. I'm against such a message, not only because I think it's not necessary, but there is no good way to implement it either.
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

Offline orel

  • Multiple posting newcomer
  • *
  • Posts: 96
cb_EVT               cb_EVT
  |                        |                              |  svn command execution
  |                        |                              |
---------------------------------------------------------------------------->
  |<-------- 5s -------->|                       |                                             time
  |                       |<-------- 5s -------->|
  |                       |                               |
timer start            |                               |
                    timer start                   timer end


Well, no. I don't "get the time between each cbEVT_PROJECT_FILE_ADDED event", i hardcode it (which is easier and safe, )

Even if YOU don't 'get the time between each cbEVT_PROJECT_FILE_ADDED', the timer does. So i don't understand the difference between hardcoding this timer and reseting it when receiving the event, and measuring the time between the events and seeing if it is less than an hardcoded value!!!  :D  To me it is really the same or i am not getting it at all !!

why should a file take 5 seconds to be added?

Because as you see in the diagram, you have to wait at least 5 seconds to execute the command. Those 5 seconds represents the timer expiration needed to understand that no more file will be added.

Nasty hack, I think.
Which hack are you talking about? the one with the timer or the one with the new message.

I'm against such a message, not only because I think it's not necessary, but there is no good way to implement it either.

I really don't want to insist but why there is no good way to implement it?
You only have to send this event once, when all files has been added, as I said at the end of the for loop in ProjectManager::AddMultipleFilesToProject ()
windows XP SP2
mingw gcc 3.4.5
svn Code::Blocks and M$ Visual Studio 2005 and .NET to eat!! SVNInside plugin :http://forums.codeblocks.org/index.php/topic,7063.0.html

Offline MortenMacFly

  • Administrator
  • Lives here!
  • *****
  • Posts: 9694
You only have to send this event once, when all files has been added, as I said at the end of the for loop in ProjectManager::AddMultipleFilesToProject ()
If that's all, please provide a patch accordingly. But I see a drawback: One could think it's good to listen to both: cbEVT_PROJECT_FILE_ADDED and cbEVT_PROJECT_MULTIPLE_FILES_ADDED. In both cases when the last file is added an operation listening on both would be executed two times.
Compiler logging: Settings->Compiler & Debugger->tab "Other"->Compiler logging="Full command line"
C::B Manual: https://www.codeblocks.org/docs/main_codeblocks_en.html
C::B FAQ: https://wiki.codeblocks.org/index.php?title=FAQ

Offline orel

  • Multiple posting newcomer
  • *
  • Posts: 96
You only have to send this event once, when all files has been added, as I said at the end of the for loop in ProjectManager::AddMultipleFilesToProject ()
If that's all, please provide a patch accordingly. But I see a drawback: One could think it's good to listen to both: cbEVT_PROJECT_FILE_ADDED and cbEVT_PROJECT_MULTIPLE_FILES_ADDED. In both cases when the last file is added an operation listening on both would be executed two times.

Thank you Morten, i will provide a little patch tonight when i come back from work. Yes that's exactly all i need. For the drawback, it is not clearly one, because those messages are not giving at all the same kind of information about the soft. To me, one gives you the name of the last added file while the other gives you a clue about CodeBlocks current status (here : CB saying i'm done adding new file to one project!!).
windows XP SP2
mingw gcc 3.4.5
svn Code::Blocks and M$ Visual Studio 2005 and .NET to eat!! SVNInside plugin :http://forums.codeblocks.org/index.php/topic,7063.0.html

Offline kkez

  • Almost regular
  • **
  • Posts: 153
    • WinapiZone
Since i don't know how it's coded, here's another solution: we could send from Code::Blocks a cbEVT_PROJECT_MULTIPLE_FILES_ARE_GOING_TO_BE_ADDED event (sorry for the name) which only sends the number of files that will be added. Then one listen to every cbEVT_PROJECT_FILE_ADDED and on the last he can do whatever he want. Nasty hack too, but it should be doable..

why should a file take 5 seconds to be added?

Because as you see in the diagram, you have to wait at least 5 seconds to execute the command. Those 5 seconds represents the timer expiration needed to understand that no more file will be added.
Mine was a justification for the "5 seconds" span. What i meant is: there's no file that will take 5 seconds to load, so waiting 5 seconds is safe.

Offline Biplab

  • Developer
  • Lives here!
  • *****
  • Posts: 1874
    • Biplab's Blog
There is another alternative. Extend the function ProjectManager::IsBusy() to incorporate this. This function would return true while loading multiple files. You should then add the file specified by cbEVT_PROJECT_FILE_ADDED to a list that will be processed once the ProjectManager::IsBusy() returns false. This would prevent the addition of another rarely used event.

Edit 1: Or addition of one extra SDK function would do the job (something like ProjectManager::IsLoadingProjectFiles()).
« Last Edit: November 30, 2007, 05:36:54 pm by Biplab »
Be a part of the solution, not a part of the problem.

Offline orel

  • Multiple posting newcomer
  • *
  • Posts: 96
There is another alternative. Extend the function ProjectManager::IsBusy() to incorporate this. This function would return true while loading multiple files. You should then add the file specified by cbEVT_PROJECT_FILE_ADDED to a list that will be processed once the ProjectManager::IsBusy() returns false. This would prevent the addition of another rarely used event.
Why not? I will let the developers find the best way to do that, i will provide a patch for the new event tonight and let them choose!


Edit 1: Or addition of one extra SDK function would do the job (something like ProjectManager::IsLoadingProjectFiles()).
A function just for that purpose? I am not sure, this would prevent the addition of another rarely used function :)


windows XP SP2
mingw gcc 3.4.5
svn Code::Blocks and M$ Visual Studio 2005 and .NET to eat!! SVNInside plugin :http://forums.codeblocks.org/index.php/topic,7063.0.html

Offline Biplab

  • Developer
  • Lives here!
  • *****
  • Posts: 1874
    • Biplab's Blog
Edit 1: Or addition of one extra SDK function would do the job (something like ProjectManager::IsLoadingProjectFiles()).
A function just for that purpose? I am not sure, this would prevent the addition of another rarely used function :)

There's a difference. An event will always be fired irrespective of anyone needs it or not. On the other hand the *extra* function would not be used unless someone calls it.
Be a part of the solution, not a part of the problem.

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
There is no way the IDE can know reliably that several files will be added.

Martin's proposal about sending an event in AddMultipleFilesToProject() is a possibility to reduce some workload, but that one is problematic too. For correct operation, the IDE would have to skip the files on cbEVT_PROJECT_FILE_ADDED if an event has already sent, else you cannot listen to single files being added.
Or, you would have to keep a list yourself, or... some other thing.

The solution proposed by kkez (sending a BEGIN and END event at the beginning/end of AddMultipleFilesToProject()) would likely work in the most reliable way, and if anything really must be implemented, this is what I'd go for, since it involves the least hacks and tampering, and it will be compatible with the old path.

Still, it does not solve the problem either, it can only reduce some of the workload. To solve your problem, the IDE must know when the user starts adding files and when the user no longer does so. This really could only be implemented if the user was required to press a "finish" button when he is done (no thank you!) or with a timer hack, which is... well... a hack.

On the other hand, running svn status asynchronously is quite acceptable, and if that's rate-limited, no excessive overhead occurs.
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

Offline orel

  • Multiple posting newcomer
  • *
  • Posts: 96
The solution proposed by kkez (sending a BEGIN and END event at the beginning/end of AddMultipleFilesToProject()) would likely work in the most reliable way, and if anything really must be implemented, this is what I'd go for, since it involves the least hacks and tampering, and it will be compatible with the old path.

I really find this solution the best without changing too many things in the current CB code. So i am finally coming with a little patch to implement both new events.
I named them cbEVT_PROJECT_FILES_ADDED_BEGIN and cbEVT_PROJECT_FILES_ADDED_END, i couldn't find best names that are shorter!!

Code
    if (addedFiles.GetCount() != 0)
    {
        // send the event indicating files are going to be added
        CodeBlocksEvent begin_event(cbEVT_PROJECT_FILES_ADDED_BEGIN);
        begin_event.SetProject(project);
        begin_event.SetInt(addedFiles.GetCount());
        Manager::Get()->GetPluginManager()->NotifyPlugins(begin_event);

        for (unsigned int i = 0; i < addedFiles.GetCount(); ++i)
        {
            CodeBlocksEvent event(cbEVT_PROJECT_FILE_ADDED);
            event.SetProject(project);
            event.SetString(addedFiles[i]);
            Manager::Get()->GetPluginManager()->NotifyPlugins(event);
        }

        // send the event indicating the end of files addition
        CodeBlocksEvent end_event(cbEVT_PROJECT_FILES_ADDED_END);
        end_event.SetProject(project);
        end_event.SetInt(addedFiles.GetCount());
        Manager::Get()->GetPluginManager()->NotifyPlugins(end_event);
    }

So this event is fired before the for loop adding the files and sending cbEVT_PROJECT_FILE_ADDED for each. The only data inside those events are

  • the number of files to be added (sent via event.SetInt()
  • the project to which files are added (sent via event.SetProject())

So, in client code, to make the difference between a single or multiple files add you just have to set a flag when receiving cbEVT_PROJECT_FILES_ADDED_BEGIN. Thus in your cbEVT_PROJECT_FILE_ADDED handler, if this flag is set you skip the event and treat the addition of files when cbEVT_PROJECT_FILES_ADDED_END is here.
This way this will be very simple to call svn status, only once, whan all is done !! i would really be glad if this patch is added :)

So here it is (patch against .../CBMAINDIR/src/)

Code
Index: include/sdk_events.h
===================================================================
--- include/sdk_events.h (revision 4693)
+++ include/sdk_events.h (working copy)
@@ -59,7 +59,7 @@
  // for some editor events
  int m_X;
  int m_Y;
-
+
  wxString m_TargetName;
  wxString m_OldTargetName;
  private:
@@ -237,6 +237,10 @@
 #define EVT_PROJECT_ACTIVATE(fn) DECLARE_EVENT_TABLE_ENTRY( cbEVT_PROJECT_ACTIVATE, -1, -1, (wxObjectEventFunction)(wxEventFunction)(CodeBlocksEventFunction)&fn, (wxObject *) NULL ),
 extern EVTIMPORT const wxEventType cbEVT_PROJECT_FILE_ADDED;
 #define EVT_PROJECT_FILE_ADDED(fn) DECLARE_EVENT_TABLE_ENTRY( cbEVT_PROJECT_FILE_ADDED, -1, -1, (wxObjectEventFunction)(wxEventFunction)(CodeBlocksEventFunction)&fn, (wxObject *) NULL ),
+extern EVTIMPORT const wxEventType cbEVT_PROJECT_FILES_ADDED_BEGIN;
+#define cbEVT_PROJECT_FILES_ADDED_BEGIN(fn) DECLARE_EVENT_TABLE_ENTRY( cbEVT_PROJECT_FILES_ADDED_BEGIN, -1, -1, (wxObjectEventFunction)(wxEventFunction)(CodeBlocksEventFunction)&fn, (wxObject *) NULL ),
+extern EVTIMPORT const wxEventType cbEVT_PROJECT_FILES_ADDED_END;
+#define cbEVT_PROJECT_FILES_ADDED_END(fn) DECLARE_EVENT_TABLE_ENTRY( cbEVT_PROJECT_FILES_ADDED_END, -1, -1, (wxObjectEventFunction)(wxEventFunction)(CodeBlocksEventFunction)&fn, (wxObject *) NULL ),
 extern EVTIMPORT const wxEventType cbEVT_PROJECT_FILE_REMOVED;
 #define EVT_PROJECT_FILE_REMOVED(fn) DECLARE_EVENT_TABLE_ENTRY( cbEVT_PROJECT_FILE_REMOVED, -1, -1, (wxObjectEventFunction)(wxEventFunction)(CodeBlocksEventFunction)&fn, (wxObject *) NULL ),
 extern EVTIMPORT const wxEventType cbEVT_PROJECT_POPUP_MENU;
Index: sdk/projectmanager.cpp
===================================================================
--- sdk/projectmanager.cpp (revision 4693)
+++ sdk/projectmanager.cpp (working copy)
@@ -1380,6 +1380,12 @@
 
     if (addedFiles.GetCount() != 0)
     {
+        // send the event indicating files are going to be added
+        CodeBlocksEvent begin_event(cbEVT_PROJECT_FILES_ADDED_BEGIN);
+        begin_event.SetProject(project);
+        begin_event.SetInt(addedFiles.GetCount());
+        Manager::Get()->GetPluginManager()->NotifyPlugins(begin_event);
+
         for (unsigned int i = 0; i < addedFiles.GetCount(); ++i)
         {
             CodeBlocksEvent event(cbEVT_PROJECT_FILE_ADDED);
@@ -1387,6 +1393,12 @@
             event.SetString(addedFiles[i]);
             Manager::Get()->GetPluginManager()->NotifyPlugins(event);
         }
+
+        // send the event indicating the end of files addition
+        CodeBlocksEvent end_event(cbEVT_PROJECT_FILES_ADDED_END);
+        end_event.SetProject(project);
+        end_event.SetInt(addedFiles.GetCount());
+        Manager::Get()->GetPluginManager()->NotifyPlugins(end_event);
     }
     return targets.GetCount();
 }
Index: sdk/sdk_events.cpp
===================================================================
--- sdk/sdk_events.cpp (revision 4693)
+++ sdk/sdk_events.cpp (working copy)
@@ -109,6 +109,8 @@
 const wxEventType cbEVT_PROJECT_SAVE = wxNewEventType();
 const wxEventType cbEVT_PROJECT_ACTIVATE = wxNewEventType();
 const wxEventType cbEVT_PROJECT_FILE_ADDED = wxNewEventType();
+const wxEventType cbEVT_PROJECT_FILES_ADDED_BEGIN = wxNewEventType();
+const wxEventType cbEVT_PROJECT_FILES_ADDED_END = wxNewEventType();
 const wxEventType cbEVT_PROJECT_FILE_REMOVED = wxNewEventType();
 const wxEventType cbEVT_PROJECT_POPUP_MENU = wxNewEventType();
 const wxEventType cbEVT_PROJECT_TARGETS_MODIFIED = wxNewEventType();
« Last Edit: November 30, 2007, 10:25:40 pm by orel »
windows XP SP2
mingw gcc 3.4.5
svn Code::Blocks and M$ Visual Studio 2005 and .NET to eat!! SVNInside plugin :http://forums.codeblocks.org/index.php/topic,7063.0.html