From 7c3a0c98362239706590036460e9ceb20113a36e Mon Sep 17 00:00:00 2001 From: PaulJonasJost Date: Tue, 15 Apr 2025 15:50:54 +0200 Subject: [PATCH 1/3] Added application Icon (not visible in MacOS) --- pyproject.toml | 6 +++++ src/petab_gui/app.py | 13 +++++++++- src/petab_gui/assets/PEtab.png | Bin 0 -> 20460 bytes src/petab_gui/utils.py | 7 ++++++ src/petab_gui/views/table_view.py | 38 +++++++++++++++++++----------- 5 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 src/petab_gui/assets/PEtab.png diff --git a/pyproject.toml b/pyproject.toml index 99e992f..a7221e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,3 +50,9 @@ petab_gui="petab_gui:main" [project.scripts] petab_gui_cli="petab_gui:main" + +[tool.setuptools] +include-package-data = true + +[tool.setuptools.package-data] +"petab_gui.assets" = ["PEtab.png"] diff --git a/src/petab_gui/app.py b/src/petab_gui/app.py index a7ea349..189acf3 100644 --- a/src/petab_gui/app.py +++ b/src/petab_gui/app.py @@ -1,6 +1,7 @@ from PySide6.QtWidgets import QApplication -from PySide6.QtGui import QFileOpenEvent +from PySide6.QtGui import QFileOpenEvent, QIcon from PySide6.QtCore import QEvent +from importlib.resources import files import sys import os import petab.v1 as petab @@ -21,6 +22,15 @@ def find_example(path: Path) -> Path: raise FileNotFoundError("Could not find examples directory") +def get_icon() -> QIcon: + """Get the Icon for the Window""" + icon_path = files("petab_gui.assets").joinpath("PEtab.png") + if not icon_path.is_file(): + raise FileNotFoundError(f"Icon file not found: {icon_path}") + icon = QIcon(str(icon_path)) + return icon + + class PEtabGuiApp(QApplication): def __init__(self): super().__init__(sys.argv) @@ -29,6 +39,7 @@ def __init__(self): # self.apply_stylesheet() self.model = PEtabModel() self.view = MainWindow() + self.view.setWindowIcon(get_icon()) self.controller = MainController(self.view, self.model) # hack to be discussed diff --git a/src/petab_gui/assets/PEtab.png b/src/petab_gui/assets/PEtab.png new file mode 100644 index 0000000000000000000000000000000000000000..79372f4d11c51a41ba55ff8aaf9ac068916be787 GIT binary patch literal 20460 zcmb?@gUiLXhl9T{I52(n?>ICE- zb_M4CoHyjYqkh_~e=Id4C3R@nnKFEu{+cXa)g=S1Aw8AkZU@4^4EH)i;||#(?0*uS znj-^Q?TulU5%!RC$&C?ZNlvq1gi2UG5x+EE@I7liTWOm*Y^_0>jqGcDmc0aXo( z;OqkwalW#C*>Yz7@Fz1|g?La(&C(w$pd<8s(8R`}nVK|DcfqzMr^Ks;GQCRa&flMN z!rVhcLkVOs5m1>oDuvRE(}oDe<0(|-&VAk5<=`dTOw)nrp0PmJE5p})hX$=@_a@%c zwoz7DHEC+4=7Dp%`u9QzPk=%&E`sj{kwgpOg(#Z_?z{^hIlB`^_L*?U`G~s`yUd&g z6S$#E?}v7Hx4*k6hWI;0dG{1tw%;Fp`s`o1G8Jg{VBf(%oIz5Pg4prM~OcR$wm?m_JOleuDl=RTcNs6;?u6XNu*5 z7|zA-_T(rG{2$on*O6`EK|wcUC?RAr6zG`n#ZnyWXaufyHJA5&{~(!pXTkOtsD$5o z;GShrkobT7bWD;S)N!a7cout;dAr><{DJ5Q;vWn$=Jnr2-UFNIqd%j4_YMvY(1nKS ztRk`SsfR5eAMWQ5C2_X)2-F`hajC?h7L#qe;6T zyCf_NPgTxJpbJ=kpzJ-uA^nKI=s*Qnyi)KB>5Y*?si>fgd0sakOmbH@b`dm5k3^D~ z#WUuqt-yNG>d71m2+$yaMJI0;mcKzioo`=Cc3nqbb&}@1OA80%b6^cl;`PgaDJ++c zr0J|D{t$YhMsLze-C(6GMOfXxs(+@Y&J8++3t}=C>gKhga&p z4c_{CdgH;235<$LN~jBt3Pl=-Vz%AO*;yU7i+Lv@9S#!j+XT*<-mhPyotGx$Tm}+H z2oUCP$85QtKK-zgP%J~NFtry~bW~Z9@a`Rnw?xJ$eZf?)+w)TATv5;dyQc}oj@Z9R zoSmJ8A+VR^obM8n02@QRl6CTX*-x+^SdpRBlCE)Nr&vs~dm`_B+-pzfb zWg^$e>+I$6Fc)|f$}AbX58zs?udnaDFk*m3E3aRd3(nQxmU3e<#E{5UaF$5B|b8g`sy!ygY zO6+LEo~gEN&R^;>w4BgU*i`w3`e$`y|exMp`@h5eZzB@ z#=q!;p)yN!86Rd7BR{m)4AwI>!jT1@^7po76<8|iuRa>Ky2x4DkXlu^w37dIi`>6+ zFJ|+5irg`B>mLp|Ug|nqS$B&@@69DVUv9DCcU<#NSU6j3WlJDCSnIfQU1@Q>?VAwU zxFdLJ$3W=}sb2i$AVU?2B`u+^tJ}EeZa;VFRFo`dR}^NM#Sca6QWVY!op`5j_E#ic z0NYpIMi7wpc$05kQOY&;nU$WCHGz@vwfsu{hEYpKs{ejykl1>4W^?|r{@n3Jr&;ay znnTMqPUNv%kwv4k4gZHsbI(B%_pY7y#@$#0v~YV;FM59HrY~%odqjT0mn|XEgxj9; zHhZBHUBd6cBQ{$R>pp;PpvIege?|}&1E2OQSCiakl2dq^W3dxE;7o3hd5aLuD;0Un*?ND!|g{fmU6o&SDL=&Bc1_&#Wsyf7+}x zAdyI6rtkD#IOiWt4EAsNa5v3vQ) z_*Hw2%uCO5MSXt3^F#iqcuN#awU)iRCk-)OaQzUIKFZv%L=Gkq*QD)w(ar82whSW!cERw~KijGew|JFef!HCE#n*-SQXCvTbh4P* z7S>Tk^6e_c(n)j^3-r__S#Zh(hZtxgx~ipn`Hb^hLRt z-O-b__yX$#akG{6^2C{p?-X$x*vo@+5-STwCOj8@oJg|yc7sTL5rd2#qZJ!Rs)(XP zFF;gInJ4K}lCuj|O9BoG(6<_4$Ow0)ZRd5x%rnuf<{p`}Hbb^X-jks#Xv$4+yWmEr z+lmn%_CICvBEJxC#5NXq+OcNs%&+;LH2K|}uT+FxtR)tcXPLRinEi|mbutdh`921m zST@>x!B?Q1<+cf#cZY*5sQSFwsF~)haomtqr&4!?3o$oVLk42r3YUz*g&z1$7u&lR zEzM+AWeZ4Q+(NDLte>*%F~w|R0281?E)RbT7|dIeOyE4HjLm|93st7>RDuB-NuMQ0 zK3lRl#`iuT`eGbx&9jorj&yF;KmAtTY6;{~bda9KdOsBS87XzVHLR$}zEWE7T`B$; zhHQ0vnQntDPob6CZ%fKso;>1PxymTG`>F`cpTQV}izWRI$p8D@WO($Av-ZwClAbsq zzjgp_v0sH+r&Q9g5e;`b)h>TKwxdKBa?$Vb8g?FE0^$HxJE7J1!` z{p=%VpJDg#_zOvUyCr!>%bKxa&s?!2JG7hz>pF2JU+1$zf(u$MC-V9MIgZb)*dKVm7@2dtJ7q}M=yzueee zQ-Scc)KP2hMnhL_BZ2Qt1YP9Fj+bzeKMK)977*Fb(G(V>sh~-(lJ3fWQWpwDTEP1^ z)cf$YWkie?*Wk=YmID8Jel%I{j0!4@<4(_OKSrjX@F2_qL-t!-=!4?N6<(i429PDV z`J|Gqh$~_b#Q)mMYBcFUc3=N^BO3VUQ(NAIo$(#!%^GsQ-R-Paoh9S*+Q&?1A~_9? zcjK|j^1#7?3)_VqKZWrTM3Wd*A_G@|Q30?#7nY49 ztf*LSIIbhMP6U`$8f<4zU-A~SEo+69&irnHPS+X&$=gQD7DDrAU5{_IjJwKpI0Tt2 zINtFe6AgP7%^BA&xK7Rd-N;kiok$pg1MqQzG8$+91df9})TD%O8}56Biu zeuY-Kg|F}2Ir^&-EmySqnK1!z@r1TEF_6$>RaJ0Q%yH=H>)-ychYxwy+TOiIlA(v* zyL}~u=EUfLVxH>>`R3!3_sp2@UJME=(nZrD=+2EEd9fcAGm`Xq53L$uE&B42K-Eb) z!N?e~sq{V2pN&rKQ!CA8nYcXNkKdBb>0$E+B|sHzx0##g*C1-$g5#Jh<|BQyr$Njb zw(wavDq{tTPvludVp5Xja57CQGvG@<(IEmh{h$ zMS`ZVTHkZy>yKR5nnQLs%p_BBF}L#5@dUe zav$?B%_X|tBA9Kn{3ckDIWr_~A7LpAOBuI9S&O6pG`0R^Pa37BW^E9~Fk8O|y+ zj0^5^TimCZfE2m*4KXCWMVxxV^-kC(&QPK0b@k1A3 zXFG#SBP9tgE-p|$0Q8@=TB6<}< zP%mw-+*3~GN~yN~weLZHDXco0EEbg_o`>AYA~V2Eaao}pqB_q8Ye~FXhr@P$#W|`CCnj2es0Gp~kXS_w_)7GNNmGCR?xN98XD4R=SGH}Y6TT<)mkAq<@w zSMK`$%YdTevez`ZAH#7p$h*nhIeO%r?k^*aszK1mcrx8&2d&WIP-Z5K5FjJL8WQ~g zw|eRKTfQe+;l1sdG@)EwXQzu=PPXkirHzrVL>E&PcJeIJH_AkYUTB?{hLU67D5p_k z!Pyth?)`0hVN{gon@-P2FF*q%(gw z>qqc4{bQ8+oB#9(-C=25?VMA~je_R66z;E!o~9_SF}BQ{_s4T{bEFUr2H7VMiB4~| zh~Frj-869JKsBOdkHiI)Puxwoh_QtAEffLWG8U9smA$gyq7D`qpvtgWJXOJ`2=k&}BIbU9h`ruYgbGJrN+7iOv+A#$sQd5_MMV8~PB9 zT>9uO;D7=OBYNs>BXU`Vy!f(Ak4^doob6S=VKF{Tj^)xWhhE#GHhIc+m-Dh{^~ldd z0NlYLfR+$ZIQP2Lcx5mb=DSm-`5ue@H#>kxhO)V)LZPA*h1%6`wO~P%@ zOwAD-nw2Dw$X~%7`@x^ePs+Q4hO*tbZkj1kq`@Zh!mjUkEYY$-5EdriR!6=iYZQoE zQ5#f7)q3^a-JoGYKgLgp`G`-zJCr#O*V80sNGM*SRnY7`>vT;0BXIQ!7C{etdVw7| zEwbg#S@vEST(VPFl`|J?CCXUrb=fnc)c=iIRN_f6Brqy}OzPaGy)@!cW$yirzGS%8 z6lYp?|8D`$uLc=>h*|x1i>dX;t6CN-eA+o~OGwPcLp-d_vN2Vj8AhM@3CoN&yU`@| zJ}j0)llUPl2<_7NM8fo=IYjKhW*!&h67&Hn*<(ArVq%zv?=`tdgYh{2B$%0fVFU5) z;yMo|TICm~N|+;y9Z!q`4NN0^4dwrUBbxlY%k0?c(^+4_`fSRV(r`=& zV1%~dNOW=|b7KoVpONqp7fJN)&)+?0PUf`-axX;Ze0mlzKbF#-j}OojutOY5^;)0v z;IsS^UE}GKH@X(1p)_hdzs}?M^fuCqGT!ZcQe0DWAgEMZ%3O(r6R}FJ2H!6?yHzmq z*L+a~v(+e$nD!7%uv7rmJ8Y;7Ec>(|7Y6*^o=uQR2rv@^EUc`m`WC7)8s$1*qry>1 zhctWJ*!-iPyDfA7RQ%7`B+-9m@t^9Hnw8UV*51v^yN_?>=8?*b7=W^!{7=>amG#jx zNw7dzH_`B{1wL@w2RvuVh)72jg%!RHY8W;kVE!qY0A5oc!c{dMyK)_Vv_`X9rksi8 zeeWpa&`A2lyPq?^o1W5v{^e%idM3KX(@bS%mvWFLHX-@-?+L>Sg(}^|^Mq%julS8+ z*cDhZWE04*o_!!l8)cSSSi$`5Ls>jxg(7OxxCICC8SZN}#8Ic49cx;6|IZzqo-{g^ z7rBs5bnNlFy(Mv?o^zCw-Z5CR6e@OY{(u0xs<8{xtMeZ(H%r#dq9>2V?nQTZzAW&| zehaGRDI=&W80wh-JHHIih+QK&6_tR%P4qj%_(M8*-VsGuIFG9r=gQc{jg<4ibP8?o zVlx8lK+}J3bvR;7xG`km<2!v-^S}M}E|%4LtS{)TZ_BX5J8r4IkhF0K$q%inY z!2wbs*X-{+;N_V!uhuiQM`>^FBHOa3Bzz8Xl@hH}AGcEew_4j_AI1S`atd1E-PHmu1F2WM3uVXz4$ONND#6!+DPvx zx$d_tAQ~RD)ZAI>T-0&OJuSru-RwWD+lCUzJEmhkaplLpbz#}+>bg0^$sORn#`)K$ z#6_Bn)yWjAWO-uyk@*rNtQE1(zxO-~RaA%evT9GqT#BJ!GUV&{zhGBpMB|`BV!|0v z6khp@jcwO4Nnp)Z96-xndr(KDewV4x)fjw?EWyzXv=0Vz1^Rdk$82=N_Y7kVZR1~> zC;dFkI5S2qtgQN1rGtg;rJ5pCq{*{_5 z>M`G1H?v9$t*g^5*HFtu`}+$4uEMu+-%-@~4={hnnuLs;eg`SGH4OEUxiiqhi1>t?Uv!f z*eP!8D>~7 z1@`9N(B~P)pJ##pmxoQVMQ`Qp>R=A=L+~i0h#zEgXI`!i{Ad|J2e5OtvrHygtZc9MiBZM+UC#e|{^Mwm+@=k=qQOI%^x; zR=8@$S!5=1hYfw%)fJh+p|LN-mOR-v*3oF#fPzB62*mnf%66Ww&U@bzs(@b6Ya-Th zR|QQYlL+h>x#3G6C-WkW-XA}T+X`&S_s_#u3o9fnLS3-2u{YyeZ=a0ugYt928q`Id zyXu9@NtI-jh7l;%272{hmeA1{pl_0^dK051`rcTGn?`^N!Z}Col4Es14FYnmy(Anb z;`3lNp8fDF@>yaNo`usFK~z#Em^0TR@gZ=k*I+{tuZON%7WqvQ24gEL4O-)|bL1(}xW?-JjaXlLQ$bYZ z3N|Rvb?$Q~L)*;*{@*MBOU{jVJIZafz`GZgK0d^V(`i-~mRI@~E&QqfGutBUISuZC ze{l~U%3W&A43S4j$Z8Xc4^bExEBVEJFX!Ul&ihE!^{|i@gpRrV3M;z+#>!b&rM#&X zdn>@>K~6R0CpJI@!x({}Ex=KF3?oFa8I^#r7-v^kTu>}WF{^aP%oquSe;zD=RcT>i zyLJd?0%%cyWJa@G2O@^rMgVxDT?zrAv zC7Jh`oJycZyXyBysi8{2PJIc1do~m8yunR{7S3;r*iXJISaRhz-yZAb!bZY zk9)1*YF~E}RC+iA1a@ZU_KAibC*sn0SP@Gac(o&Xx8-a@ZOm77Q7+i`%YYUGpYzMb zYw@uCL}qTO30gl%iJ=axo<_G?#X;WJMJqm=|2hY#R|=x()jnyldzYA!lCG*lDJsqz zujrZvyVlxxmWsB1fCUcG^O%vT{6%om?Y_tLLL+*5jXOh9lXDE?QF zGhtw8kdcuADh>@@640m0pG01iIPX=$-x)^MA@PlsMZO8}avfrkhizdnDuNDBMb|Zc zK-&W^Gy})TU?9Ma3Prec(Mb%b`UhtZQ7+4K1V5iNDiT6so$G`+>wGKts&4XNaxxVa zk>Z~lR^~o}Nk#jCv|l8MX@(g(Yh^F>(N2_QG=<(eaS%U6i(ryJr@K`R2K6k4HHLqCQ}PTsLHs!tDKB1tXbha)q9Z>|ZM zkgDAGGoV|+=IONXMmzd+BcN}A&c}c#&GUx%Mf&E3xNJdX)FHfbO{Lf~2IBccL1J+w z+d`e!Ra3TIR0bv{g4Tio`AS{ulpSy=cuqh$x_en;+A;nvBWgE5d3SINk zzsLr!z7!C8oMdLN9*Ux&IaFSR8ElELIb;!FLdbvqC`3pP=g?pH%e{q05y}6`y(Qeq zd&oNzEg_bN%jz;Mr^RE=MpG-Zyw1#Hml-G238b|G>?OFRQIv<5Vv3miPoeU980B*l z!V&~i5FB#LCr7Xwne@?5Pq%)KjKoin7!WIf;Y7~zBIe{{`YV>S3A>5=zaia~oOM(n zNdFC?mE5bo@{dJLd8NiAz<2m}IS;4yZ@Y^fT9|_;b&3>3r$l^L)Z&!9q)L^xA8&5l-@m~9ww&;4J6A?QT`ktx+=q@?3>5m8{!Wc?30 z^Ru%X+93KIByV3lnSyT0KPzxo!CoIF`9hP+v)|&nLVvQZ6YkuN3S{NxHZ_-P8@H>* zIW|N`zaO~3$NqBUhO0lGS??b`>|{6~|9;p=Vc@=OgebBoQHp@A3BnJu(ZPg2KZq@0znvDm(DfR{h%f ze5rkHc)tdZP3q(9_qxU$aJ_D^7t^ube8)5T<3KE!CwwRwIw|!8Q{iL4O@Js8y}gJ` z?nDAt;-DX2J|2j?tSV+>{O}5VWY37s-*nQ)qwpriN&i~!+2BJR#u`HUtaD#!Z2nc* z{#&(x&MF!<+WT^8f*xc(btvcQa2t@TgApXCy5ee(yIu>3j>1buWizd0g+7N_cmE%L zBTo{88+APVxjE)>l**J+M&JRPB^^W~%oqz8zKsVGW3hQ990}w>xE3E}*o8`YI+{E5 zBM$60H4WrHJM6?~!x64JZ!Gmw;Fj|R9sp@uZtVrzcYU`OGq;zo@| z>;)RLY`Fb8$EyZi&;9J2oW`Zp7A)axKolshLG~*SL(VH7)SPUl>m6Q7nWi7LI!EzE ze>eUXgz5WUC{p?+jMSf&bnDfPdIRH-`dYG5GIqc|G)17*`MUXy^L4pYY^=vIHl*7} zoic^T2v!GO_3TLI>1s?oebw0g1kiaOK^qtEwr6;SmV`s?=K@24%ZUPv2q++{J2%bG ze;JHbw^5HSOAsr5-0Y&taQ)bwGl+_PNh|QgAz-+BJK#`E*Ci*vx0UwA_OugLW`W-D zlVE1viohjqT(ZfR*MCACL+&4TeYTu%ueYhRug9szCI;2GBGkef$Xg%U6lq-8lvZ)^ zjgz40YCtr++tXALPieCKuj{yULRY?#+ zt0-nDZU{@jCELoy6B@Cu-#4zl_3JN~c{L#P(Xb?EEQj+40E&e7x=*!tcPDQTr#yde zONz6u?$%<@Nc4VH?>e zEyrmm?I_Rng=#qnY7Tl6Od9!j$v;xd$uB0%UHqk25nBRs8PI$#9g7!5nH;jUOXwEX z>9%r}5Xye{+gK@Wv#WXV@H#yF0_LYGgjUC`4Sq{;rM`LAQLpTB`w}l4;sNW4|4d2` zfiJ@8xy%u=0VtO_4#m3?9%I|ScgVF%oehjjmXq%yN!fkMvS=@eVGqN|VV7ICpr&N| z%*ZyJTZSmN9bpN~^HA6{@3m)=bNy)#`<(-*l5Ye);CQuB%WDdfVf-cw`e28H+BHOe zSJ1)gF`!+F@LX8!;@td_;W}0-zlk4iiQ~O3`EVzJW*~NaPJt4BGw&G>IrUL*r;!fV zhh!Gy^}DK*Q=*sj>bvu7xAL4_ZnT@WQdzp|5|T&bA~3;`pILOa5|e4#i%4wl-iP~J zP43Lo>F4-c9UJ#H!lF(H`2GT z_Zuzu*`H6>5)p^g;j7<##n(B}Pb1IYu!Wta>vq~srMGn<$0?YH_fC_042RYoQOxfy z^rAKkO!Rx-jHzyf<)c0<@FZK=Rh2iXaGZ23Jn^{xlxFS`@+s0~pP3`wv-aU|ox?3) z#7!b=obYaNPJ6^a+5T7fi3>MjLF1CLk5-%AsutG`D zr5UUUUGLIhC>xtq1OShVF>e+WpjTC0qZ0{vjHpQyJU4p2V^s# zq97c=>2U~8-pCbAr;{x1V`$VafTk$z7gtVBPCGpdfTj`R9|X3lBdh}dT(?=uNqX1&|>(xtVTHGMfp>A=^Qf~C>X_4 z+>?FXEJ3zE#po$!a~&v@Si;ZcDXFN)$3#@S_ZI2~(q{~w&T0M(z>Rb|ud{u<`Ei4m zZ~GR-BG_#BmWM-bHoG>lSykRt5u!Mi$0*5fQu?TfLQ|uOh=zCG+HxEP)wE%qFukOZ zZ1@?fyIC(dhG;j*UbE^e}|a%3ia*Z*Qhc90v;;KB^# zMwc;bh4TEyM&HW4x7B!|YJS^7wl9MRvRwfIfn7fdeG5`GWTwOa9c6KL1CzViH4 zlBR_f0Wb>1lF7Ld|2-XT*^!tVtn+3)F`ugbF&QhX@f~(#k~=_B%bUfXVTPeGe10zI zcXZxuLLTfE zzG9?bBKDUMb9Ca^6LViRtlK@~xgT}bIPF{2WXod@djmq$hQB+D>&aY%WZmP!mVs3$ zIC^tE)QTnZU9h^nq2bTK@87>gAhD^TH!}s7J_Ib+E(v4p?dn+`Mh{&#SxWfO1*tAn z-~^+GH_3Dc(l0mZ(U-m$1(n-2qjf}c@3unlG-Z3@fLGWa zgox#9JzxZ=XyB?{54~EW;~{->Rn)OH&2l}@AR~?Io6`qlb5vaDcAYi-OEp0`?EIfa z2zBRX6-B~A&sVjRDQ-$N$%4P@;?K^ye7Q3F4}q3%@S<8UOx1b;`)&cpMQT+g%Rtdl z;DAYqmKZo1-x_M?=5{px;lqbF+U2u;`Fq+)+l5I7eQ&jjk>V&af~rj5Rt3k@S%@Dv z=ZSvu2)ryIBqbx8a0M;sFre9}x^z$pJ0`L^%yhx{4(MD2Koto(S2Ws@h74o;=UN1k zVpRClHL{vO8j}GJk}c(zGA8v=NO$Z-L$bD_Zmwv{W_jpaEozBBjMD~A;6RLQZ3}lX zH0>02N={&K{sAN)f|AgAC*!be*XIYQN8Gca3UH} zeE_6oD%(V`%X@E9V0UkC0|Fi6`uctnJyFbiex~w&GsFv<^r^N>dOgNQ9z4*^PSD2P zj2B_$Fno_vk|=PdbQ<8v8ivGvdHu7aW&6WNj)r2yHmCTr^AaKh1I^QydwPX$ZC3u~ z!3y=9u)ukimer`k$-}0CBCT?8tUH&BxoBVUPipwzO*Ip5dz6j#()iji3)XJGTgr#S zBgTi5Ae!*o7Ng;t#rsO#%CdzVStSNMhCDu=HIuc8B|f=$JQ+G>g7Z9p(nv<4vD#M= zv4o=o_yQ{A{jN#O#3s+IK30u;npAIa_eQ;f{g*-k0AC#bh)HU$zIK275-pK02;FUa zLb3OlvPWM@EbW~g$*F$Da_2T(BpW4_gYU?SYD!Bs1_>EE+ujtzr3;)PH@ngz*l1Uh z6K7}oka{wBrTQac02%NjI+ko+cRb0D%#P+#zk#SN5IWsj!~+0P=YaV4jsw$WBYemp4zSpGagpt4W}3VSL!tBnt0l>Iinm|!3Tn2z$FS(l}9Nf(nIze>yfEO~p5V`+`#-2Yx zXuy*xH$KI_D+rsf4}fvSXfUKZ-?QAX=HwJ#|0j zBkE?_##tEbgUGG8_r4rn?{fz{D)h*RA&5a@Bw|e+;eNL}eNN<2p?xTcZAgKOm{(Qs zmpHOFXO$0q_`>XYJ)hCo5-J@oOSutT7~7(}luQt0P?B)-^H1gZL8Nl zmDOVNQ^h7%38unti(!eA*&GUZC{m|EIdSKWEyV=bfxz*e8*9Ypt?rFS0t6!h3rCv# zGA*L;B^}y8EEm2SmCVdF!$25Qm56+VCBB6%@t7DESF*xetx$NM%s{+-ro!rp&ScB6 zDTd7_h*P&&@Q~RVRb2xU`{vX-G|@(M^~8e0U)nWwe&f*tcX%G>>_2Q)-8*Dn*Dw|o zI`iU#w=r65DjDTQQY-;h;qoFkV1S|Fbdd2qAO&OY7cMS_n**xM4BtrhlM(R=rSH^K zhD5K+c-<)DKJ$6N4{5*J%AuC@ns21Vxj9}gWhj_*Iv3_8xr@I3u__iB{K|B2^?_QofZ)mUb%cZj5Ue#T(kdr-@x-T_b zyTeY`zl>Q<{!%SW01T!W51ZK}cN4X*wyS9Tf_u|!Nm}a@2Z%-6U33xE4a;Axv9X?= z`b|Lr!RV~4wkbeRLKIyQe(=#Xng|X@fmnE~18?f#bu$fTxbLQ?(J9YLP0fGQC58pz zcyc4}s}NnTtnR#~0gqe_`KMF=R?jc@hIj=*3(R3RIKe~Pe^pSzW?n*s4@n(-(Hoo^ zsKA*<1QF>(?}TGy>zy9u3L%5MV=mIjo+aZq+pOEyBBZ#DVQeuQT%rC6+6R5mE;Uv( zE2Tp$)Hi%q?FX~kFJBftDNmMJ?dyzOyPYXC`|!3zkDft0%jQ$5pBC1{8?d8@to4A% zx`zmr03wiTWiQ{b_6gkq4NExCt~SDk%*Q#mjb$y&bemO?{Jk_4%9%H;dS0UK>9UqF z!`+&j&ubTB@y$NUIwyK3*8uL1*d*qm_`D+XA$mjr3n7$UO;%H6U)2IjhBUbK^;7n# zsNy0N-aVn+>TkVw2J+;`wd=exZZGsVc{hd87Wt_QlgH)exjJR)+RR8Tm=lUWc(TQ3 zn}9=}WAER+D3O6~`WS*!Yj!VqS+TSrkEi2JuI9P~rzz^@7A}(CSHrz%0**6{k=KV~ z&H=Y*TEi`xFEqJzCPKl$^250j;6@)^sKF+eo`}SbL|h0l`6qI*79l0SmGI9m=$MG2 zhWva7dG-*+oJCG!jIsXr3hUX`F6E`#(y?*9hJ3lrS5CGUqMUdlIj&eeFzbVY!S1X4 z6;Up$shr8)Eo8M`xSeDoW-pp4TF>csr{?ACi?6pw9aFojL`G4uHV!9w&r4+*zMQKv zBePVW=B$883HYdRkIdCt^0{pZgg{8sl3 zH$`aJpNxWoiyJ#Ta1@jmjQNhPqQJZJR^aqyoOJ;jf-EVNiyi*8mAIR9?&Phiw=|3F zTg@0l^-VqrZSHOl#0R<3B|9cOkbP#v+uj_*h{3z8r<`?}H!G&zf;s5>L%gwAn6Jhu zk7k#YlB#-FTBj_o*!`RzYY)-=rgTs7r8zzbqv*0;@23!nnyGK=o2Mx?H{rR?DvOK% z@hP+F{alwJdZr&v7h*MBIW@M`zLBSNxzC!a;uWy(UAna={g?45jIzUXOKClYu6u`w zH*x8}v}GA@QS>_wxzo5`j2tA56@i}nAsUulkE$1rxOt8*<#V``X&x5F@lIUmK=FJZ zW)nJ!$?$X~@0)+cjNuXMFyWW0K|6dUnbY-`V>Jsn1A%dHE9eu$CMLaS@iQqTF_dvr zA?k=vT8TdqZ4?9OC*$dSf^C=G{BA+BZcs7Tj(8E;5r)hkr}`pQ&-HSq4n8Y6iH67x z26HoI;h4X%?vlp;q^O1{eJy+z`hDF7zpa&w9%r?O zi91ha@G^7r`<3koA8#c%+2*pDPgc_-Q_L_-z9bC{2D9Z$IW`@G2NLi*AKH>~qa5$h zD?VXQ4){Nei;6yzmS(qbE1tU!nG7NPNI@I(!b#$*5BiIzXxlWb%E`MPg9{JlKmB{~ z=@qRf?m0(xRe_$7&<(+rJpCKQO0UD3ZARi^w8moL)6!=Xst{?8#JH^P?E z3Bz>Zbwz~%Ji{YnxX!)cEWJl)8o0@NC)FVr;=iYFF_mJVOj{GR;5Dhuh_t7DN z@Qqro9O$fgqaffGd-7+^>msZ_c)|iH3%V?6)VTyl<>uL*g>$A%Z7f%9ABXGo>L0Uh zZM)M9--h{pa?LTx7dSI|vRiuXK=QVN^-VTCJF&`lGcYZC-d2OEQ!P{e1h7Gg5BN=& zm-2Vvf$!_VvlUGFtSG+FUpaZ=mTa&>l%5YUvt;0Xe%=2*SuSS0;q|vRm~0KprBCt} z*aOwQx~i&b7kYdR!O0lLVb>$_a*i)Asb$PvBv-=Tp-ZPQsLNp<0PrpU{a=7ApMWc0 zCes(}EMC+P3&t!S6KhZIZc{kx^7#c=ELO@8apq;)759d#H}WJsXU!xw8Pql1TnpVl z?CuZlE$FO`YQNCSa#L5O*1voP-l%)GWqdGGPxm;lGVo0E*&i4J$FIu|>-O1++s|Ed zjM5DFoGsV-!;}MM_w#{iIAUsC&c&`b+fZ2snecU<>Tox2PVg5%IP7Wn9=o>do?ZY( zBbi>;cE^IYNkirma(ui;8-TfY>1~RhjJkd?6WHnFj#Y5`ApRbU!%y|imp!83(_3@% z{sErZ)4qa&uNYx&gzgXHZ>|eA4El_DMj3yr$`SIer!i+y;{P)Ea(ec2ww31kqkBFa zuYlKuG(qt+dFtsVl|PA08Ouxz-D*_9{cap@*!(+SL0m8O&D8em$J^n68&2t1%LiTf zk5|3ZaA5NV#O(p)AVN_sro5l=SmB%fP#^^1qge1wCFpUBf|#OS-S@ z&{uA$uHqt(e@MZ6M7SUm0Q_?0W!FSY)6t4ZX79saD5;*#T_4XYYrAo7hMj0%W=xEI z7-L^%nq-L>RMs(;TPX%DmPD59G$dLu#?X*dQr8}pi<@;U(Zw*9xD_EgVKj_n8N!e- z-?`uKpYZ+ZJm);;dCu~jAI|%=U4j60svv(qRPm}CT4ZwTV1%$l2-cGX&KiD$$Go~y z;T>ABSTa{{OqE$`8bsW=dsog>!1U%}!qPt6^nDrLh&(^fsz^WbVTAJGPv7UYoH_Xy z6JIJ7i=>XJW#DcxIdi3#|59WJH0?G%rSE>h5h!y3ythvw3~66V#dE! zRN7m%o0Z@Ttzh8Lu!gE7cyaOWDE|=NG*RtfHsa1|&Ka*nk<9)cC0G!nzh46IM1x8a z(uPmbbI$jl1LJ}NF#WbVUH4*LKI(Z3#;|$1y~TS%vPJ?4Fw!96or5|FEj4Od^QoR& z^A8jGMQ=pgqq# zaGBd5aY#fJ1k`7PG87!n1WP)WG2ri9gL6GQAktEwEgy|z{!~>2z4nE~M8!(=Rh)`g zdyx0odBwQVYi0d>dP2=JYLq*%G-XLedi}u?{#&HZTk+gVT0?TKN(CLeL$w+(Dvx-y z_gE3q^X+Y$LQ&b@$~5tA0#{6VuXfUNlfx575kCpV%4F^VXJq|tVJOdR$a0a^Jq&-L)0~N-_r;V_WSn!@9gkG- z%mu8Q{uJ?0J|ko1ybqBafpD@5&cR4NNR&g32ai=o4!|EXkx)xUcq=01_1HHZvh}S- z8uNWASv-!Gyd*Y(R*KLND~Rca5a<1Ka@wjRl^U?9S)NJ4bf-B{AioSZ5^LKXd=v5I z2Ut(vpA;l{uwloxSYHd5rI?LO>c8?g!z$e5T*f6`;iJB`^Fsv_Ryn<%!_t?=KC}fn zL-%xD=9H`);?bR0?EVj0Cu@VdD}2Gwe>uK&`78rID>sNQ_$OTGT#Q$71NlUru~3PO#2DRE7sEs#+Ht)^+?oDS3n zKeKc-PR9zY(3RE(zCbu&XA9jsB=oP3Gkt+{P>tE^Q?~hl0t>R2q`;C3ueo)ia%+&@-JCuJtSdPOu zG4fkHLRPjl|L){^RUTL@J&F_vqJ?})ecA-=A!*}}r^roH z=J-xXzp+3t;$Ci01CPY`nr{}}1LrOl90>B_R!-{4Z6`MpUtX%+_Q-tkXPc37X6JMe zm~DOhy%#%5;>0*n<(AUlWm0mP^8?#A8m_ArOZ^x9@a4iYbzXgnF^Il1__X_H=oEWM zjQ{u=-g>0eOdW=1QioSgdHwRc(WYTwiLGkgxhqPN7dE=G!B3rWy6s&*7qRlDB!9P?2XwOSp(sJROYC>v4^qx0dTUda z%HlI5t_AN@etMmO*?r<&z4Kka&olx?fu{}g^_LzpJVB0svSEUf6qY&-I9a7`#bb_X z`)p3Mx3@Fx&G$DKZn;<0mz5Wsr4wCmgyDTKT09Njlc{Jn?OLKl!!-;2tR&j05rY4f z-)EubuwVe7ORIQ+EX%iV<3S&ncm7+en^zy_n=h5udYJ3!-ONWqePm(TlI}L-VEp-@ zoTC!XgPy5W3ysUXdu`{rz1cClizV#)s68z=as6f2N3r7-y=Sw~^IG!R9j21XY47qtPAjL~Jn48X@_D@R(~t{Ph7x_X zo8bPaab)L`m-xJ|C1JlF4?6uA@D_au%DkGuLK*IX`W2;zJg@!u=i+BjFj%tHbM854 z_EvYbWa`;E&65H5$L%1j1bYTnsRv5h+SDR-Ykn_fHrOd7r?2s0Kx6&7(5Q1}t99Z- z14Gi~Mu#Tm6#=pYko(3#p$#parkPW!UhCQk<@bj@zPytiHP4zWbZvRjJ*IZEU7Yt$ z!2*JYv7oFqVO?ci@j|sQp}3~M3URt%h8Nz(SP+Obxa`PsmqyFVf?U|ugCDvB`}Ji? z?oS0Q*YR0PVnFX+T7ZRe+WQjo_x)_ywzwZX#@A0A`3bE&s4cfXoXmqmo_eMM=aF*b znW0cm#4Y|~AVU*!l*$qeC-Bv3ppcXWOwhgIVKuF8?E`oSJ+Z}E6wp;n&(ldCZcFU_ zqZ`U!%+r)DPxiWhHEtjvh-C{il<3_^D_cOR9|;Ps_bTg1tKGg`%KiMWCF`R65HIvh zLq-9B@7-g<#X;nbpariZLlX9fD4-J5aIe_h)dwFl45DNq1*oIIlK>tLyYY%Is-qxs9MiCD+2}i| zlf{pGI|k&)1A}01QKVtHJW2n^*Ty~@h?Uxo2nMu6I-l;ibf@W}6H3}1W{^&K`fx}O zg4DJmjq$@2M_hrDwGLmdgAfgY0c`@AQgbUF{A30>@PvWp@sj}Sc@0X=_arJ0v#Tu| z^{V0UQBqp}Vo^Yvm5D&%4Nn`J?8tG!;6@Ersw5f`a+F7*W&!*p504`c{RS$XYgF~e zg>*tw*I-F}XB4I5SO3oF;^moOKp}c*6*)C(r;(jjq}iks6KQ-nAIa|uC$0IG7O2OM zl4b>x{8qt;YNv*5oENN7?jh`?Tqi_#^QD%>12FS$S3W6M;Ik=26J;GyX+I$B4VI0{ z+c+p7r)l8+9igjT%1lIIDAJ0DW~CHqizvl|ZJ&U|7`Ub7Amo3iuFqf_2kepu{CoCp zN&GS+ball2f-P4In4y(*#01K*-!b*_$-3n1Pcu-ohON#&s%|hieT|-s3lZc`saAC$ z9(*8PQV<7G_{z649o&8$f7yp~wsz1Snns=;!igy0*8APxEm@gc4-T8u;gNV@EF_?3 zsaEx4%_IAoYMuOznP$(sYA(}fG7j8DKS5>T^t6}N6jUzT-^XHMf)8_2CX40oe#LYs zke&rlAfnoI?G=~QUQsu2I#ns2cLY6`WMtO}?pm$rdk75OC4JgdRQA8d7QlFicy<2Y f*#EcF#TEBSi42%HA%x&1^#L}2;H@hyJ<0zAY)pcM literal 0 HcmV?d00001 diff --git a/src/petab_gui/utils.py b/src/petab_gui/utils.py index 6045b00..f66ed4d 100644 --- a/src/petab_gui/utils.py +++ b/src/petab_gui/utils.py @@ -599,6 +599,12 @@ def get_selected_rectangles(table_view: QTableView) -> np.array: selected = get_selected(table_view, mode=INDEX) if not selected: return None + + model = table_view.model() + if hasattr(model, "mapToSource"): + # map all indices to source + selected = [model.mapToSource(index) for index in selected] + rows = [index.row() for index in selected] cols = [index.column() for index in selected] min_row, max_row = min(rows), max(rows) @@ -609,6 +615,7 @@ def get_selected_rectangles(table_view: QTableView) -> np.array: ) for index in selected: selected_rect[index.row() - min_row, index.column() - min_col] = True + return selected_rect, rect_start diff --git a/src/petab_gui/views/table_view.py b/src/petab_gui/views/table_view.py index 12d4180..87c50a0 100644 --- a/src/petab_gui/views/table_view.py +++ b/src/petab_gui/views/table_view.py @@ -41,33 +41,43 @@ def paste_from_clipboard(self): text = clipboard.text() if not text: return + + # Get the proxy and source models + proxy_model = self.table_view.model() + source_model = proxy_model.sourceModel() + + # Get the start index from the current selection start_index = self.table_view.selectionModel().currentIndex() if not start_index.isValid(): return - model = self.table_view.model() - row_start, col_start = start_index.row(), start_index.column() - # identify which invalid cells are being pasted into + + # Map the start index to the source model + source_index = proxy_model.mapToSource(start_index) + row_start, col_start = source_index.row(), source_index.column() + + # Parse clipboard data pasted_data = [line.split("\t") for line in text.split("\n") if line.strip()] num_rows = len(pasted_data) - num_cols = max([len(line) for line in pasted_data]) + num_cols = max(len(line) for line in pasted_data) + + # Identify which cells are being overridden overridden_cells = { (row_start + r, col_start + c) for r in range(num_rows) for c in range(num_cols) - if model.index(row_start + r, col_start + c).isValid() + if source_model.index(row_start + r, col_start + c).isValid() } - invalid_overridden_cells = overridden_cells.intersection( - model._invalid_cells - ) - if invalid_overridden_cells: + + # Handle invalid cells + if hasattr(source_model, "_invalid_cells"): + invalid_overridden_cells = overridden_cells.intersection( + source_model._invalid_cells) for row_invalid, col_invalid in invalid_overridden_cells: - model.discard_invalid_cell(row_invalid, col_invalid) + source_model.discard_invalid_cell(row_invalid, col_invalid) - model.setDataFromText( - text, start_index.row(), - start_index.column() - ) + # Paste the data into the source model + source_model.setDataFromText(text, row_start, col_start) class ComboBoxDelegate(QStyledItemDelegate): From 640d36f5e2492071886e0f24842400ab0270c05b Mon Sep 17 00:00:00 2001 From: PaulJonasJost Date: Tue, 15 Apr 2025 16:24:31 +0200 Subject: [PATCH 2/3] Fixed typesetting in copy/paste --- src/petab_gui/C.py | 2 +- src/petab_gui/models/pandas_table_model.py | 16 ++++++++++++---- src/petab_gui/utils.py | 6 ++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/petab_gui/C.py b/src/petab_gui/C.py index 2a9efc4..814c95c 100644 --- a/src/petab_gui/C.py +++ b/src/petab_gui/C.py @@ -38,7 +38,7 @@ "conditionId": {"type": np.object_, "optional": False}, "conditionName": {"type": np.object_, "optional": False}, } - } +} CONFIG = { 'window_title': 'My Application', diff --git a/src/petab_gui/models/pandas_table_model.py b/src/petab_gui/models/pandas_table_model.py index c690783..47c1a71 100644 --- a/src/petab_gui/models/pandas_table_model.py +++ b/src/petab_gui/models/pandas_table_model.py @@ -180,10 +180,18 @@ def _set_data_single(self, index, value): column_name = self._data_frame.columns[column - col_setoff] old_value = self._data_frame.iloc[row, column - col_setoff] # cast to numeric if necessary - if not self._data_frame[column_name].dtype == "object": - try: - value = float(value) - except ValueError: + expected_type = self._allowed_columns.get(column_name, None) + if is_invalid(value): + if not expected_type["optional"]: + return False + self._data_frame.iloc[row, column - col_setoff] = None + self.dataChanged.emit(index, index, [Qt.DisplayRole]) + return True + if expected_type: + expected_type = expected_type["type"] + tried_value = value + value, error_message = validate_value(value, expected_type) + if error_message: self.new_log_message.emit( f"Column '{column_name}' expects a numeric value", "red" diff --git a/src/petab_gui/utils.py b/src/petab_gui/utils.py index f66ed4d..279bb16 100644 --- a/src/petab_gui/utils.py +++ b/src/petab_gui/utils.py @@ -488,12 +488,10 @@ def highlightBlock(self, text): def validate_value(value, expected_type): try: - if expected_type == "STRING": + if expected_type == np.object_: value = str(value) - elif expected_type == "NUMERIC": + elif expected_type == np.float64: value = float(value) - elif expected_type == "BOOLEAN": - value = bool(value) except ValueError as e: return None, str(e) return value, None From 1659728e9d7de0c11df463c92729cc57c9c03357 Mon Sep 17 00:00:00 2001 From: PaulJonasJost Date: Tue, 15 Apr 2025 16:30:00 +0200 Subject: [PATCH 3/3] Removed superfluous line --- src/petab_gui/models/pandas_table_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/petab_gui/models/pandas_table_model.py b/src/petab_gui/models/pandas_table_model.py index 47c1a71..9973885 100644 --- a/src/petab_gui/models/pandas_table_model.py +++ b/src/petab_gui/models/pandas_table_model.py @@ -189,7 +189,6 @@ def _set_data_single(self, index, value): return True if expected_type: expected_type = expected_type["type"] - tried_value = value value, error_message = validate_value(value, expected_type) if error_message: self.new_log_message.emit(