
    %
i@                     r   d Z ddlZddlZddlZddlZddlmZ ddlmZ ddlm	Z	 dZ
dZdZdZ ej        e
eee            ej        e
eeed	d
g            G d d          Z G d d          Z G d de          Z G d de          Zedk    r%ddlZej        j                            e           dS dS )aD  Excel IRTDServer implementation.

This module is a functional example of how to implement the IRTDServer interface
in python, using the pywin32 extensions. Further details, about this interface
and it can be found at:
     https://learn.microsoft.com/en-us/previous-versions/office/developer/office-xp/aa140060(v=office.10)
    N)	universal)gencache)COMExceptionz&{00020813-0000-0000-C000-000000000046}      
IRtdServerIRTDUpdateEventc                        e Zd ZdZdgZg dZej        ZdZ	dZ
 fdZd Zd Zd	 Zd
 Zd Zd Zd ZddZd Zd Zd Zd Zd Z xZS )ExcelRTDServera  Base RTDServer class.

    Provides most of the features needed to implement the IRtdServer interface.
    Manages topic adding, removal, and packing up the values for excel.

    Shouldn't be instanciated directly.

    Instead, descendant classes should override the CreateTopic() method.
    Topic objects only need to provide a GetValue() function to play nice here.
    The values given need to be atomic (eg. string, int, float... etc).

    Also note: nothing has been done within this class to ensure that we get
    time to check our topics for updates. I've left that up to the subclass
    since the ways, and needs, of refreshing your topics will vary greatly. For
    example, the sample implementation uses a timer thread to wake itself up.
    Whichever way you choose to do it, your class needs to be able to wake up
    occaisionally, since excel will never call your class without being asked to
    first.

    Excel will communicate with our object in this order:
      1. Excel instanciates our object and calls ServerStart, providing us with
         an IRTDUpdateEvent callback object.
      2. Excel calls ConnectData when it wants to subscribe to a new "topic".
      3. When we have new data to provide, we call the UpdateNotify method of the
         callback object we were given.
      4. Excel calls our RefreshData method, and receives a 2d SafeArray (row-major)
         containing the Topic ids in the 1st dim, and the topic values in the
         2nd dim.
      5. When not needed anymore, Excel will call our DisconnectData to
         unsubscribe from a topic.
      6. When there are no more topics left, Excel will call our ServerTerminate
         method to kill us.

    Throughout, at undetermined periods, Excel will call our Heartbeat
    method to see if we're still alive. It must return a non-zero value, or
    we'll be killed.

    NOTE: By default, excel will at most call RefreshData once every 2 seconds.
          This is a setting that needs to be changed excel-side. To change this,
          you can set the throttle interval like this in the excel VBA object model:
            Application.RTD.ThrottleInterval = 1000 ' milliseconds
    r   )ConnectDataDisconnectData	HeartbeatRefreshDataServerStartServerTerminater   r   c                 |    t                                                       | j        | _        d| _        i | _        dS )ConstructorN)super__init__ALIVEIsAlive_ExcelRTDServer__callbacktopicsself	__class__s    C:\Users\Dell Inspiron 16\Desktop\tws\AgrotaPowerBi\back-agrota-powerbi\mcp-client-agrota\venv\Lib\site-packages\win32com/demos/excelRTDServer.pyr   zExcelRTDServer.__init__   s4    z    c                 f    | j         t          d          | j                                          dS )zCUse the callback we were given to tell excel new data is available.NzCallback excel provided is Nulldesc)r   r   UpdateNotifyr   s    r   SignalExcelzExcelRTDServer.SignalExcel   s6    ?"$EFFFF$$&&&&&r   c                 :   	 |                      |          | j        |<   n/# t          $ r"}t          t	          |                    d}~ww xY wd}| j        |         }|d| j        j        z  }n|                                }|                     |           ||fS )z6Creates a new topic out of the Strings excel gives us.r    NTz# %s: Waiting for update)	CreateTopicr   	Exceptionr   strr   __name__GetValueOnConnectData)r   TopicIDStringsGetNewValueswhyresults         r   r   zExcelRTDServer.ConnectData   s    	.#'#3#3G#<#<DK   	. 	. 	.CHH----	.W%>/$.2IIFF__&&F 	7### |##s     
AAAc                 j    |                      |           || j        v rd| j        |<   | j        |= dS dS )zDeletes the given topic.N)OnDisconnectDatar   r   r,   s     r   r   zExcelRTDServer.DisconnectData   sG    g&&&dk!!#'DK G$$$ "!r   c                     | j         S )z+Called by excel to see if we're still here.)r   r#   s    r   r   zExcelRTDServer.Heartbeat   s
    |r   c                 >   t          | j                  }|                                  dg|z  dg|z  g}t          | j                                                  D ]2\  }}|\  }}||d         |<   |                                |d         |<   3t          |          |fS )a  Packs up the topic values. Called by excel when it's ready for an update.

        Needs to:
          * Return the current number of topics, via the "ByRef" TopicCount
          * Return a 2d SafeArray of the topic data.
            - 1st dim: topic numbers
            - 2nd dim: topic values

        We could do some caching, instead of repacking everytime...
        But this works for demonstration purposes.Nr   r   )lenr   OnRefreshData	enumerateitemsr*   tuple)r   
TopicCountresultsidx	topicdatatopicNumtopics          r   r   zExcelRTDServer.RefreshData   s     %%
 6J&(;< ((9(9(;(;<< 	/ 	/NC'OHe&GAJsO#nn..GAJsOO W~~z))r   c                     | j         | _        |t          d          t          j        j                            d          } ||          | _        |                                  | j        S )zMExcel has just created us... We take its callback for later, and set up shop.Nz Excel did not provide a callbackr    z&{A43788C1-D91B-11D3-8F39-00C04F3651B8})	r   r   r   win32comclientCLSIDToClassGetClassr   OnServerStart)r   CallbackObjectIRTDUpdateEventKlasss      r   r   zExcelRTDServer.ServerStart   sq    z!$FGGGG  (;DD4 
  
 /.~>>|r   c                 F    | j         | _        |                                  dS )z%Called when excel no longer wants us.N)	NOT_ALIVEr   OnServerTerminater#   s    r   r   zExcelRTDServer.ServerTerminate   s#    ~     r   Nc                      t          d          )zTopic factory method. Subclass must override.

        Topic objects need to provide:
          * GetValue() method which returns an atomic value.

        Will raise NotImplemented if not overridden.
        zSubclass must implementNotImplementedr   TopicStringss     r   r&   zExcelRTDServer.CreateTopic   s     6777r   c                     dS )z=Called when a new topic has been created, at excel's request.N r3   s     r   r+   zExcelRTDServer.OnConnectData       r   c                     dS )z?Called when a topic is about to be deleted, at excel's request.NrR   r3   s     r   r2   zExcelRTDServer.OnDisconnectData   rS   r   c                     dS )z7Called when excel has requested all current topic data.NrR   r#   s    r   r7   zExcelRTDServer.OnRefreshData   rS   r   c                     dS )z&Called when excel has instanciated us.NrR   r#   s    r   rF   zExcelRTDServer.OnServerStart   rS   r   c                     dS )z)Called when excel is about to destroy us.NrR   r#   s    r   rK   z ExcelRTDServer.OnServerTerminate  rS   r   N)r)   
__module____qualname____doc___com_interfaces__public_methods_	pythoncomCLSCTX_INPROC_SERVER_reg_clsctx_r   rJ   r   r$   r   r   r   r   r   r   r&   r+   r2   r7   rF   rK   __classcell__r   s   @r   r   r   H   s>       ) )V %~   1L
 EI    ' ' '$ $ $&% % %  * * *@  "! ! !
8 8 8 8              r   r   c                   @     e Zd ZdZ fdZd Zd Zd Zd Zd Z	 xZ
S )RTDTopiczBase RTD Topic.
    Only method required by our RTDServer implementation is GetValue().
    The others are more for convenience.c                 r    t                                                       || _        d | _        d| _        d S )NF)r   r   rP   _RTDTopic__currentValue_RTDTopic__dirty)r   rP   r   s     r   r   zRTDTopic.__init__  s4    ("r   c                      t          d          )zCalled by the RTD Server.
        Gives us a chance to check if our topic data needs to be
        changed (eg. check a file, quiz a database, etc).zsubclass must implementrM   )r   senders     r   UpdatezRTDTopic.Update  s     6777r   c                     d| _         dS )z6Call when this topic isn't considered "dirty" anymore.FNrg   r#   s    r   ResetzRTDTopic.Reset  s    r   c                     | j         S rX   )rf   r#   s    r   r*   zRTDTopic.GetValue  s    ""r   c                 "    d| _         || _        d S )NT)rg   rf   )r   values     r   SetValuezRTDTopic.SetValue  s    #r   c                     | j         S rX   rl   r#   s    r   
HasChangedzRTDTopic.HasChanged#  s
    |r   )r)   rY   rZ   r[   r   rj   rm   r*   rq   rs   ra   rb   s   @r   rd   rd     s        , ,    8 8 8  # # #$ $ $      r   rd   c                   L     e Zd ZdZdZdZdZdZ fdZd Z	d Z
d	 ZddZ xZS )
TimeServeraD  Example Time RTD server.

    Sends time updates back to excel.

    example of use, in an excel sheet:
      =RTD("Python.RTD.TimeServer","","seconds","5")

    This will cause a timestamp string to fill the cell, and update its value
    every 5 seconds (or as close as possible depending on how busy excel is).

    The empty string parameter denotes the com server is running on the local
    machine. Otherwise, put in the hostname to look on. For more info
    on this, lookup the Excel help for its "RTD" worksheet function.

    Obviously, you'd want to wrap this kind of thing in a friendlier VBA
    function.

    Also, remember that the RTD function accepts a maximum of 28 arguments!
    If you want to pass more, you may need to concatenate arguments into one
    string, and have your topic parse them appropriately.
    z&{EA7F2CF1-11A2-45E4-B2D5-68E240DB8CB1}zPython.RTD.TimeServerz8Python class implementing Excel IRTDServer -- feeds timeg      ?c                     t                                                       t          j        | j        | j                  | _        d S rX   )r   r   	threadingTimerINTERVALrj   tickerr   s    r   r   zTimeServer.__init__N  s6      odmT[AAr   c                 8    | j                                          d S rX   )rz   startr#   s    r   rF   zTimeServer.OnServerStartY  s    r   c                 x    | j         j                                        s| j                                          d S d S rX   )rz   finishedis_setcancelr#   s    r   rK   zTimeServer.OnServerTerminate\  s?    {#**,, 	!K     	! 	!r   c                    t          j        | j        | j                  | _        	 t          | j                  rsd}| j                                        D ]A}|                    |            |                                rd}|	                                 B|r| 
                                 | j                                         d S # | j                                         w xY w)NFT)rw   rx   ry   rj   rz   r6   r   valuesrs   rm   r$   r|   )r   refreshr@   s      r   rj   zTimeServer.Update`  s    odmT[AA	 4; 	'![//11 " "ELL&&&'')) '"&KKMMMM '$$&&&KDKs   BC C#Nc                      t          |          S )zGTopic factory. Builds a TimeTopic object out of the given TopicStrings.)	TimeTopicrO   s     r   r&   zTimeServer.CreateTopicr  s    &&&r   rX   )r)   rY   rZ   r[   _reg_clsid__reg_progid_
_reg_desc_ry   r   rF   rK   rj   r&   ra   rb   s   @r   ru   ru   .  s         0 ;K*LKJ H	B 	B 	B 	B 	B  ! ! !     $' ' ' ' ' ' ' 'r   ru   c                   .     e Zd ZdZ fdZd Zd Z xZS )r   zExample topic for example RTD server.

    Will accept some simple commands to alter how long to delay value updates.

    Commands:
      * seconds, delay_in_seconds
      * minutes, delay_in_minutes
      * hours, delay_in_hours
    c                    t                                          |           	 | j        \  | _        | _        n1# t
          $ r$}t          dt          |          z            d }~ww xY wt          | j                  | _        | 	                                | _
        |                     t          | j
                             d S )NzInvalid topic strings: %s)r   r   rP   cmddelayr'   
ValueErrorr(   float	timestamp
checkpointrq   )r   rP   Er   s      r   r   zTimeTopic.__init__  s    &&&	N#'#4 DHdjj 	N 	N 	N 83|;L;LLMMM		N 4:&&
 ..**c$/**+++++s   9 
A'A""A'c                 >    t           j                                         S rX   )datetimenowr#   s    r   r   zTimeTopic.timestamp  s     $$&&&r   c                    |                                  }|| j        z
  }d}| j        dk    r|j        | j        k    rd}nY| j        dk    r|j        | j        k    rd}n;| j        dk    r|j        | j        k    rd}n|                     d| j        z              |r+|                     t          |                     || _        d S d S )NFsecondsTminuteshoursz#Unknown command: )	r   r   r   r   r   r   r   rq   r(   )r   ri   r   deltar   s        r   rj   zTimeTopic.Update  s    nndo%8y  }
**X""}
**X  {dj((MM.9::: 	"MM#c((###!DOOO	" 	"r   )r)   rY   rZ   r[   r   r   rj   ra   rb   s   @r   r   r   w  s`         , , , , ,"' ' '" " " " " " "r   r   __main__)r[   r   rw   r^   win32com.clientrB   r   r   win32com.server.exceptionr   EXCEL_TLB_GUIDEXCEL_TLB_LCIDEXCEL_TLB_MAJOREXCEL_TLB_MINOREnsureModuleRegisterInterfacesr   rd   ru   r   r)   win32com.server.registerserverregisterUseCommandLinerR   r   r   <module>r      s   @                    $ $ $ $ $ $ 2 2 2 2 2 2
 :  nno W W W 	 $%  | | | | | | | |~       NF' F' F' F' F' F' F' F'R1" 1" 1" 1" 1" 1" 1" 1"h z#### O++J77777 r   