Refactor FileChooserDialogs

Use GtkFileChooserDialog only when we need previews, default to
NativeFileChooser otherwise.

GtkFileChooserDialogs have a long list of issues, so lets only use it
if we gain something from it.

Flatpak should only run NativeFileChoosers because its sandboxed and
this is needed for security purposes. As a result of that, Flatpak Users
dont have image previews in the FileOpenDialogs

Refactor all FileChoosers for a more simple approach when we use them

Add a new SendFileDialog, so we dont have to put widgets into the FileChooser
which forces non-native Dialogs.
This commit is contained in:
Philipp Hörist 2018-05-04 00:36:10 +02:00
parent bb33e055a5
commit c38db84e04
13 changed files with 569 additions and 499 deletions

View File

@ -155,6 +155,7 @@ _dependencies = {
'PYCURL': False, 'PYCURL': False,
'GSPELL': False, 'GSPELL': False,
'IDLE': False, 'IDLE': False,
'RUN_AS_FLATPAK': False,
} }
@ -167,6 +168,9 @@ def is_installed(dependency):
return _dependencies['AVAHI'] or _dependencies['PYBONJOUR'] return _dependencies['AVAHI'] or _dependencies['PYBONJOUR']
return _dependencies[dependency] return _dependencies[dependency]
def is_flatpak():
return _dependencies['RUN_AS_FLATPAK']
def disable_dependency(dependency): def disable_dependency(dependency):
_dependencies[dependency] = False _dependencies[dependency] = False

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.21.0 --> <!-- Generated with glade 3.22.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.12"/> <requires lib="gtk+" version="3.12"/>
<object class="GtkMenu" id="context_menu"> <object class="GtkMenu" id="context_menu">
@ -22,70 +22,6 @@
</object> </object>
</child> </child>
</object> </object>
<object class="GtkFileChooserDialog" id="filechooserdialog">
<property name="can_focus">False</property>
<property name="type_hint">dialog</property>
<property name="action">save</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">24</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save_button">
<property name="label">gtk-save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">cancel_button</action-widget>
<action-widget response="-5">save_button</action-widget>
</action-widgets>
<child>
<placeholder/>
</child>
</object>
<object class="GtkImage" id="image1"> <object class="GtkImage" id="image1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
@ -98,6 +34,9 @@
<property name="default_width">650</property> <property name="default_width">650</property>
<property name="default_height">500</property> <property name="default_height">500</property>
<signal name="delete-event" handler="on_history_manager_window_delete_event" swapped="no"/> <signal name="delete-event" handler="on_history_manager_window_delete_event" swapped="no"/>
<child>
<placeholder/>
</child>
<child> <child>
<object class="GtkBox" id="vbox"> <object class="GtkBox" id="vbox">
<property name="visible">True</property> <property name="visible">True</property>
@ -306,8 +245,5 @@ If you plan to do massive deletions, please make sure Gajim is not running. Gene
</child> </child>
</object> </object>
</child> </child>
<child>
<placeholder/>
</child>
</object> </object>
</interface> </interface>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 --> <!-- Generated with glade 3.22.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.12"/> <requires lib="gtk+" version="3.12"/>
<object class="GtkWindow" id="profile_window"> <object class="GtkWindow" id="profile_window">
@ -8,6 +8,9 @@
<property name="type_hint">dialog</property> <property name="type_hint">dialog</property>
<signal name="destroy" handler="on_profile_window_destroy" swapped="no"/> <signal name="destroy" handler="on_profile_window_destroy" swapped="no"/>
<signal name="key-press-event" handler="on_profile_window_key_press_event" swapped="no"/> <signal name="key-press-event" handler="on_profile_window_key_press_event" swapped="no"/>
<child>
<placeholder/>
</child>
<child> <child>
<object class="GtkBox" id="vbox1"> <object class="GtkBox" id="vbox1">
<property name="visible">True</property> <property name="visible">True</property>
@ -30,10 +33,10 @@
<object class="GtkLabel" id="label24"> <object class="GtkLabel" id="label24">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Name:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Name:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -54,10 +57,10 @@
<object class="GtkLabel" id="label20"> <object class="GtkLabel" id="label20">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Nickname:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Nickname:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -89,10 +92,10 @@
<object class="GtkLabel" id="label18"> <object class="GtkLabel" id="label18">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes" comments="Family Name">&lt;b&gt;Family:&lt;/b&gt;</property> <property name="label" translatable="yes" comments="Family Name">&lt;b&gt;Family:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -113,10 +116,10 @@
<object class="GtkLabel" id="label17"> <object class="GtkLabel" id="label17">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes" comments="Given Name">&lt;b&gt;Given:&lt;/b&gt;</property> <property name="label" translatable="yes" comments="Given Name">&lt;b&gt;Given:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -137,10 +140,10 @@
<object class="GtkLabel" id="label16"> <object class="GtkLabel" id="label16">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes" comments="Middle Name">&lt;b&gt;Middle:&lt;/b&gt;</property> <property name="label" translatable="yes" comments="Middle Name">&lt;b&gt;Middle:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -151,10 +154,10 @@
<object class="GtkLabel" id="label15"> <object class="GtkLabel" id="label15">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes" comments="Prefix in Name">&lt;b&gt;Prefix:&lt;/b&gt;</property> <property name="label" translatable="yes" comments="Prefix in Name">&lt;b&gt;Prefix:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -185,10 +188,10 @@
<object class="GtkLabel" id="label14"> <object class="GtkLabel" id="label14">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes" comments="Suffix in Name">&lt;b&gt;Suffix:&lt;/b&gt;</property> <property name="label" translatable="yes" comments="Suffix in Name">&lt;b&gt;Suffix:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -217,10 +220,10 @@
<object class="GtkLabel" id="label19"> <object class="GtkLabel" id="label19">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Full Name&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Full Name&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object> </object>
</child> </child>
</object> </object>
@ -245,10 +248,10 @@
<object class="GtkLabel" id="label31"> <object class="GtkLabel" id="label31">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Street:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Street:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -269,10 +272,10 @@
<object class="GtkLabel" id="label29"> <object class="GtkLabel" id="label29">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Extra Address:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Extra Address:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -293,10 +296,10 @@
<object class="GtkLabel" id="label28"> <object class="GtkLabel" id="label28">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;City:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;City:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -317,10 +320,10 @@
<object class="GtkLabel" id="label26"> <object class="GtkLabel" id="label26">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Postal Code:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Postal Code:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -341,10 +344,10 @@
<object class="GtkLabel" id="label27"> <object class="GtkLabel" id="label27">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;State:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;State:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -365,10 +368,10 @@
<object class="GtkLabel" id="label25"> <object class="GtkLabel" id="label25">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Country:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Country:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -391,10 +394,10 @@
<object class="GtkLabel" id="label30"> <object class="GtkLabel" id="label30">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Address&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Address&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object> </object>
</child> </child>
</object> </object>
@ -408,10 +411,10 @@
<object class="GtkLabel" id="label22"> <object class="GtkLabel" id="label22">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Homepage:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Homepage:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -433,9 +436,9 @@
<object class="GtkLabel" id="label57"> <object class="GtkLabel" id="label57">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">&lt;b&gt;E-Mail:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;E-Mail:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -457,10 +460,10 @@
<object class="GtkLabel" id="label23"> <object class="GtkLabel" id="label23">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Phone No.:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Phone No.:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -492,10 +495,10 @@
<object class="GtkLabel" id="label58"> <object class="GtkLabel" id="label58">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Avatar:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Avatar:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -506,12 +509,11 @@
<object class="GtkBox" id="hbox3"> <object class="GtkBox" id="hbox3">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="spacing">6</property>
<child> <child>
<object class="GtkButton" id="PHOTO_button"> <object class="GtkButton" id="PHOTO_button">
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<signal name="button-press-event" handler="on_PHOTO_button_press_event" swapped="no"/> <signal name="button-press-event" handler="on_PHOTO_button_press_event" swapped="no"/>
<child> <child>
<object class="GtkEventBox" id="PHOTO_eventbox3"> <object class="GtkEventBox" id="PHOTO_eventbox3">
@ -522,7 +524,6 @@
<object class="GtkImage" id="PHOTO_image"> <object class="GtkImage" id="PHOTO_image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="yalign">0</property>
<property name="stock">gtk-missing-image</property> <property name="stock">gtk-missing-image</property>
</object> </object>
</child> </child>
@ -543,8 +544,6 @@
<property name="receives_default">False</property> <property name="receives_default">False</property>
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<signal name="button-press-event" handler="on_PHOTO_button_press_event" swapped="no"/> <signal name="button-press-event" handler="on_PHOTO_button_press_event" swapped="no"/>
</object> </object>
<packing> <packing>
@ -553,10 +552,31 @@
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkButton" id="remove_avatar">
<property name="label" translatable="yes">Remove Avatar</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="no_show_all">True</property>
<property name="tooltip_text" translatable="yes">Clear Avatar</property>
<property name="halign">start</property>
<property name="valign">end</property>
<signal name="clicked" handler="_clear_photo" swapped="no"/>
<style>
<class name="destructive-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="top_attach">6</property> <property name="top_attach">6</property>
<property name="width">3</property>
</packing> </packing>
</child> </child>
<child> <child>
@ -569,10 +589,10 @@
<object class="GtkLabel" id="label13"> <object class="GtkLabel" id="label13">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Birthday:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Birthday:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
</child> </child>
</object> </object>
@ -581,21 +601,15 @@
<property name="top_attach">5</property> <property name="top_attach">5</property>
</packing> </packing>
</child> </child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object> </object>
</child> </child>
<child type="tab"> <child type="tab">
<object class="GtkLabel" id="label4"> <object class="GtkLabel" id="label4">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="label" translatable="yes">Personal Info</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="yalign">0</property> <property name="yalign">0</property>
<property name="label" translatable="yes">Personal Info</property>
</object> </object>
<packing> <packing>
<property name="tab_fill">False</property> <property name="tab_fill">False</property>
@ -612,10 +626,10 @@
<object class="GtkLabel" id="label44"> <object class="GtkLabel" id="label44">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Company:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Company:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -636,10 +650,10 @@
<object class="GtkLabel" id="label43"> <object class="GtkLabel" id="label43">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Department:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Department:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -660,10 +674,10 @@
<object class="GtkLabel" id="label42"> <object class="GtkLabel" id="label42">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Position:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Position:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -684,10 +698,10 @@
<object class="GtkLabel" id="label41"> <object class="GtkLabel" id="label41">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Role:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Role:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -719,10 +733,10 @@
<object class="GtkLabel" id="label39"> <object class="GtkLabel" id="label39">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Street:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Street:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -743,10 +757,10 @@
<object class="GtkLabel" id="label38"> <object class="GtkLabel" id="label38">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Extra Address:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Extra Address:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -767,10 +781,10 @@
<object class="GtkLabel" id="label37"> <object class="GtkLabel" id="label37">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;City:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;City:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -791,10 +805,10 @@
<object class="GtkLabel" id="label35"> <object class="GtkLabel" id="label35">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Postal Code:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Postal Code:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -815,10 +829,10 @@
<object class="GtkLabel" id="label36"> <object class="GtkLabel" id="label36">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;State:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;State:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -839,10 +853,10 @@
<object class="GtkLabel" id="label34"> <object class="GtkLabel" id="label34">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Country:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Country:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">2</property> <property name="left_attach">2</property>
@ -865,10 +879,10 @@
<object class="GtkLabel" id="label40"> <object class="GtkLabel" id="label40">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Address&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Address&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
</child> </child>
</object> </object>
@ -882,10 +896,10 @@
<object class="GtkLabel" id="label32"> <object class="GtkLabel" id="label32">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;E-Mail:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;E-Mail:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -907,10 +921,10 @@
<object class="GtkLabel" id="label33"> <object class="GtkLabel" id="label33">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">&lt;b&gt;Phone No.:&lt;/b&gt;</property> <property name="label" translatable="yes">&lt;b&gt;Phone No.:&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
@ -942,9 +956,9 @@
<object class="GtkLabel" id="label5"> <object class="GtkLabel" id="label5">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="label" translatable="yes">Work</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="yalign">0</property> <property name="yalign">0</property>
<property name="label" translatable="yes">Work</property>
</object> </object>
<packing> <packing>
<property name="position">1</property> <property name="position">1</property>
@ -974,9 +988,9 @@
<object class="GtkLabel" id="label6"> <object class="GtkLabel" id="label6">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="label" translatable="yes" comments="&quot;About&quot; is the text of a tab of vcard window">About</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="yalign">0</property> <property name="yalign">0</property>
<property name="label" translatable="yes" comments="&quot;About&quot; is the text of a tab of vcard window">About</property>
</object> </object>
<packing> <packing>
<property name="position">2</property> <property name="position">2</property>

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkGrid" id="send_file_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBox" id="listbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="vexpand">True</property>
<property name="selection_mode">none</property>
<property name="activate_on_single_click">False</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Description:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="height_request">40</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="description">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="wrap_mode">word-char</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Select Files</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">start</property>
<signal name="clicked" handler="_select_files" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Send</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">end</property>
<signal name="clicked" handler="_send" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Files:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
</packing>
</child>
</object>
</interface>

View File

@ -99,3 +99,7 @@ popover#EmoticonPopover flowboxchild { padding-top: 5px; padding-bottom: 5px; }
/*MessageWindow Notebook*/ /*MessageWindow Notebook*/
.notebook-tab-label {min-width: 80px} .notebook-tab-label {min-width: 80px}
/*SendFileDialog*/
#SendFileDialog grid {padding: 12px}
#SendFileDialog grid list { background-color: @theme_bg_color}

View File

@ -1426,74 +1426,6 @@ class HigDialog(Gtk.MessageDialog):
vb.grab_focus() vb.grab_focus()
self.show_all() self.show_all()
class FileChooserDialog(Gtk.FileChooserDialog):
"""
Non-blocking FileChooser Dialog around Gtk.FileChooserDialog
"""
def __init__(self, title_text, action, buttons, default_response,
select_multiple=False, current_folder=None, on_response_ok=None,
on_response_cancel=None, preview=False, transient_for=None):
Gtk.FileChooserDialog.__init__(self, title=title_text,
parent=transient_for, action=action)
self.add_button(buttons[0],buttons[1])
if len(buttons) ==4:
self.add_button(buttons[2],buttons[3])
self.set_default_response(default_response)
self.set_select_multiple(select_multiple)
if current_folder and os.path.isdir(current_folder):
self.set_current_folder(current_folder)
else:
self.set_current_folder(os.path.expanduser('~'))
self.response_ok, self.response_cancel = \
on_response_ok, on_response_cancel
# in gtk+-2.10 clicked signal on some of the buttons in a dialog
# is emitted twice, so we cannot rely on 'clicked' signal
self.connect('response', self.on_dialog_response)
if preview:
self.set_use_preview_label(False)
self.set_preview_widget(Gtk.Image())
self.connect('selection-changed', self.update_preview)
self.show_all()
def on_dialog_response(self, dialog, response):
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.CLOSE):
if self.response_cancel:
if isinstance(self.response_cancel, tuple):
self.response_cancel[0](dialog, *self.response_cancel[1:])
else:
self.response_cancel(dialog)
else:
self.just_destroy(dialog)
elif response == Gtk.ResponseType.OK:
if self.response_ok:
if isinstance(self.response_ok, tuple):
self.response_ok[0](dialog, *self.response_ok[1:])
else:
self.response_ok(dialog)
else:
self.just_destroy(dialog)
def update_preview(self, widget):
path_to_file = widget.get_preview_filename()
preview = widget.get_preview_widget()
if path_to_file is None or os.path.isdir(path_to_file):
# nothing to preview or directory
# make sure you clean image do show nothing
preview.clear()
return
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path_to_file, 200, 200)
except GObject.GError:
preview.clear()
return
widget.get_preview_widget().set_from_pixbuf(pixbuf)
def just_destroy(self, widget):
self.destroy()
class AspellDictError: class AspellDictError:
def __init__(self, lang): def __init__(self, lang):
ErrorDialog( ErrorDialog(
@ -4773,139 +4705,6 @@ class ProgressDialog:
def on_progress_dialog_delete_event(self, widget, event): def on_progress_dialog_delete_event(self, widget, event):
return True # WM's X button or Escape key should not destroy the window return True # WM's X button or Escape key should not destroy the window
class ImageChooserDialog(FileChooserDialog):
def __init__(self, path_to_file='', on_response_ok=None,
on_response_cancel=None):
"""
Optionally accepts path_to_snd_file so it has that as selected
"""
def on_ok(widget, callback):
'''check if file exists and call callback'''
path_to_file = self.get_filename()
if not path_to_file:
return
if os.path.exists(path_to_file):
if isinstance(callback, tuple):
callback[0](widget, path_to_file, *callback[1:])
else:
callback(widget, path_to_file)
path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES)
FileChooserDialog.__init__(self,
title_text = _('Choose Image'),
action = Gtk.FileChooserAction.OPEN,
buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK),
default_response = Gtk.ResponseType.OK,
current_folder = path,
on_response_ok = (on_ok, on_response_ok),
on_response_cancel = on_response_cancel)
if on_response_cancel:
self.connect('destroy', on_response_cancel)
filter_ = Gtk.FileFilter()
filter_.set_name(_('All files'))
filter_.add_pattern('*')
self.add_filter(filter_)
filter_ = Gtk.FileFilter()
filter_.set_name(_('Images'))
filter_.add_mime_type('image/png')
filter_.add_mime_type('image/jpeg')
filter_.add_mime_type('image/gif')
filter_.add_mime_type('image/tiff')
filter_.add_mime_type('image/svg+xml')
filter_.add_mime_type('image/x-xpixmap') # xpm
self.add_filter(filter_)
self.set_filter(filter_)
if path_to_file:
self.set_filename(path_to_file)
self.set_use_preview_label(False)
self.set_preview_widget(Gtk.Image())
self.connect('selection-changed', self.update_preview)
def update_preview(self, widget):
path_to_file = widget.get_preview_filename()
if path_to_file is None or os.path.isdir(path_to_file):
# nothing to preview or directory
# make sure you clean image do show nothing
preview = widget.get_preview_widget()
preview.clear()
return
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path_to_file, 100, 100)
except GObject.GError:
return
widget.get_preview_widget().set_from_pixbuf(pixbuf)
class AvatarChooserDialog(ImageChooserDialog):
def __init__(self, path_to_file='', on_response_ok=None,
on_response_cancel=None, on_response_clear=None):
ImageChooserDialog.__init__(self, path_to_file, on_response_ok,
on_response_cancel)
button = Gtk.Button(None, Gtk.STOCK_CLEAR)
self.response_clear = on_response_clear
if on_response_clear:
button.connect('clicked', self.on_clear)
button.show_all()
action_area = self.get_action_area()
action_area.pack_start(button, True, True, 0)
action_area.reorder_child(button, 0)
def on_clear(self, widget):
if isinstance(self.response_clear, tuple):
self.response_clear[0](widget, *self.response_clear[1:])
else:
self.response_clear(widget)
class ArchiveChooserDialog(FileChooserDialog):
def __init__(self, on_response_ok=None, on_response_cancel=None,
transient_for=None):
def on_ok(widget, callback):
'''check if file exists and call callback'''
path_to_file = self.get_filename()
if not path_to_file:
return
if os.path.exists(path_to_file):
if isinstance(callback, tuple):
callback[0](path_to_file, *callback[1:])
else:
callback(path_to_file)
self.destroy()
path = os.path.expanduser('~')
FileChooserDialog.__init__(self,
title_text=_('Choose Archive'),
action=Gtk.FileChooserAction.OPEN,
buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK),
default_response=Gtk.ResponseType.OK,
current_folder=path,
on_response_ok=(on_ok, on_response_ok),
on_response_cancel=on_response_cancel,
transient_for=transient_for)
if on_response_cancel:
self.connect('destroy', on_response_cancel)
filter_ = Gtk.FileFilter()
filter_.set_name(_('All files'))
filter_.add_pattern('*')
self.add_filter(filter_)
filter_ = Gtk.FileFilter()
filter_.set_name(_('Zip files'))
filter_.add_pattern('*.zip')
self.add_filter(filter_)
self.set_filter(filter_)
class TransformChatToMUC: class TransformChatToMUC:
# Keep a reference on windows so garbage collector don't restroy them # Keep a reference on windows so garbage collector don't restroy them
instances = [] instances = []

212
gajim/filechoosers.py Normal file
View File

@ -0,0 +1,212 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
import os
from pathlib import Path
from collections import namedtuple
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import GObject
from gajim.common import app
Filter = namedtuple('Filter', 'name pattern default')
# Notes: Adding mime types to Gtk.FileFilter forces non-native dialogs
class BaseFileChooser:
def _on_response(self, dialog, response, accept_cb, cancel_cb):
if response == Gtk.ResponseType.ACCEPT:
if self.get_select_multiple():
accept_cb(dialog.get_filenames())
else:
accept_cb(dialog.get_filename())
if response in (Gtk.ResponseType.CANCEL,
Gtk.ResponseType.DELETE_EVENT):
if cancel_cb is not None:
cancel_cb()
def _add_filters(self, filters):
for filterinfo in filters:
filter_ = Gtk.FileFilter()
filter_.set_name(filterinfo.name)
if isinstance(filterinfo.pattern, list):
for mime_type in filterinfo.pattern:
filter_.add_mime_type(mime_type)
else:
filter_.add_pattern(filterinfo.pattern)
self.add_filter(filter_)
if filterinfo.default:
self.set_filter(filter_)
def _update_preview(self, filechooser):
path_to_file = filechooser.get_preview_filename()
preview = filechooser.get_preview_widget()
if path_to_file is None or os.path.isdir(path_to_file):
# nothing to preview
preview.clear()
return
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
path_to_file, *self._preivew_size)
except GObject.GError:
preview.clear()
return
filechooser.get_preview_widget().set_from_pixbuf(pixbuf)
class BaseFileOpenDialog:
_title = _('Choose File to Send…')
_filters = [Filter(_('All files'), '*', True)]
class BaseAvatarChooserDialog:
_title = _('Choose Avatar…')
_preivew_size = (100, 100)
if app.is_flatpak():
_filters = [Filter(_('PNG files'), '*.png', True),
Filter(_('JPEG files'), '*.jp*g', False),
Filter(_('SVG files'), '*.svg', False)]
else:
_filters = [Filter(_('Images'), ['image/png',
'image/jpeg',
'image/svg+xml'], True)]
class NativeFileChooserDialog(Gtk.FileChooserNative, BaseFileChooser):
_title = ''
_filters = []
_action = Gtk.FileChooserAction.OPEN
def __init__(self, accept_cb, cancel_cb=None, transient_for=None,
path=None, file_name=None, select_multiple=False,
modal=False):
Gtk.FileChooserNative.__init__(self,
title=self._title,
action=self._action,
transient_for=transient_for)
self.set_current_folder(path or str(Path.home()))
if file_name is not None:
self.set_current_name(file_name)
self.set_select_multiple(select_multiple)
self.set_do_overwrite_confirmation(True)
self.set_modal(modal)
self._add_filters(self._filters)
self.connect('response', self._on_response, accept_cb, cancel_cb)
self.show()
class ArchiveChooserDialog(NativeFileChooserDialog):
_title = _('Choose Archive')
_filters = [Filter(_('All files'), '*', False),
Filter(_('ZIP files'), '*.zip', True)]
class FileSaveDialog(NativeFileChooserDialog):
_title = _('Save File as…')
_filters = [Filter(_('All files'), '*', True)]
_action = Gtk.FileChooserAction.SAVE
class AvatarSaveDialog(FileSaveDialog):
if os.name == 'nt':
_filters = [Filter(_('Images'), '*.png;*.jpg;*.jpeg;*.svg', True)]
class NativeFileOpenDialog(BaseFileOpenDialog, NativeFileChooserDialog):
pass
class NativeAvatarChooserDialog(BaseAvatarChooserDialog, NativeFileChooserDialog):
pass
class GtkFileChooserDialog(Gtk.FileChooserDialog, BaseFileChooser):
_title = ''
_filters = []
_action = Gtk.FileChooserAction.OPEN
_preivew_size = (200, 200)
def __init__(self, accept_cb, cancel_cb=None, transient_for=None,
path=None, file_name=None, select_multiple=False,
preview=True, modal=False):
Gtk.FileChooserDialog.__init__(
self,
title=self._title,
action=self._action,
buttons=[Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT],
transient_for=transient_for)
self.set_current_folder(path or str(Path.home()))
if file_name is not None:
self.set_current_name(file_name)
self.set_select_multiple(select_multiple)
self.set_do_overwrite_confirmation(True)
self.set_modal(modal)
self._add_filters(self._filters)
if preview:
self.set_use_preview_label(False)
self.set_preview_widget(Gtk.Image())
self.connect('selection-changed', self._update_preview)
self.connect('response', self._on_response, accept_cb, cancel_cb)
self.show()
def _on_response(self, *args):
super()._on_response(*args)
self.destroy()
class GtkFileOpenDialog(BaseFileOpenDialog, GtkFileChooserDialog):
pass
class GtkAvatarChooserDialog(BaseAvatarChooserDialog, GtkFileChooserDialog):
pass
def FileChooserDialog(*args, **kwargs):
if app.is_flatpak():
return NativeFileOpenDialog(*args, **kwargs)
else:
return GtkFileOpenDialog(*args, **kwargs)
def AvatarChooserDialog(*args, **kwargs):
if app.is_flatpak():
return NativeAvatarChooserDialog(*args, **kwargs)
else:
return GtkAvatarChooserDialog(*args, **kwargs)

View File

@ -28,6 +28,8 @@ from gi.repository import GLib
from gi.repository import Pango from gi.repository import Pango
import os import os
import time import time
from functools import partial
from pathlib import Path
from enum import IntEnum, unique from enum import IntEnum, unique
from datetime import datetime from datetime import datetime
@ -41,6 +43,7 @@ from gajim.common import helpers
from gajim.common.file_props import FilesProp from gajim.common.file_props import FilesProp
from gajim.common.protocol.bytestream import (is_transfer_active, is_transfer_paused, from gajim.common.protocol.bytestream import (is_transfer_active, is_transfer_paused,
is_transfer_stopped) is_transfer_stopped)
from gajim.filechoosers import FileSaveDialog, FileChooserDialog
from nbxmpp.protocol import NS_JINGLE_FILE_TRANSFER_5 from nbxmpp.protocol import NS_JINGLE_FILE_TRANSFER_5
import logging import logging
log = logging.getLogger('gajim.filetransfer_window') log = logging.getLogger('gajim.filetransfer_window')
@ -322,51 +325,8 @@ class FileTransfersWindow:
account), type_=Gtk.MessageType.ERROR) account), type_=Gtk.MessageType.ERROR)
def show_file_send_request(self, account, contact): def show_file_send_request(self, account, contact):
win = Gtk.ScrolledWindow() send_callback = partial(self.send_file, account, contact)
win.set_shadow_type(Gtk.ShadowType.IN) SendFileDialog(send_callback, self.window)
win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER)
from gajim.message_textview import MessageTextView
desc_entry = MessageTextView()
win.add(desc_entry)
def on_ok(widget):
file_dir = None
files_path_list = dialog.get_filenames()
desc = desc_entry.get_text()
for file_path in files_path_list:
if self.send_file(account, contact, file_path, desc) \
and file_dir is None:
file_dir = os.path.dirname(file_path)
if file_dir:
app.config.set('last_send_dir', file_dir)
dialog.destroy()
dialog = dialogs.FileChooserDialog(_('Choose File to Send…'),
Gtk.FileChooserAction.OPEN, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL),
Gtk.ResponseType.OK,
True, # select multiple true as we can select many files to send
app.config.get('last_send_dir'),
on_response_ok=on_ok,
on_response_cancel=lambda e:dialog.destroy(),
preview=True,
transient_for=app.interface.roster.window
)
btn = Gtk.Button.new_with_mnemonic(_('_Send'))
btn.set_property('can-default', True)
# FIXME: add send icon to this button (JUMP_TO)
dialog.add_action_widget(btn, Gtk.ResponseType.OK)
dialog.set_default_response(Gtk.ResponseType.OK)
desc_hbox = Gtk.HBox(homogeneous=False, spacing=5)
desc_hbox.pack_start(Gtk.Label.new(_('Description: ')), False, False, 0)
desc_hbox.pack_start(win, True, True, 0)
dialog.vbox.pack_start(desc_hbox, False, False, 0)
btn.show()
desc_hbox.show_all()
def send_file(self, account, contact, file_path, file_desc=''): def send_file(self, account, contact, file_path, file_desc=''):
""" """
@ -411,9 +371,9 @@ class FileTransfersWindow:
app.connections[account].send_file_approval(file_props) app.connections[account].send_file_approval(file_props)
def on_file_request_accepted(self, account, contact, file_props): def on_file_request_accepted(self, account, contact, file_props):
def on_ok(widget, account, contact, file_props): def on_ok(account, contact, file_props, file_path):
file_path = dialog2.get_filename()
if os.path.exists(file_path): if os.path.exists(file_path):
app.config.set('last_save_dir', os.path.dirname(file_path))
# check if we have write permissions # check if we have write permissions
if not os.access(file_path, os.W_OK): if not os.access(file_path, os.W_OK):
file_name = GLib.markup_escape_text(os.path.basename( file_name = GLib.markup_escape_text(os.path.basename(
@ -433,13 +393,11 @@ class FileTransfersWindow:
return return
elif response == 100: elif response == 100:
file_props.offset = dl_size file_props.offset = dl_size
dialog2.destroy()
self._start_receive(file_path, account, contact, file_props) self._start_receive(file_path, account, contact, file_props)
dialog = dialogs.FTOverwriteConfirmationDialog( dialog = dialogs.FTOverwriteConfirmationDialog(
_('This file already exists'), _('What do you want to do?'), _('This file already exists'), _('What do you want to do?'),
propose_resume=not dl_finished, on_response=on_response, propose_resume=not dl_finished, on_response=on_response)
transient_for=dialog2)
dialog.set_destroy_with_parent(True) dialog.set_destroy_with_parent(True)
return return
else: else:
@ -452,26 +410,15 @@ class FileTransfersWindow:
dirname, _('You do not have permission to create files ' dirname, _('You do not have permission to create files '
'in this directory.')) 'in this directory.'))
return return
dialog2.destroy()
self._start_receive(file_path, account, contact, file_props) self._start_receive(file_path, account, contact, file_props)
def on_cancel(widget, account, contact, file_props): con = app.connections[account]
dialog2.destroy() accept_cb = partial(on_ok, account, contact, file_props)
app.connections[account].send_file_rejection(file_props) cancel_cb = partial(con.send_file_rejection, file_props)
FileSaveDialog(accept_cb,
dialog2 = dialogs.FileChooserDialog( cancel_cb,
title_text=_('Save File as…'), path=app.config.get('last_save_dir'),
action=Gtk.FileChooserAction.SAVE, file_name=file_props.name)
buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_SAVE, Gtk.ResponseType.OK),
default_response=Gtk.ResponseType.OK,
current_folder=app.config.get('last_save_dir'),
on_response_ok=(on_ok, account, contact, file_props),
on_response_cancel=(on_cancel, account, contact, file_props))
dialog2.set_current_name(file_props.name)
dialog2.connect('delete-event', lambda widget, event:
on_cancel(widget, account, contact, file_props))
def show_file_request(self, account, contact, file_props): def show_file_request(self, account, contact, file_props):
""" """
@ -1048,3 +995,78 @@ class FileTransfersWindow:
def on_file_transfers_window_key_press_event(self, widget, event): def on_file_transfers_window_key_press_event(self, widget, event):
if event.keyval == Gdk.KEY_Escape: # ESCAPE if event.keyval == Gdk.KEY_Escape: # ESCAPE
self.window.hide() self.window.hide()
class SendFileDialog(Gtk.ApplicationWindow):
def __init__(self, send_callback, transient_for):
active_window = app.app.get_active_window()
Gtk.ApplicationWindow.__init__(self)
self.set_name('SendFileDialog')
self.set_application(app.app)
self.set_show_menubar(False)
self.set_resizable(True)
self.set_default_size(400, 250)
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
self.set_transient_for(active_window)
self.set_title(_('Choose a File to Send…'))
self.set_destroy_with_parent(True)
self._send_callback = send_callback
xml = gtkgui_helpers.get_gtk_builder('send_file_dialog.ui')
grid = xml.get_object('send_file_grid')
self._filebox = xml.get_object('listbox')
self._description = xml.get_object('description')
self.add(grid)
self.connect('key-press-event', self._key_press_event)
xml.connect_signals(self)
self.show_all()
def _send(self, button):
for file in self._filebox.get_children():
self._send_callback(str(file.path), self._get_description())
self.destroy()
def _select_files(self, button):
FileChooserDialog(self._set_files,
select_multiple=True,
transient_for=self,
path=app.config.get('last_send_dir'))
def _set_files(self, filenames):
# Clear the ListBox
self._filebox.foreach(self._remove_widget, None)
for file in filenames:
row = FileRow(file)
if row.path.is_dir():
continue
last_dir = row.path.parent
self._filebox.add(row)
self._filebox.show_all()
app.config.set('last_send_dir', str(last_dir))
def _remove_widget(self, widget, data):
self._filebox.remove(widget)
def _get_description(self):
buffer_ = self._description.get_buffer()
start, end = buffer_.get_bounds()
return buffer_.get_text(start, end, False)
def _key_press_event(self, widget, event):
if event.keyval == Gdk.KEY_Escape:
self.destroy()
class FileRow(Gtk.ListBoxRow):
def __init__(self, path):
Gtk.ListBoxRow.__init__(self)
self.path = Path(path)
label = Gtk.Label(self.path.name)
label.set_ellipsize(Pango.EllipsizeMode.END)
label.set_xalign(0)
self.add(label)

View File

@ -51,6 +51,7 @@ from gajim.common import i18n
from gajim.common import app from gajim.common import app
from gajim.common import pep from gajim.common import pep
from gajim.common import configpaths from gajim.common import configpaths
from gajim.filechoosers import AvatarSaveDialog
gtk_icon_theme = Gtk.IconTheme.get_default() gtk_icon_theme = Gtk.IconTheme.get_default()
gtk_icon_theme.append_search_path(configpaths.get('ICONS')) gtk_icon_theme.append_search_path(configpaths.get('ICONS'))
@ -450,6 +451,7 @@ def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
if response < 0: if response < 0:
return return
app.config.set('last_save_dir', os.path.dirname(file_path))
if isinstance(avatar, str): if isinstance(avatar, str):
# We got a SHA # We got a SHA
pixbuf = app.interface.get_avatar(avatar) pixbuf = app.interface.get_avatar(avatar)
@ -459,10 +461,8 @@ def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
extension = os.path.splitext(file_path)[1] extension = os.path.splitext(file_path)[1]
if not extension: if not extension:
# Silently save as Jpeg image # Silently save as Jpeg image
image_format = 'jpeg' image_format = 'png'
file_path += '.jpeg' file_path += '.png'
elif extension == 'jpg':
image_format = 'jpeg'
else: else:
image_format = extension[1:] # remove leading dot image_format = extension[1:] # remove leading dot
@ -473,19 +473,16 @@ def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
log.error('Error saving avatar: %s' % str(e)) log.error('Error saving avatar: %s' % str(e))
if os.path.exists(file_path): if os.path.exists(file_path):
os.remove(file_path) os.remove(file_path)
new_file_path = '.'.join(file_path.split('.')[:-1]) + '.jpeg' new_file_path = '.'.join(file_path.split('.')[:-1]) + '.png'
def on_ok(file_path, pixbuf): def on_ok(file_path, pixbuf):
pixbuf.savev(file_path, 'jpeg', [], []) pixbuf.savev(file_path, 'png', [], [])
dialogs.ConfirmationDialog(_('Extension not supported'), dialogs.ConfirmationDialog(_('Extension not supported'),
_('Image cannot be saved in %(type)s format. Save as ' _('Image cannot be saved in %(type)s format. Save as '
'%(new_filename)s?') % {'type': image_format, '%(new_filename)s?') % {'type': image_format,
'new_filename': new_file_path}, 'new_filename': new_file_path},
on_response_ok = (on_ok, new_file_path, pixbuf)) on_response_ok = (on_ok, new_file_path, pixbuf))
else:
dialog.destroy()
def on_ok(widget): def on_ok(file_path):
file_path = dialog.get_filename()
if os.path.exists(file_path): if os.path.exists(file_path):
# check if we have write permissions # check if we have write permissions
if not os.access(file_path, os.W_OK): if not os.access(file_path, os.W_OK):
@ -496,8 +493,7 @@ def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
return return
dialog2 = dialogs.FTOverwriteConfirmationDialog( dialog2 = dialogs.FTOverwriteConfirmationDialog(
_('This file already exists'), _('What do you want to do?'), _('This file already exists'), _('What do you want to do?'),
propose_resume=False, on_response=(on_continue, file_path), propose_resume=False, on_response=(on_continue, file_path))
transient_for=dialog)
dialog2.set_destroy_with_parent(True) dialog2.set_destroy_with_parent(True)
else: else:
dirname = os.path.dirname(file_path) dirname = os.path.dirname(file_path)
@ -509,19 +505,11 @@ def on_avatar_save_as_menuitem_activate(widget, avatar, default_name=''):
on_continue(0, file_path) on_continue(0, file_path)
def on_cancel(widget): transient = app.app.get_active_window()
dialog.destroy() AvatarSaveDialog(on_ok,
path=app.config.get('last_save_dir'),
dialog = dialogs.FileChooserDialog(title_text=_('Save Image as…'), file_name='%s.png' % default_name,
action=Gtk.FileChooserAction.SAVE, buttons=(Gtk.STOCK_CANCEL, transient_for=transient)
Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK),
default_response=Gtk.ResponseType.OK,
current_folder=app.config.get('last_save_dir'), on_response_ok=on_ok,
on_response_cancel=on_cancel)
dialog.set_current_name(default_name + '.jpeg')
dialog.connect('delete-event', lambda widget, event:
on_cancel(widget))
def create_combobox(value_list, selected_value = None): def create_combobox(value_list, selected_value = None):
""" """

View File

@ -39,6 +39,7 @@ import sys
import re import re
import time import time
import hashlib import hashlib
from functools import partial
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
@ -66,7 +67,7 @@ from gajim import notify
from gajim import message_control from gajim import message_control
from gajim.dialog_messages import get_dialog from gajim.dialog_messages import get_dialog
from gajim.dialogs import ProgressWindow from gajim.dialogs import ProgressWindow
from gajim.dialogs import FileChooserDialog from gajim.filechoosers import FileChooserDialog
from gajim.chat_control_base import ChatControlBase from gajim.chat_control_base import ChatControlBase
from gajim.chat_control import ChatControl from gajim.chat_control import ChatControl
@ -1147,22 +1148,13 @@ class Interface:
ProgressWindow(file) ProgressWindow(file)
def send_httpupload(self, chat_control): def send_httpupload(self, chat_control):
FileChooserDialog( accept_cb = partial(self.on_file_dialog_ok, chat_control)
on_response_ok=lambda widget: self.on_file_dialog_ok(widget, FileChooserDialog(accept_cb,
chat_control), select_multiple=True,
title_text=_('Choose file to send'), transient_for=chat_control.parent_win.window)
action=Gtk.FileChooserAction.OPEN,
buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK),
select_multiple=True,
default_response=Gtk.ResponseType.OK,
preview=True,
transient_for=chat_control.parent_win.window)
@staticmethod @staticmethod
def on_file_dialog_ok(widget, chat_control): def on_file_dialog_ok(chat_control, paths):
paths = widget.get_filenames()
widget.destroy()
con = app.connections[chat_control.account] con = app.connections[chat_control.account]
groupchat = chat_control.type_id == message_control.TYPE_GC groupchat = chat_control.type_id == message_control.TYPE_GC
for path in paths: for path in paths:

View File

@ -83,10 +83,11 @@ if is_standalone():
configpaths.init() configpaths.init()
from gajim.common import app from gajim.common import app
from gajim import gtkgui_helpers
from gajim.common.const import JIDConstant, KindConstant from gajim.common.const import JIDConstant, KindConstant
from gajim.common import helpers from gajim.common import helpers
from gajim import dialogs from gajim import dialogs
from gajim.filechoosers import FileSaveDialog
from gajim import gtkgui_helpers
@unique @unique
@ -465,24 +466,14 @@ class HistoryManager:
return True return True
def on_export_menuitem_activate(self, widget): def on_export_menuitem_activate(self, widget):
xml = gtkgui_helpers.get_gtk_builder('history_manager.ui', FileSaveDialog(self._on_export,
'filechooserdialog') transient_for=self.window,
xml.connect_signals(self) modal=True)
dlg = xml.get_object('filechooserdialog') def _on_export(self, filename):
dlg.set_title(_('Exporting History Logs…')) liststore, list_of_paths = self.jids_listview.get_selection()\
dlg.set_current_folder(configpaths.get('HOME')) .get_selected_rows()
dlg.props.do_overwrite_confirmation = True self._export_jids_logs_to_file(liststore, list_of_paths, filename)
response = dlg.run()
if response == Gtk.ResponseType.OK: # user want us to export ;)
liststore, list_of_paths = self.jids_listview.get_selection()\
.get_selected_rows()
path_to_file = dlg.get_filename()
self._export_jids_logs_to_file(liststore, list_of_paths,
path_to_file)
dlg.destroy()
def on_delete_menuitem_activate(self, widget, listview): def on_delete_menuitem_activate(self, widget, listview):
widget_name = Gtk.Buildable.get_name(listview) widget_name = Gtk.Buildable.get_name(listview)

View File

@ -35,7 +35,8 @@ import os
from enum import IntEnum, unique from enum import IntEnum, unique
from gajim import gtkgui_helpers from gajim import gtkgui_helpers
from gajim.dialogs import WarningDialog, YesNoDialog, ArchiveChooserDialog from gajim.dialogs import WarningDialog, YesNoDialog
from gajim.filechoosers import ArchiveChooserDialog
from gajim.htmltextview import HtmlTextView from gajim.htmltextview import HtmlTextView
from gajim.common import app from gajim.common import app
from gajim.common import configpaths from gajim.common import configpaths
@ -309,8 +310,7 @@ class PluginsWindow(object):
sel = self.installed_plugins_treeview.get_selection() sel = self.installed_plugins_treeview.get_selection()
sel.select_iter(iter_) sel.select_iter(iter_)
self.dialog = ArchiveChooserDialog( ArchiveChooserDialog(_try_install, transient_for=self.window)
on_response_ok=_try_install, transient_for=self.window)
class GajimPluginConfigDialog(Gtk.Dialog): class GajimPluginConfigDialog(Gtk.Dialog):

View File

@ -33,6 +33,7 @@ import hashlib
from gajim import gtkgui_helpers from gajim import gtkgui_helpers
from gajim import dialogs from gajim import dialogs
from gajim.filechoosers import AvatarChooserDialog
from gajim.common.const import AvatarSize from gajim.common.const import AvatarSize
from gajim.common import app from gajim.common import app
@ -107,7 +108,7 @@ class ProfileWindow:
if event.keyval == Gdk.KEY_Escape: if event.keyval == Gdk.KEY_Escape:
self.window.destroy() self.window.destroy()
def on_clear_button_clicked(self, widget): def _clear_photo(self, widget):
# empty the image # empty the image
button = self.xml.get_object('PHOTO_button') button = self.xml.get_object('PHOTO_button')
image = button.get_image() image = button.get_image()
@ -115,12 +116,14 @@ class ProfileWindow:
button.hide() button.hide()
text_button = self.xml.get_object('NOPHOTO_button') text_button = self.xml.get_object('NOPHOTO_button')
text_button.show() text_button.show()
remove_avatar = self.xml.get_object('remove_avatar')
remove_avatar.hide()
self.avatar_encoded = None self.avatar_encoded = None
self.avatar_sha = None self.avatar_sha = None
self.avatar_mime_type = None self.avatar_mime_type = None
def on_set_avatar_button_clicked(self, widget): def on_set_avatar_button_clicked(self, widget):
def on_ok(widget, path_to_file): def on_ok(path_to_file):
with open(path_to_file, 'rb') as file: with open(path_to_file, 'rb') as file:
data = file.read() data = file.read()
sha = app.interface.save_avatar(data, publish=True) sha = app.interface.save_avatar(data, publish=True)
@ -129,9 +132,6 @@ class ProfileWindow:
_('Could not load image'), transient_for=self.window) _('Could not load image'), transient_for=self.window)
return return
self.dialog.destroy()
self.dialog = None
scale = self.window.get_scale_factor() scale = self.window.get_scale_factor()
surface = app.interface.get_avatar(sha, AvatarSize.VCARD, scale) surface = app.interface.get_avatar(sha, AvatarSize.VCARD, scale)
@ -142,26 +142,15 @@ class ProfileWindow:
text_button = self.xml.get_object('NOPHOTO_button') text_button = self.xml.get_object('NOPHOTO_button')
text_button.hide() text_button.hide()
remove_avatar = self.xml.get_object('remove_avatar')
remove_avatar.show()
self.avatar_sha = sha self.avatar_sha = sha
publish = app.interface.get_avatar(sha, publish=True) publish = app.interface.get_avatar(sha, publish=True)
self.avatar_encoded = base64.b64encode(publish).decode('utf-8') self.avatar_encoded = base64.b64encode(publish).decode('utf-8')
self.avatar_mime_type = 'image/jpeg' self.avatar_mime_type = 'image/png'
def on_clear(widget): AvatarChooserDialog(on_ok, transient_for=self.window)
self.dialog.destroy()
self.dialog = None
self.on_clear_button_clicked(widget)
def on_cancel(widget):
self.dialog.destroy()
self.dialog = None
if self.dialog:
self.dialog.present()
else:
self.dialog = dialogs.AvatarChooserDialog(
on_response_ok=on_ok, on_response_cancel=on_cancel,
on_response_clear=on_clear)
def on_PHOTO_button_press_event(self, widget, event): def on_PHOTO_button_press_event(self, widget, event):
""" """
@ -218,11 +207,13 @@ class ProfileWindow:
button = self.xml.get_object('PHOTO_button') button = self.xml.get_object('PHOTO_button')
image = button.get_image() image = button.get_image()
text_button = self.xml.get_object('NOPHOTO_button') text_button = self.xml.get_object('NOPHOTO_button')
remove_avatar = self.xml.get_object('remove_avatar')
if not 'PHOTO' in vcard_: if not 'PHOTO' in vcard_:
# set default image # set default image
image.set_from_pixbuf(None) image.set_from_pixbuf(None)
button.hide() button.hide()
text_button.show() text_button.show()
remove_avatar.hide()
for i in vcard_.keys(): for i in vcard_.keys():
if i == 'PHOTO': if i == 'PHOTO':
photo_encoded = vcard_[i]['BINVAL'] photo_encoded = vcard_[i]['BINVAL']
@ -241,6 +232,7 @@ class ProfileWindow:
GdkPixbuf.InterpType.BILINEAR) GdkPixbuf.InterpType.BILINEAR)
image.set_from_pixbuf(pixbuf) image.set_from_pixbuf(pixbuf)
button.show() button.show()
remove_avatar.show()
text_button.hide() text_button.hide()
continue continue
if i == 'ADR' or i == 'TEL' or i == 'EMAIL': if i == 'ADR' or i == 'TEL' or i == 'EMAIL':