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,
'GSPELL': False,
'IDLE': False,
'RUN_AS_FLATPAK': False,
}
@ -167,6 +168,9 @@ def is_installed(dependency):
return _dependencies['AVAHI'] or _dependencies['PYBONJOUR']
return _dependencies[dependency]
def is_flatpak():
return _dependencies['RUN_AS_FLATPAK']
def disable_dependency(dependency):
_dependencies[dependency] = False

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.21.0 -->
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkMenu" id="context_menu">
@ -22,70 +22,6 @@
</object>
</child>
</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">
<property name="visible">True</property>
<property name="can_focus">False</property>
@ -98,6 +34,9 @@
<property name="default_width">650</property>
<property name="default_height">500</property>
<signal name="delete-event" handler="on_history_manager_window_delete_event" swapped="no"/>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="vbox">
<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>
</object>
</child>
<child>
<placeholder/>
</child>
</object>
</interface>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkWindow" id="profile_window">
@ -8,6 +8,9 @@
<property name="type_hint">dialog</property>
<signal name="destroy" handler="on_profile_window_destroy" swapped="no"/>
<signal name="key-press-event" handler="on_profile_window_key_press_event" swapped="no"/>
<child>
<placeholder/>
</child>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
@ -30,10 +33,10 @@
<object class="GtkLabel" id="label24">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -54,10 +57,10 @@
<object class="GtkLabel" id="label20">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -89,10 +92,10 @@
<object class="GtkLabel" id="label18">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -113,10 +116,10 @@
<object class="GtkLabel" id="label17">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -137,10 +140,10 @@
<object class="GtkLabel" id="label16">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -151,10 +154,10 @@
<object class="GtkLabel" id="label15">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -185,10 +188,10 @@
<object class="GtkLabel" id="label14">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -217,10 +220,10 @@
<object class="GtkLabel" id="label19">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object>
</child>
</object>
@ -245,10 +248,10 @@
<object class="GtkLabel" id="label31">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -269,10 +272,10 @@
<object class="GtkLabel" id="label29">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -293,10 +296,10 @@
<object class="GtkLabel" id="label28">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -317,10 +320,10 @@
<object class="GtkLabel" id="label26">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -341,10 +344,10 @@
<object class="GtkLabel" id="label27">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -365,10 +368,10 @@
<object class="GtkLabel" id="label25">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -391,10 +394,10 @@
<object class="GtkLabel" id="label30">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
</object>
</child>
</object>
@ -408,10 +411,10 @@
<object class="GtkLabel" id="label22">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -433,9 +436,9 @@
<object class="GtkLabel" id="label57">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -457,10 +460,10 @@
<object class="GtkLabel" id="label23">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -492,10 +495,10 @@
<object class="GtkLabel" id="label58">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -506,12 +509,11 @@
<object class="GtkBox" id="hbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkButton" id="PHOTO_button">
<property name="can_focus">True</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"/>
<child>
<object class="GtkEventBox" id="PHOTO_eventbox3">
@ -522,7 +524,6 @@
<object class="GtkImage" id="PHOTO_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="yalign">0</property>
<property name="stock">gtk-missing-image</property>
</object>
</child>
@ -543,8 +544,6 @@
<property name="receives_default">False</property>
<property name="no_show_all">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"/>
</object>
<packing>
@ -553,10 +552,31 @@
<property name="position">1</property>
</packing>
</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>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">6</property>
<property name="width">3</property>
</packing>
</child>
<child>
@ -569,10 +589,10 @@
<object class="GtkLabel" id="label13">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
</child>
</object>
@ -581,21 +601,15 @@
<property name="top_attach">5</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Personal Info</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">Personal Info</property>
</object>
<packing>
<property name="tab_fill">False</property>
@ -612,10 +626,10 @@
<object class="GtkLabel" id="label44">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -636,10 +650,10 @@
<object class="GtkLabel" id="label43">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -660,10 +674,10 @@
<object class="GtkLabel" id="label42">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -684,10 +698,10 @@
<object class="GtkLabel" id="label41">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -719,10 +733,10 @@
<object class="GtkLabel" id="label39">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -743,10 +757,10 @@
<object class="GtkLabel" id="label38">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -767,10 +781,10 @@
<object class="GtkLabel" id="label37">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -791,10 +805,10 @@
<object class="GtkLabel" id="label35">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -815,10 +829,10 @@
<object class="GtkLabel" id="label36">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -839,10 +853,10 @@
<object class="GtkLabel" id="label34">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">2</property>
@ -865,10 +879,10 @@
<object class="GtkLabel" id="label40">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
</child>
</object>
@ -882,10 +896,10 @@
<object class="GtkLabel" id="label32">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -907,10 +921,10 @@
<object class="GtkLabel" id="label33">
<property name="visible">True</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="use_markup">True</property>
<property name="xalign">1</property>
<property name="yalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -942,9 +956,9 @@
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Work</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="label" translatable="yes">Work</property>
</object>
<packing>
<property name="position">1</property>
@ -974,9 +988,9 @@
<object class="GtkLabel" id="label6">
<property name="visible">True</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="yalign">0</property>
<property name="label" translatable="yes" comments="&quot;About&quot; is the text of a tab of vcard window">About</property>
</object>
<packing>
<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*/
.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()
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:
def __init__(self, lang):
ErrorDialog(
@ -4773,139 +4705,6 @@ class ProgressDialog:
def on_progress_dialog_delete_event(self, widget, event):
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:
# Keep a reference on windows so garbage collector don't restroy them
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
import os
import time
from functools import partial
from pathlib import Path
from enum import IntEnum, unique
from datetime import datetime
@ -41,6 +43,7 @@ from gajim.common import helpers
from gajim.common.file_props import FilesProp
from gajim.common.protocol.bytestream import (is_transfer_active, is_transfer_paused,
is_transfer_stopped)
from gajim.filechoosers import FileSaveDialog, FileChooserDialog
from nbxmpp.protocol import NS_JINGLE_FILE_TRANSFER_5
import logging
log = logging.getLogger('gajim.filetransfer_window')
@ -322,51 +325,8 @@ class FileTransfersWindow:
account), type_=Gtk.MessageType.ERROR)
def show_file_send_request(self, account, contact):
win = Gtk.ScrolledWindow()
win.set_shadow_type(Gtk.ShadowType.IN)
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()
send_callback = partial(self.send_file, account, contact)
SendFileDialog(send_callback, self.window)
def send_file(self, account, contact, file_path, file_desc=''):
"""
@ -411,9 +371,9 @@ class FileTransfersWindow:
app.connections[account].send_file_approval(file_props)
def on_file_request_accepted(self, account, contact, file_props):
def on_ok(widget, account, contact, file_props):
file_path = dialog2.get_filename()
def on_ok(account, contact, file_props, 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
if not os.access(file_path, os.W_OK):
file_name = GLib.markup_escape_text(os.path.basename(
@ -433,13 +393,11 @@ class FileTransfersWindow:
return
elif response == 100:
file_props.offset = dl_size
dialog2.destroy()
self._start_receive(file_path, account, contact, file_props)
dialog = dialogs.FTOverwriteConfirmationDialog(
_('This file already exists'), _('What do you want to do?'),
propose_resume=not dl_finished, on_response=on_response,
transient_for=dialog2)
propose_resume=not dl_finished, on_response=on_response)
dialog.set_destroy_with_parent(True)
return
else:
@ -452,26 +410,15 @@ class FileTransfersWindow:
dirname, _('You do not have permission to create files '
'in this directory.'))
return
dialog2.destroy()
self._start_receive(file_path, account, contact, file_props)
def on_cancel(widget, account, contact, file_props):
dialog2.destroy()
app.connections[account].send_file_rejection(file_props)
dialog2 = dialogs.FileChooserDialog(
title_text=_('Save File as…'),
action=Gtk.FileChooserAction.SAVE,
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))
con = app.connections[account]
accept_cb = partial(on_ok, account, contact, file_props)
cancel_cb = partial(con.send_file_rejection, file_props)
FileSaveDialog(accept_cb,
cancel_cb,
path=app.config.get('last_save_dir'),
file_name=file_props.name)
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):
if event.keyval == Gdk.KEY_Escape: # ESCAPE
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 pep
from gajim.common import configpaths
from gajim.filechoosers import AvatarSaveDialog
gtk_icon_theme = Gtk.IconTheme.get_default()
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:
return
app.config.set('last_save_dir', os.path.dirname(file_path))
if isinstance(avatar, str):
# We got a SHA
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]
if not extension:
# Silently save as Jpeg image
image_format = 'jpeg'
file_path += '.jpeg'
elif extension == 'jpg':
image_format = 'jpeg'
image_format = 'png'
file_path += '.png'
else:
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))
if os.path.exists(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):
pixbuf.savev(file_path, 'jpeg', [], [])
pixbuf.savev(file_path, 'png', [], [])
dialogs.ConfirmationDialog(_('Extension not supported'),
_('Image cannot be saved in %(type)s format. Save as '
'%(new_filename)s?') % {'type': image_format,
'new_filename': new_file_path},
on_response_ok = (on_ok, new_file_path, pixbuf))
else:
dialog.destroy()
def on_ok(widget):
file_path = dialog.get_filename()
def on_ok(file_path):
if os.path.exists(file_path):
# check if we have write permissions
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
dialog2 = dialogs.FTOverwriteConfirmationDialog(
_('This file already exists'), _('What do you want to do?'),
propose_resume=False, on_response=(on_continue, file_path),
transient_for=dialog)
propose_resume=False, on_response=(on_continue, file_path))
dialog2.set_destroy_with_parent(True)
else:
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)
def on_cancel(widget):
dialog.destroy()
dialog = dialogs.FileChooserDialog(title_text=_('Save Image as…'),
action=Gtk.FileChooserAction.SAVE, 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,
on_response_cancel=on_cancel)
dialog.set_current_name(default_name + '.jpeg')
dialog.connect('delete-event', lambda widget, event:
on_cancel(widget))
transient = app.app.get_active_window()
AvatarSaveDialog(on_ok,
path=app.config.get('last_save_dir'),
file_name='%s.png' % default_name,
transient_for=transient)
def create_combobox(value_list, selected_value = None):
"""

View File

@ -39,6 +39,7 @@ import sys
import re
import time
import hashlib
from functools import partial
from gi.repository import Gtk
from gi.repository import GdkPixbuf
@ -66,7 +67,7 @@ from gajim import notify
from gajim import message_control
from gajim.dialog_messages import get_dialog
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 import ChatControl
@ -1147,22 +1148,13 @@ class Interface:
ProgressWindow(file)
def send_httpupload(self, chat_control):
FileChooserDialog(
on_response_ok=lambda widget: self.on_file_dialog_ok(widget,
chat_control),
title_text=_('Choose file to send'),
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)
accept_cb = partial(self.on_file_dialog_ok, chat_control)
FileChooserDialog(accept_cb,
select_multiple=True,
transient_for=chat_control.parent_win.window)
@staticmethod
def on_file_dialog_ok(widget, chat_control):
paths = widget.get_filenames()
widget.destroy()
def on_file_dialog_ok(chat_control, paths):
con = app.connections[chat_control.account]
groupchat = chat_control.type_id == message_control.TYPE_GC
for path in paths:

View File

@ -83,10 +83,11 @@ if is_standalone():
configpaths.init()
from gajim.common import app
from gajim import gtkgui_helpers
from gajim.common.const import JIDConstant, KindConstant
from gajim.common import helpers
from gajim import dialogs
from gajim.filechoosers import FileSaveDialog
from gajim import gtkgui_helpers
@unique
@ -465,24 +466,14 @@ class HistoryManager:
return True
def on_export_menuitem_activate(self, widget):
xml = gtkgui_helpers.get_gtk_builder('history_manager.ui',
'filechooserdialog')
xml.connect_signals(self)
FileSaveDialog(self._on_export,
transient_for=self.window,
modal=True)
dlg = xml.get_object('filechooserdialog')
dlg.set_title(_('Exporting History Logs…'))
dlg.set_current_folder(configpaths.get('HOME'))
dlg.props.do_overwrite_confirmation = True
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_export(self, filename):
liststore, list_of_paths = self.jids_listview.get_selection()\
.get_selected_rows()
self._export_jids_logs_to_file(liststore, list_of_paths, filename)
def on_delete_menuitem_activate(self, widget, listview):
widget_name = Gtk.Buildable.get_name(listview)

View File

@ -35,7 +35,8 @@ import os
from enum import IntEnum, unique
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.common import app
from gajim.common import configpaths
@ -309,8 +310,7 @@ class PluginsWindow(object):
sel = self.installed_plugins_treeview.get_selection()
sel.select_iter(iter_)
self.dialog = ArchiveChooserDialog(
on_response_ok=_try_install, transient_for=self.window)
ArchiveChooserDialog(_try_install, transient_for=self.window)
class GajimPluginConfigDialog(Gtk.Dialog):

View File

@ -33,6 +33,7 @@ import hashlib
from gajim import gtkgui_helpers
from gajim import dialogs
from gajim.filechoosers import AvatarChooserDialog
from gajim.common.const import AvatarSize
from gajim.common import app
@ -107,7 +108,7 @@ class ProfileWindow:
if event.keyval == Gdk.KEY_Escape:
self.window.destroy()
def on_clear_button_clicked(self, widget):
def _clear_photo(self, widget):
# empty the image
button = self.xml.get_object('PHOTO_button')
image = button.get_image()
@ -115,12 +116,14 @@ class ProfileWindow:
button.hide()
text_button = self.xml.get_object('NOPHOTO_button')
text_button.show()
remove_avatar = self.xml.get_object('remove_avatar')
remove_avatar.hide()
self.avatar_encoded = None
self.avatar_sha = None
self.avatar_mime_type = None
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:
data = file.read()
sha = app.interface.save_avatar(data, publish=True)
@ -129,9 +132,6 @@ class ProfileWindow:
_('Could not load image'), transient_for=self.window)
return
self.dialog.destroy()
self.dialog = None
scale = self.window.get_scale_factor()
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.hide()
remove_avatar = self.xml.get_object('remove_avatar')
remove_avatar.show()
self.avatar_sha = sha
publish = app.interface.get_avatar(sha, publish=True)
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):
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)
AvatarChooserDialog(on_ok, transient_for=self.window)
def on_PHOTO_button_press_event(self, widget, event):
"""
@ -218,11 +207,13 @@ class ProfileWindow:
button = self.xml.get_object('PHOTO_button')
image = button.get_image()
text_button = self.xml.get_object('NOPHOTO_button')
remove_avatar = self.xml.get_object('remove_avatar')
if not 'PHOTO' in vcard_:
# set default image
image.set_from_pixbuf(None)
button.hide()
text_button.show()
remove_avatar.hide()
for i in vcard_.keys():
if i == 'PHOTO':
photo_encoded = vcard_[i]['BINVAL']
@ -241,6 +232,7 @@ class ProfileWindow:
GdkPixbuf.InterpType.BILINEAR)
image.set_from_pixbuf(pixbuf)
button.show()
remove_avatar.show()
text_button.hide()
continue
if i == 'ADR' or i == 'TEL' or i == 'EMAIL':