a
    a/n                     @   s  d Z ddlZddlmZ ddlZddlZddlmZ ddl	Z	ddl
Z
ddlZddlmZmZ ddlmZmZmZmZmZmZmZmZmZmZ ddlmZmZmZmZmZ ddl m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/ ddl0m1Z1 dd	l2m3Z3 dd
l4m5Z5m6Z6m7Z7m8Z8 ddl9m:Z: ddl;m<Z< ddl=m>Z> ddl?m@Z@ ddlAmBZBmCZC ddlDmEZE dd	l2m3Z3 e
jFdkrddlGZHe8rddlImJZJ nddlKmJZJ eLeMZNdZOdd ZPdnddZQdd ZRdoddZSdd ZTdaUd d! ZVd"d# ZWd$d% ZXdpd&d'ZYd(d) ZZd*d+ Z[d,d- Z\dqd/d0Z]drd3d4Z^dsd5d6Z_d7d8 Z`dddddddejadddddd.d.fd9d:Zbd;d< Zcd=d> Zdd?d@ ZedAdB ZfdtdCdDZgdEdF ZhdGdH ZidudIdJZjdKdL ZkdvdMdNZlg fdOdPZmG dQdR dReZndSdT ZoG dUdV dVe!ZpG dWdX dXe/ZqdYdZ Zrd[d\ Zsdwd]d^Ztd_d` ZuG dadb dbe)ZvG dcdd dde#ZwG dedf dfe"Zxdgdh ZydxdkdlZzeMdmkr~er  dS )yzQt utilities.    N)pi)from_qvariantto_qvariant)
QEventQLibraryInfoQLocaleQObjectQtQTimerQTranslatorQUrlSignalSlot)QDesktopServicesQIcon	QKeyEventQKeySequenceQPixmap)QActionQApplicationQDialogQHBoxLayoutQLabel	QLineEditQMenuQPlainTextEditQProxyStyleQPushButtonQStyleQToolBarQToolButtonQVBoxLayoutQWidget)MAC_APP_NAME)CONF)configparseris_text_stringto_text_stringPY2)ima)programs)get_image_path)QStylePalette)ACTION_REGISTRYTOOLBUTTON_REGISTRY)QWaitingSpinnerdarwin)unquotec                 C   s   t  }||  t|S )z
    Generalized os.startfile for all platforms supported by Qt

    This function is simply wrapping QDesktopServices.openUrl

    Returns True if successful, otherwise returns False.
    )r   ZsetUrlr   ZopenUrl)filenameurl r4   5lib/python3.9/site-packages/spyder/utils/qthelpers.py
start_fileA   s    
r6   	not_foundc                 C   s   t  }|tt| | |S )z#Return image inside a QLabel object)r   	setPixmapr   r+   )namedefaultlabelr4   r4   r5   get_image_labelS   s    r<   c                  C   s"   t  } | jdur| j} q| jjS )z+Return the filename at the top of the stackN)sys	_getframef_backf_codeco_filename)fr4   r4   r5   get_origin_filenameZ   s    
rC   T   c                 C   s   t jdkrt}nt}| }|du r8|dg}|d t jdkrVtdddrVt  | rbt	| t
jdd}|durt|}|j|j ||d  |S )	z
    Return QApplication instance
    Creates it if it doesn't already exist

    test_time: Time to maintain open the application when testing. It's given
    in seconds
    r0   NZSpydermainZmac_open_fileFZTEST_CI_WIDGETSi  )r=   platformMacApplicationr   instanceZsetApplicationNamer$   getregister_app_launchservicesinstall_translatorosenvironr
   Ztimeoutconnectquitstart)	translateZ	test_timeZSpyderApplicationappZtest_ciZtimer_shutdownr4   r4   r5   qapplicationc   s"    


rS   c                 C   s4   t jdkr(td| rd|  S d|  S nd|  S dS )zBSelect the right file uri scheme according to the operating systemntz
^[a-zA-Z]:file:///file://N)rL   r9   research)fnamer4   r4   r5   file_uri   s
    

rZ   c                 C   sH   t du r2t }|dt   ttjr2|a t durD| 	t  dS )z2Install Qt translator to the QApplication instanceNZqt_)
QT_TRANSLATORr   loadr   systemr9   r   locationZTranslationsPathZinstallTranslator)ZqappZqt_translatorr4   r4   r5   rK      s    
rK   c                 C   s   t t| }tt|d tS )zReturn keybindingr   )getattrr   r   ZkeyBindingsstr)attrZksr4   r4   r5   
keybinding   s    
rb   c                 C   s   |  drFtjdkr:|  dr,| dd  } qF| dd  } n| dd  } | dtj} t| r||d u sxt| d |v r|| S d S )	NrV   rT   rU            \   )
startswithrL   r9   replacesepospexistssplitext)pathextlistr4   r4   r5   _process_mime_path   s    



rp   c                 C   s   g }|   rD|  D ],}ttt| |}|dur|| qn:|  r~t|  	 D ] }t||}|dur\|| q\|r|S dS )zR
    Extract url list from MIME data
    extlist: for example ('.py', '.pyw')
    N)
ZhasUrlsZurlsrp   r1   r'   toStringappendZhasTexttext
splitlines)sourcero   Zpathlistr3   rn   Zrawpathr4   r4   r5   mimedata2url   s    
rv   c                 C   s(   |   |  |  |  |  |  fS )z'Convert QKeyEvent instance into a tuple)typekey	modifiersrs   ZisAutoRepeatcount)eventr4   r4   r5   keyevent2tuple   s    r|   c                 C   s   t |  S )z'Convert tuple into a QKeyEvent instance)r   )Z
past_eventr4   r4   r5   tuple2keyevent   s    r}   c                 C   s^   t | tr$| \}}}}}}t| } n|  }|  }|  }|tj@ }|tj@ }| ||||fS N)	
isinstancetupler}   rs   ry   rx   r	   ZControlModifierZShiftModifier)r{   _rx   ry   rs   Zctrlshiftr4   r4   r5   restore_keyevent   s    



r   Fc                 C   s   t | }|dur|| |dur>t|r4t|}|| |dusN|durd||du r^|n| |rt|tj	 |
| |dur|j| |durt|||	|
 |dur|| |dur||_|rt|||| |S )zCreate a QToolButtonN)r    ZsetTextr&   r)   get_iconsetIcon
setToolTipsetToolButtonStyler	   ToolButtonTextBesideIconsetAutoRaiseclickedrN   setup_toggled_actionsetShortcutZIDr.   register_reference)parentrs   shortcuticontiptoggled	triggered	autoraisetext_beside_iconsectionoptionid_plugincontext_nameZregister_toolbuttonbuttonr4   r4   r5   create_toolbutton   s2    




r          c                 C   sz   d}t |  ||  |t   }| d|  d }t|dd}|d || || || || |tj	 |S )zS
    Create a wait spinner with the specified size built with n circling dots.
    rg      F)ZcenterOnParentT)
r   r/   ZsetTrailSizeDecreasingZsetNumberOfLinesZsetLineLengthZsetLineWidthZsetInnerRadiusZsetColorr,   ZCOLOR_TEXT_1)sizenr   Zdot_paddingZdot_sizeZinner_radiusZspinnerr4   r4   r5   create_waitspinner  s    




r   c                 C   sN   |du r|   }t|}||  || |r<|tj |rJ| | |S )z3Create a QToolButton directly from a QAction objectN)r   r    ZsetDefaultActionr   r   r	   r   r   )actionr   r   r   r   r   r4   r4   r5   action2button  s    


r   c                 C   s(   | dur$| D ]}|dur| | qdS )zEnable/disable actionsN)Z
setEnabled)actionsenabler   r4   r4   r5   toggle_actions.  s    r   c                 C   s*  t || |d}|dur"|j| |dur8t||||
 |dur\t|rRt|}|| |durx|| |	| |dur|
t| |dur|| tjdkrd|_|	tjkr|dur||_qd|_n|dur|| ||	 n|dur|| ||	 |r&t||||| |S )zCreate a QAction	action_idNr0   Zmissing)SpyderActionr   rN   r   r&   r)   r   r   r   ZsetStatusTipsetDatar   ZsetMenuRoler=   rF   Z_shown_shortcutr	   ZWidgetShortcutr   ZsetShortcutContextr-   r   )r   rs   r   r   r   r   r   dataZmenurolecontextr   r   r   r   r   Zregister_actionZ	overwriter   r4   r4   r5   create_action6  sB    











r   c                 C   sL   t |||}| j| | d |durH|durHt| || t|  dS )z]
    Setup a checkable action and wrap the toggle function to receive
    configuration.
    TN)wrap_toggledr   rN   ZsetCheckabler$   Zobserve_configurationadd_configuration_update)r   r   r   r   r4   r4   r5   r   g  s    
r   c                    s2   dur. dur.t  fdd}|S S )z@Wrap a toggle function to set a value on a configuration option.Nc                    s   t j | dd |  d S )NT)Zrecursive_notification)r$   set)valuer   r   r   r4   r5   wrapped_toggledw  s    z%wrap_toggled.<locals>.wrapped_toggled)	functoolswraps)r   r   r   r   r4   r   r5   r   t  s
    r   c                 C   s$   dd }t || }t| d| dS )zCAdd on_configuration_change to a SpyderAction that depends on CONF.c                 S   s"   |  d | | |  d d S NTF)ZblockSignalsZ
setChecked)selfZ_optionZ_sectionr   r4   r4   r5   on_configuration_change  s    

z9add_configuration_update.<locals>.on_configuration_changer   N)types
MethodTypesetattr)r   r   methodr4   r4   r5   r     s    r   c              	   C   sv   t | ds|  | _ztj||d}W n tjtjfyD   d}Y n0 |rrt|}|	tj
}| d| j| dS )z>Add the shortcut associated with a given action to its tooltip_tooltip_backup)r   r9   Nz	{0} ({1}))hasattrZtoolTipr   r$   Zget_shortcutr%   ZNoSectionErrorZNoOptionErrorr   rq   Z
NativeTextr   format)r   r   r9   r   Zkeyseqstringr4   r4   r5   add_shortcut_to_tooltip  s    


r   c              	   C   s   d}t |  }|r(|d }| r(d}|D ]}|du r^|dur^|du rR|   q| | nrt|tr|du r|| | q| || nFt|t	r|du rz| 
| W q ty   Y q,Y q0 n| || |}q,dS )z%Add actions to a QMenu or a QToolBar.N)listr   isSeparatorZaddSeparatorZinsertSeparatorr   r   ZaddMenuZ
insertMenur   Z	addActionRuntimeErrorZinsertAction)targetr   Zinsert_beforeZprevious_actionZtarget_actionsr   r4   r4   r5   add_actions  s.    


r   c                 C   s   t | dtjtS )z$Get QTreeWidgetItem user role stringr   )r   r   r	   UserRoler'   )itemr4   r4   r5   get_item_user_text  s    r   c                 C   s   |  dtjt| dS )z$Set QTreeWidgetItem user role stringr   N)r   r	   r   r   )r   rs   r4   r4   r5   set_item_user_text  s    r   c                    s$   t   fdd}t| ||||dS )zCreate bookmark actionc                      s   t  S r~   )r6   r4   r3   r4   r5   open_url  s    z(create_bookmark_action.<locals>.open_url)r   r   r   )r   r   )r   r3   titler   r   r   r4   r   r5   create_bookmark_action  s
    
r   c                 C   sL   g }|D ]>\}}}d}|dkr,t |s,d}|rt| ||}|| q|S )zt
    Create bookmark actions depending on module installation:
    bookmarks = ((module_name, url, title), ...)
    TZ	winpythonF)r*   Zis_module_installedr   rr   )r   Z	bookmarksr   rx   r3   r   Z
create_actZactr4   r4   r5   create_module_bookmark_actions  s    
r   c                    sV   t |rt|}tjdkr(|dur(| t }|durRt| || fdddS dS )zCreate action to run a programrT   Nc                      s
   t  S r~   )r*   Zrun_programr4   r9   r4   r5   <lambda>      z'create_program_action.<locals>.<lambda>r   r   )r&   r)   r   rL   r9   r*   Zfind_programr   )r   rs   r9   r   Znt_namern   r4   r   r5   create_program_action  s    


r   c                    s>   t |rt|}tr:t| || fdddS dS )z.Create action to run a GUI based Python scriptc                      s   t  S r~   )r*   Zrun_python_scriptr4   argsmodulepackager4   r5   r     s    z-create_python_script_action.<locals>.<lambda>r   N)r&   r)   r   r*   Zpython_script_existsr   )r   rs   r   r   r   r   r4   r   r5   create_python_script_action  s    
r   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )DialogManagerz
    Object that keep references to non-modal dialog boxes for another QObject,
    typically a QMainWindow or any kind of QWidget
    c                 C   s   t |  i | _d S r~   )r   __init__dialogsr   r4   r4   r5   r     s    
zDialogManager.__init__c                    s   t  j D ]0}t| t| kr|  |   qq|  | jt|< |j	t|f fdd	 |j
	t|f fdd	 dS )zYGeneric method to show a non-modal dialog and keep reference
        to the Qt C++ objectc                    s
     | S r~   dialog_finishedZeidr   r4   r5   r     r   z$DialogManager.show.<locals>.<lambda>c                    s
     | S r~   r   r   r   r4   r5   r     r   N)r   r   valuesr'   ZwindowTitleshowZraise_idZacceptedrN   Zrejected)r   dialogdlgr4   r   r5   r     s    

zDialogManager.showc                 C   s   | j |S )zManage non-modal dialog boxes)r   pop)r   Z	dialog_idr4   r4   r5   r     s    zDialogManager.dialog_finishedc                 C   s    t | j D ]}|  qdS )zClose all opened dialog boxesN)r   r   r   reject)r   r   r4   r4   r5   	close_all  s    zDialogManager.close_allN)__name__
__module____qualname____doc__r   r   r   r   r4   r4   r4   r5   r     s
   r   c                 C   s:   t | d }|dr$|dd }td| tdS )zReturn file type iconrg   .Nz%s.pngZFileIcon)rk   rm   rh   r)   r   r   )rY   Zextr4   r4   r5   get_filetype_icon"  s    
r   c                       s6   e Zd ZdZdd fdd
Zdd Zdd	 Z  ZS )
r   >Spyder QAction class wrapper to handle cross platform patches.Nr   c                   s4   t t| j|i | || _tjdkr0| d dS )r   r0   FN)superr   r   r   r=   rF   setIconVisibleInMenu)r   r   r   kwargs	__class__r4   r5   r   -  s    
zSpyderAction.__init__c                 C   s   d |  S NzSpyderAction('{0}')r   rs   r   r4   r4   r5   __str__4  s    zSpyderAction.__str__c                 C   s   d |  S r   r   r   r4   r4   r5   __repr__7  s    zSpyderAction.__repr__)r   r   r   r   r   r   r   __classcell__r4   r4   r   r5   r   *  s   r   c                   @   s   e Zd ZdZdd ZdS )ShowStdIconsz'
    Dialog showing standard icons
    c           
      C   s   t | | t }d}d}ttD ]}|dr"|dkr>t }t }t|}t	 }	|	
|dd ||	 |t|dd || |d | }|dkr"|| q"| | | d | td d S )	N   r   ZSP_r    rg   zStandard Platform IconsZTitleBarMenuButton)r"   r   r   dirr   rh   r!   r)   Zget_std_iconr   r8   Zpixmap	addWidgetr   ri   	addLayout	setLayoutsetWindowTitleZsetWindowIcon)
r   r   layoutZrow_nbZcindexchildZ
col_layoutZicon_layoutr   r;   r4   r4   r5   r   ?  s*    





zShowStdIcons.__init__N)r   r   r   r   r   r4   r4   r4   r5   r   ;  s   r   c                  C   s(   t  } td}|  t|   dS )z!
    Show all standard Icons
    N)rS   r   r   r=   exitZexec_)rR   r   r4   r4   r5   show_std_iconsW  s    r  c              
   C   sp   dddddddddd	}t   d	}d
tj|f }||v rl|| \}}|   }|| | }t|dS dS )a  
    Return a spacing (int) or None if we don't have the appropriate metrics
    to calculate the spacing.

    We're trying to adapt the spacing below the tools_layout spacing so that
    the main_widget has the same vertical position as the editor widgets
    (which have tabs above).

    The required spacing is

        spacing = tabbar_height - tools_height + offset

    where the tabbar_heights were empirically determined for a combination of
    operating systems and styles. Offsets were manually adjusted, so that the
    heights of main_widgets and editor widgets match. This is probably
    caused by a still not understood element of the layout and style metrics.
    )r   r   )   rD   )   r   )   r   )&   )   r   )   r   )	z	nt.fusionznt.windowsvistaznt.windowsxpz
nt.windowszposix.breezezposix.oxygenzposix.qtcurvezposix.windowszposix.fusionr9   z%s.%sr   N)rS   ZstylepropertyrL   r9   ZsizeHintZheightmax)tools_layoutZmetricsZ
style_namerx   Ztabbar_heightoffsetZtools_heightspacingr4   r4   r5   calc_tools_spacinga  s"    r  c                 C   sP   t  }|dddd t| }|dur0|| ||  |durL|| |S )a  
    Returns a layout for a set of controls above a main widget. This is a
    standard layout for many plugin panes (even though, it's currently
    more often applied not to the pane itself but with in the one widget
    contained in the pane.

    tools_layout: a layout containing the top toolbar
    main_widget: the main widget. Can be None, if you want to add this
        manually later on.
    r   N)r!   ZsetContentsMarginsr  Z
setSpacingr  r   )r  Zmain_widgetr  r  r4   r4   r5   create_plugin_layout  s    


r  c              	   C   sf   |   }|D ]T}z8| dur.t| | n| r<W qn
|| W q ty^   Y qY q0 qdS )z!Show/hide icons for menu actions.N)r   menuset_menu_iconsr   r   r   )r  stateZmenu_actionsr   r4   r4   r5   r    s    r  c                   @   s   e Zd ZdZdddZdS )SpyderProxyStylez(Style proxy to adjust qdarkstyle issues.r   c                 C   s    |t jkrdS t| ||||S )zOverride Qt method.r   )r   ZSH_ComboBox_Popupr   	styleHint)r   hintr   ZwidgetZ
returnDatar4   r4   r5   r    s    
zSpyderProxyStyle.styleHintN)r   r   r   )r   r   r   r   r  r4   r4   r4   r5   r    s   r  c                       s"   e Zd ZdZd fdd	Z  ZS )QInputDialogMultilinezy
    Build a replica interface of QInputDialog.getMultilineText.

    Based on: https://stackoverflow.com/a/58823967
    r   c           	         s   t t| j|fi | |d ur*| | | t  |  t| t	 | _
|  | j
 t }|  td}|| td}|| |  | | j
| |j| j |j| j d S )NZOKZCancel)r   r  r   r  r  r!   r  r   r   r   Z	text_editr   Z
addStretchr   r  ZsetPlainTextr   rN   Zacceptr   )	r   r   r   r;   rs   r   Zbutton_layoutZ	ok_buttonZcancel_buttonr   r4   r5   r     s"    


zQInputDialogMultiline.__init__)r   )r   r   r   r   r   r   r4   r4   r   r5   r    s   r  c                   @   s(   e Zd ZdZeeZdd Zdd ZdS )rG   z;Subclass to be able to open external files with our Mac appc                 G   s.   t j| g|R   d| _d| _g | _i | _d S r   )r   r   _never_shown_has_started_pending_file_open_original_handlers)r   r   r4   r4   r5   r     s
    zMacApplication.__init__c                 C   sd   |  tjkrXt| }tjr0tjd |kr0n(| jrD| j	| nt
|vrX| j| t| |S )Nr   )rw   r   ZFileOpenr`   filer=   argvr  sig_open_external_fileemitr#   r  rr   r   r{   )r   r{   rY   r4   r4   r5   r{     s    zMacApplication.eventN)	r   r   r   r   r   r`   r#  r   r{   r4   r4   r4   r5   rG     s   rG   c                  C   s6   t  } | j D ]\}}|\}}t||| qdS )z,Restore LaunchServices to the previous stateN)r   rH   r   itemsalsset_UTI_handler)rR   rx   ZhandlerZUTIroler4   r4   r5   restore_launchservices  s    r)  public.python-scripteditorc                    s   t   t }t|v r8|t}t|d| t }nt}| jf<  j	
t  js~t }t| dS  fdd} j
| dS )zO
    Register app to the Apple launch services so it can open Python files
    Nc                    s0   | t jkr, jr,d _t }t| d S )NF)r	   ZApplicationActiver  r&  get_bundle_identifierr'  )r  bundle_identifierrR   r(  uniform_type_identifierr4   r5   handle_applicationStateChanged  s    zCregister_app_launchservices.<locals>.handle_applicationStateChanged)r   rH   rC   r#   findr&  Zget_bundle_identifier_for_pathZget_UTI_handlerr   ZaboutToQuitrN   r)  r  r,  r'  ZapplicationStateChanged)r/  r(  Zorigin_filenameZ
bundle_idxZold_handlerr-  r0  r4   r.  r5   rJ     s(    
rJ   __main__)r7   )TrD   )N)NNNNNNTFNNNNNF)r   r   N)TFNN)N)NN)NN)N)r*  r+  ){r   r   Zmathr   ZloggingrL   os.pathrn   rk   rW   r=   r   Zqtpy.compatr   r   Zqtpy.QtCorer   r   r   r   r	   r
   r   r   r   r   Z
qtpy.QtGuir   r   r   r   r   Zqtpy.QtWidgetsr   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   Zspyder.config.baser#   Zspyder.config.managerr$   Zspyder.py3compatr%   r&   r'   r(   Zspyder.utils.icon_managerr)   Zspyder.utilsr*   Zspyder.utils.image_path_managerr+   Zspyder.utils.paletter,   Zspyder.utils.registriesr-   r.   Zspyder.widgets.waitingspinnerr/   rF   Zapplaunchservicesr&  Zurllibr1   Zurllib.parseZ	getLoggerr   ZloggerZMENU_SEPARATORr6   r<   rC   rS   rZ   r[   rK   rb   rp   rv   r|   r}   r   r   r   r   r   ZWindowShortcutr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  rG   r)  rJ   r4   r4   r4   r5   <module>   s   0D

	
%
     
!
  

1

!


$
(
!	  
(
