Merge lp:~julien-spautz/cable/clean-up into lp:cable

Proposed by Julien Spautz
Status: Merged
Merged at revision: 64
Proposed branch: lp:~julien-spautz/cable/clean-up
Merge into: lp:cable
Diff against target: 4226 lines (+2750/-1267) (has conflicts)
25 files modified
CMakeLists.txt (+26/-4)
data/org.pantheon.cable.gschema.xml (+11/-19)
po/cable.pot (+57/-75)
src/Cable.vala (+85/-248)
src/Config.vala.cmake (+7/-7)
src/Dialogs/JoinChannel.vala (+97/-0)
src/Dialogs/ManageIdentity.vala (+117/-0)
src/Dialogs/ManageNetwork.vala (+116/-0)
src/Dialogs/Preferences.vala (+214/-0)
src/Global.vala (+0/-18)
src/Services/Client.vala (+278/-0)
src/Services/Identity.vala (+123/-0)
src/Services/Network.vala (+103/-0)
src/Services/Settings.vala (+146/-0)
src/Settings.vala (+0/-23)
src/Utils.vala (+69/-0)
src/Widgets/Channel.vala (+109/-55)
src/Widgets/Room.vala (+276/-63)
src/Widgets/Server.vala (+380/-229)
src/Widgets/ServerList.vala (+103/-76)
src/Widgets/SettingsDialog.vala (+0/-65)
src/Widgets/StatusBar.vala (+49/-0)
src/Widgets/Welcome.vala (+112/-0)
src/Window.vala (+272/-0)
src/doodleIRC.vala (+0/-385)
Text conflict in src/Widgets/Room.vala
To merge this branch: bzr merge lp:~julien-spautz/cable/clean-up
Reviewer Review Type Date Requested Status
Auroral Xylon (community) Needs Fixing
Julián Unrrein (community) Needs Fixing
Eduard Gotwig (community) Needs Fixing
Review via email: mp+168703@code.launchpad.net

Description of the change

Just testing for conflicts, please don't merge.

To post a comment you must log in.
Revision history for this message
Julien Spautz (julien-spautz) wrote :

This is now almost ready for merging. There are still a few regressiong left because of the switch to maki as backend daemon, which I'll try to fix asap so we can continue enhancing cable and implementing new features.

Revision history for this message
Julián Unrrein (junrrein) wrote :

If you'd like more people to test this when this is ready, I offer my help. Just shoot me an email.

Revision history for this message
Julien Spautz (julien-spautz) wrote :

I'll start implementing this: https://blueprints.launchpad.net/cable/+spec/identities-and-networks

After this is done, we can start reviewing.

Revision history for this message
Julien Spautz (julien-spautz) wrote :

Ok, I guess the branch is now kind of working. I need some feedback in case there are any important bugs, else this branch is ready for merging into trunk.

lp:~julien-spautz/cable/clean-up updated
56. By Julien Spautz

replaced toolber with status bar, entry not yet resizing

57. By Julien Spautz

added new statusbar file

58. By Julien Spautz

small fixes

59. By Julien Spautz

fixed duplicates in user list

Revision history for this message
Auroral Xylon (avlabs314) wrote :

This branch is looking pretty good now...Small bugs can be fixed later on I guess...Merge time?

lp:~julien-spautz/cable/clean-up updated
60. By Julien Spautz

entry now expands and is centered correctly, buttons on the right are misaligned

61. By Julien Spautz

added file

62. By Julien Spautz

make pot

Revision history for this message
Eduard Gotwig (gotwig) wrote :

Nickname entry description should tell the user that hes not able to use spaces or special charachters;

The join channel dialog shouldnt autoselect the # charachter as a selection;

when the user enters an alphabetical charachter as the first charachter for a channel, cable IRC Suite should automaticly prepend a "#" charachter before this.

review: Needs Fixing
Revision history for this message
Julián Unrrein (junrrein) wrote :

I can't compile your branch as of rev62:

/clean-up/src/Widgets/Room.vala:91.27-91.61: error: Assignment: Cannot convert from `Gtk.Widget' to `Gtk.Container?'
            Gtk.Container content = topic.get_content_area ();
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

PS: Consider adding me to the reviewer list of this merge proposal, so I get automatically notified of new comments.

review: Needs Fixing
Revision history for this message
Julián Unrrein (junrrein) wrote :

Do you enforce a certain version of valac? I am using 0.16.

Revision history for this message
Julián Unrrein (junrrein) wrote :

@gotwig

Shouldn't we just focus on checking that this branch solves all the bugs and implements all the blueprints linked? Because everything you mentioned seems to be nonrelated details.

Revision history for this message
Eduard Gotwig (gotwig) wrote :

@Junrrein

This branch offers a new look, and a new implementation of a design specification. With this, it should not make the UX of Cable IRC Suite worse.

Revision history for this message
Auroral Xylon (avlabs314) wrote :

I have always had @junrreins problem; I fixed this in trunk but I presums that Julien Spautz's branch is based of an older revsion. To fix the compile error, you need to put '(Gtk.Container)' before topic so it looks like this:

Gtk.Container content = (Gtk.Container)topic.get_content_area ();

However, there are also some disagreementtwith the design. Until we can resolve them,' the branch should not be merged.

lp:~julien-spautz/cable/clean-up updated
63. By Julien Spautz

fixed a few things

Revision history for this message
Julián Unrrein (junrrein) wrote :

@gotwig

In trunk the identity dialog doesn't check if the input contains spaces or special characters, so the situation is the same here.

As for the other details, they are very minor nuisances which can be taken care of at another moment.

Revision history for this message
Julián Unrrein (junrrein) wrote :

@xylon

I am aware I can type-cast the compile error away, but that is not the problem.

It is apparent that Julien didn't even try to compile his branch before pushing his latest revisions. I am reluctant to test code that wasn't tested by the developer.

Revision history for this message
Julien Spautz (julien-spautz) wrote :

@junrrein

I did try the code and it compiled fine for me, the compiler error xylon mentionned existed in trunk but it didn't affect me there either. It's now been fixed, so I hope it now works for you too.

This is the merge request that fixed the bug in trunk, and as you can see, the bug never affected me. https://code.launchpad.net/~avlabs314/cable/cable/+merge/168510

Revision history for this message
Julián Unrrein (junrrein) wrote :

@Julien

I talked to xylon about this a minute ago, and we concluded this might be pinned down to different versions of valac being used. I'm sorry for the "accusation". If I standed out as rude, it wasn't my intention.

I can now compile rev63 just fine, thanks. I'll be testing this.

Revision history for this message
Julián Unrrein (junrrein) wrote :

I noticed a couple of issues:

1 - New identities can't join channels in the same session they are created. After closing Cable and restarting it, the new identity works just as expected. I can reproduce this always.

2 - The first time Cable is opened (in a new desktop session) console output reveals it connects every past identity to each correspondent server - even identities that were erased from Cable (and from Dconf). This is related with the previous issue because after connecting sucesfully with an identity, erasing it will not trigger the first bug again.

review: Needs Fixing
Revision history for this message
Julien Spautz (julien-spautz) wrote :

Thanks for testing!

1) I don't (yet) know how to fix this, as there is no documentation for maki, the backend daemon. I'm currently performing some hackish tests which are relatively reliable, but I'm still searching for a way to test if maki is connected to a specific server or not.

2) Shouldn't be too hard to fix, but again, maki really lacks documentation…

( And don't worry, I'm not offended ;) )

Revision history for this message
Julián Unrrein (junrrein) wrote :

About item 2: This makes impossible to change the current nick to one that was used previously, even if you are not using it right now.

Curiously, changing the current nick to another one which was never used doesn't trigger item 1.
The nick is changed correctly when seen from the outside.
From the inside, the nick shown in the window title only changes when changing to another channel and then back.
The nick shown in the operators/users lists isn't changed in any of the current opened channels. It will stay the same until you leave those channels and join again. New channels will join the nick correctly.

Revision history for this message
Julián Unrrein (junrrein) wrote :

The last line should read "New channels will show the nick correctly".

Revision history for this message
Julián Unrrein (junrrein) wrote :

About the linked bugs:

(3) Cable doesn't let me join a channel twice. Console output says "Server.vala:336: Channel '#elementary-apps' already joined. Works as intended. UI feedback would be nice, but it's not necessary right now.

(4) The operators/users lists are expanded by default.

(5) I don't know how to test running with invalid Gschemas. Do I just modify any key with random content?

(6) Toolbar buttons have tooltips now.

(7) I can remove identities that I am currently using from the settings dialog - not good.
Identities created using this dialog exhibit the first bug I outlined earlier (bug (1)).
Maybe identities should be tied to specific networks. See my comment in the blueprint (http://goo.gl/r6nr9).

This is looking pretty well!

Revision history for this message
Auroral Xylon (avlabs314) wrote :

I am having a problem - cable does not connect to a channel, except it randomly does on a few occasions. Basically, the interface loads - the sidebars and the 'loading topic' text appears but it doesn't actually connect.

Unfortunately, junrrein also had this problem.

review: Needs Fixing
lp:~julien-spautz/cable/clean-up updated
64. By Julien Spautz

joining channels should now be more reliable, some internal changes to how settings are handeled

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-05-29 00:24:15 +0000
3+++ CMakeLists.txt 2013-06-28 19:09:26 +0000
4@@ -41,22 +41,44 @@
5
6 include(ValaPrecompile)
7 vala_precompile(VALA_C
8- src/doodleIRC.vala
9 src/Cable.vala
10- src/Global.vala
11- src/Settings.vala
12+ src/Window.vala
13+ src/Utils.vala
14+
15+ src/Services/Client.vala
16+ src/Services/Settings.vala
17+ src/Services/Identity.vala
18+ src/Services/Network.vala
19+
20 src/Widgets/Room.vala
21 src/Widgets/Server.vala
22 src/Widgets/Channel.vala
23 src/Widgets/ServerList.vala
24- src/Widgets/SettingsDialog.vala
25+ src/Widgets/StatusBar.vala
26+ src/Widgets/Welcome.vala
27+
28+ src/Dialogs/JoinChannel.vala
29+ src/Dialogs/Preferences.vala
30+ src/Dialogs/ManageIdentity.vala
31+ src/Dialogs/ManageNetwork.vala
32+
33 ${CMAKE_BINARY_DIR}/src/Config.vala
34 PACKAGES
35+ gtk+-3.0
36 granite
37+ #WebKit-3.0
38 OPTIONS
39 --target-glib=2.32
40 --vapidir=${CMAKE_CURRENT_SOURCE_DIR}/vapi/
41 )
42+
43+pkg_check_modules(DEPS REQUIRED
44+ glib-2.0>=${TARGET_GLIB}.0
45+ gio-2.0>=2.28.0
46+ gtk+-3.0>=3.4.0
47+ gee-0.8>=0.8.0
48+ #webkitgtk-3.0>=1.10.0
49+)
50
51 add_subdirectory (po)
52
53
54=== modified file 'data/org.pantheon.cable.gschema.xml'
55--- data/org.pantheon.cable.gschema.xml 2013-05-26 15:42:50 +0000
56+++ data/org.pantheon.cable.gschema.xml 2013-06-28 19:09:26 +0000
57@@ -1,27 +1,19 @@
58 <schemalist>
59 <schema path="/org/pantheon/cable/" id="org.pantheon.cable" gettext-domain="cable">
60- <key name="servers" type="as">
61+ <key name="identities" type="as">
62 <default>[]</default>
63- <summary>All the todo items</summary>
64- <description></description>
65- </key>
66- <key name="nick" type="s">
67- <default>""</default>
68- <summary>Your nick</summary>
69- </key>
70- <key name="real-name" type="s">
71- <default>""</default>
72- <summary>Your real name</summary>
73- </key>
74- <key name="login-name" type="as">
75- <default>[]</default>
76- <summary>Your login name for different IRC server</summary>
77- <description>Specify your user accounts in the form "server:loginname"</description>
78+ <summary>Your identities that can be used to connect to networks.</summary>
79+ <description>The format is ["nickname:realname:partmsg", "...", ...]</description>
80+ </key>
81+ <key name="networks" type="as">
82+ <default>["irc.freenode.net:Freenode:", "irc.gimp.org:GimpNet:"]</default>
83+ <summary>Networks too choose from when joining a channel.</summary>
84+ <description>The format is ["address:name:password", "..."]</description>
85 </key>
86 <key name="channels" type="as">
87- <default>[]</default>
88- <summary>Channels to be joined on startup, typically from last session</summary>
89- <description>These channels in the form "server:#channel" will be joined on startup</description>
90+ <default>[]</default>
91+ <summary>Channels to be joined on startup, typically from last session</summary>
92+ <description>These channels in the form "network address:nickname:#channel" will be joined on startup</description>
93 </key>
94 </schema>
95 </schemalist>
96
97=== modified file 'po/cable.pot'
98--- po/cable.pot 2013-06-04 20:46:10 +0000
99+++ po/cable.pot 2013-06-28 19:09:26 +0000
100@@ -3,12 +3,13 @@
101 # This file is distributed under the same license as the PACKAGE package.
102 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
103 #
104+#: /home/tutebatti/cable/po/../src/Widgets/Server.vala:121
105 #, fuzzy
106 msgid ""
107 msgstr ""
108 "Project-Id-Version: PACKAGE VERSION\n"
109 "Report-Msgid-Bugs-To: \n"
110-"POT-Creation-Date: 2013-06-04 22:45+0200\n"
111+"POT-Creation-Date: 2013-06-23 18:12+0200\n"
112 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
113 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
114 "Language-Team: LANGUAGE <LL@li.org>\n"
115@@ -17,87 +18,68 @@
116 "Content-Type: text/plain; charset=UTF-8\n"
117 "Content-Transfer-Encoding: 8bit\n"
118
119-#: /home/gotwig/cable/po/../src/Cable.vala:63
120-msgid "Welcome to Cable"
121-msgstr ""
122-
123-#: /home/gotwig/cable/po/../src/Cable.vala:63
124-msgid "Connect to the IRC world"
125-msgstr ""
126-
127-#: /home/gotwig/cable/po/../src/Cable.vala:65
128-#: /home/gotwig/cable/po/../src/Cable.vala:70
129-msgid "Join a Channel"
130-msgstr ""
131-
132-#: /home/gotwig/cable/po/../src/Cable.vala:66
133-#: /home/gotwig/cable/po/../src/Widgets/Channel.vala:31
134-msgid "Leave Channel"
135-msgstr ""
136-
137-#: /home/gotwig/cable/po/../src/Cable.vala:67
138-msgid "Add a Server"
139-msgstr ""
140-
141-#: /home/gotwig/cable/po/../src/Cable.vala:68
142-msgid "Edit User Settings"
143-msgstr ""
144-
145-#: /home/gotwig/cable/po/../src/Cable.vala:70
146-msgid "Channel"
147-msgstr ""
148-
149-#: /home/gotwig/cable/po/../src/Cable.vala:71
150-#: /home/gotwig/cable/po/../src/Cable.vala:202
151-msgid "Server"
152-msgstr ""
153-
154-#: /home/gotwig/cable/po/../src/Cable.vala:71
155-msgid "Add a Custom Server"
156-msgstr ""
157-
158-#: /home/gotwig/cable/po/../src/Cable.vala:204
159-#: /home/gotwig/cable/po/../src/Cable.vala:215
160+#: /home/tutebatti/cable/po/../src/Widgets/Welcome.vala:8
161+msgid "Connect to the IRC world."
162+msgstr ""
163+
164+#: /home/tutebatti/cable/po/../src/Widgets/Welcome.vala:8
165+msgid "Join a Channel."
166+msgstr ""
167+
168+#: /home/tutebatti/cable/po/../src/Widgets/Welcome.vala:16
169+msgid "Network:"
170+msgstr ""
171+
172+#: /home/tutebatti/cable/po/../src/Widgets/Welcome.vala:20
173+msgid "Identity:"
174+msgstr ""
175+
176+#: /home/tutebatti/cable/po/../src/Widgets/Welcome.vala:24
177+msgid "Channel:"
178+msgstr ""
179+
180+#: /home/tutebatti/cable/po/../src/Widgets/Welcome.vala:45
181 msgid "Join Channel"
182 msgstr ""
183
184-#: /home/gotwig/cable/po/../src/Widgets/Channel.vala:32
185-msgid "Mark Away"
186-msgstr ""
187-
188-#: /home/gotwig/cable/po/../src/Widgets/Channel.vala:41
189-msgid "Away"
190-msgstr ""
191-
192-#: /home/gotwig/cable/po/../src/Widgets/Room.vala:73
193+#: /home/tutebatti/cable/po/../src/Widgets/Room.vala:57
194 msgid "Loading Topic…"
195 msgstr ""
196
197-#: /home/gotwig/cable/po/../src/Widgets/Room.vala:84
198+#: /home/tutebatti/cable/po/../src/Widgets/Room.vala:94
199+#: /home/tutebatti/cable/po/../src/Widgets/Room.vala:203
200+#: /home/tutebatti/cable/po/../src/Widgets/Room.vala:216
201 msgid "Operators"
202 msgstr ""
203
204-#: /home/gotwig/cable/po/../src/Widgets/Server.vala:150
205-#: /home/gotwig/cable/po/../src/Widgets/Server.vala:154
206-msgid "Add Server"
207-msgstr ""
208-
209-#: /home/gotwig/cable/po/../src/Widgets/Server.vala:162
210-msgid "Server Name:"
211-msgstr ""
212-
213-#: /home/gotwig/cable/po/../src/Widgets/Server.vala:164
214-msgid "Server URL:"
215-msgstr ""
216-
217-#: /home/gotwig/cable/po/../src/Widgets/SettingsDialog.vala:32
218-msgid "Done"
219-msgstr ""
220-
221-#: /home/gotwig/cable/po/../src/Widgets/SettingsDialog.vala:34
222-msgid "Nick:"
223-msgstr ""
224-
225-#: /home/gotwig/cable/po/../src/Widgets/SettingsDialog.vala:36
226-msgid "Real Name:"
227+#: /home/tutebatti/cable/po/../src/Widgets/Room.vala:202
228+#: /home/tutebatti/cable/po/../src/Widgets/Room.vala:215
229+msgid "Regular"
230+msgstr ""
231+
232+#: /home/tutebatti/cable/po/../src/Widgets/Room.vala:204
233+#: /home/tutebatti/cable/po/../src/Widgets/Room.vala:217
234+msgid "Voiced"
235+msgstr ""
236+
237+#: /home/tutebatti/cable/po/../src/Widgets/Channel.vala:31
238+msgid "Leave Channel"
239+msgstr ""
240+
241+#: /home/tutebatti/cable/po/../src/Widgets/Server.vala:110
242+#: /home/tutebatti/cable/po/../src/Widgets/Server.vala:122
243+msgid "Mark Away"
244+msgstr ""
245+
246+#: /home/tutebatti/cable/po/../src/Widgets/Server.vala:111
247+msgid "Leave all channels"
248+msgstr ""
249+
250+#: /home/tutebatti/cable/po/../src/Widgets/Server.vala:118
251+#, c-format
252+msgid "%s is away."
253+msgstr ""
254+
255+#: /home/tutebatti/cable/po/../src/Widgets/Server.vala:119
256+msgid "Mark Present"
257 msgstr ""
258
259=== modified file 'src/Cable.vala'
260--- src/Cable.vala 2013-06-07 12:59:28 +0000
261+++ src/Cable.vala 2013-06-28 19:09:26 +0000
262@@ -1,248 +1,85 @@
263-namespace Cable {
264-
265- /**
266- * Main class of the application. Manages one window.
267- */
268- public class App : Granite.Application {
269-
270- construct {
271- program_name = "Cable";
272- exec_name = "cable";
273-
274- build_data_dir = Constants.DATADIR;
275- build_pkg_data_dir = Constants.PKGDATADIR;
276- build_release_name = Constants.RELEASE_NAME;
277- build_version = Constants.VERSION;
278- build_version_info = Constants.VERSION_INFO;
279-
280- app_years = "2012";
281-
282- app_icon = "applications-chat";
283- app_launcher = "cable.desktop";
284- application_id = "net.launchpad.cable";
285-
286- main_url = "https://code.launchpad.net/cable";
287- bug_url = "https://bugs.launchpad.net/cable";
288- help_url = "https://code.launchpad.net/cable";
289- translate_url = "https://translations.launchpad.net/cable";
290-
291- about_authors = {"Tom Beckmann <tombeckmann@online.de>", "Akshay Shekher <voldyman666@gmail.com"};
292- about_documenters = {"Tom Beckmann <tombeckmann@online.de>"};
293- about_artists = {"Harvey Cabaguio"};
294- about_comments = "Development release, not all features implemented";
295- about_translators = "";
296- about_license_type = Gtk.License.GPL_3_0;
297- }
298-
299- Gtk.Window window;
300- bool welcome_shown;
301-
302- public Gtk.EventBox display_box;
303- public Widgets.ServerList server_list;
304-
305- Gtk.Toolbar toolbar;
306- Gtk.Box layout;
307- Granite.Widgets.ThinPaned paned;
308- Gtk.Box sidebar;
309- Gtk.Menu menu;
310- Granite.Widgets.Welcome welcome;
311-
312- public App () {
313- Granite.Services.Logger.initialize ("Cable");
314- Granite.Services.Logger.DisplayLevel = Granite.Services.LogLevel.DEBUG;
315- }
316-
317- void build () {
318-
319- window = new Gtk.Window ();
320- layout = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
321- server_list = new Widgets.ServerList ();
322- display_box = new Gtk.EventBox ();
323- toolbar = new Gtk.Toolbar ();
324- paned = new Granite.Widgets.ThinPaned ();
325- menu = new Gtk.Menu ();
326- sidebar = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
327- welcome = new Granite.Widgets.Welcome (_("Welcome to Cable"), _("Connect to the IRC world"));
328-
329- layout.pack_start( toolbar, false, false, 0);
330-
331- var join_button = new Gtk.ToolButton (new Gtk.Image.from_icon_name ("list-add", Gtk.IconSize.SMALL_TOOLBAR), _("Join a Channel"));
332- var leave_button = new Gtk.ToolButton (new Gtk.Image.from_icon_name ("list-remove", Gtk.IconSize.SMALL_TOOLBAR), _("Leave Channel"));
333- var user_settings_button = new Gtk.ToolButton (new Gtk.Image.from_icon_name ("avatar-default", Gtk.IconSize.SMALL_TOOLBAR), _("Leave Channel"));
334- var add_server_buttton = new Gtk.ToolButton (new Gtk.Image.from_icon_name ("network-server", Gtk.IconSize.SMALL_TOOLBAR), _("Add a Server"));
335- toolbar.insert(join_button, -1);
336- toolbar.insert(leave_button, -1);
337- toolbar.insert(user_settings_button, -1);
338- toolbar.insert(add_server_buttton, -1);
339-
340- welcome.append ("internet-web-browser", _("Channel"), _("Join a Channel"));
341- welcome.append ("network-server", _("Server"), _("Add a Custom Server"));
342-
343- /*var exp = new Gtk.ToolItem ();
344- exp.set_expand (true);
345-
346- menu.append (edit_user);
347-
348- toolbar.insert (exp, -1);
349- toolbar.insert (join_button, -1);
350- toolbar.insert (leave_button, -1);
351- toolbar.insert (exp, -1);
352- toolbar.get_style_context ().add_class (Gtk.STYLE_CLASS_INLINE_TOOLBAR);
353- toolbar.icon_size = 1;*/
354-
355- paned.position = 150;
356-
357- sidebar.pack_start (server_list);
358-
359- paned.pack1 (sidebar, false, false);
360- paned.pack2 (display_box, true, false);
361-
362- window.set_application (this);
363- window.title = "Cable";
364- window.icon_name = "internet-chat";
365- window.set_default_size (740, 480);
366- window.window_position = Gtk.WindowPosition.CENTER;
367-
368- welcome.activated.connect ((index) => {
369- if (index == 0) {
370- var dialog = get_join_dialog ();
371- dialog.show_all ();
372- dialog.run ();
373- } else {
374- var dialog = Widgets.Server.get_add_dialog ();
375- dialog.show_all ();
376- dialog.run ();
377- }
378- });
379-
380- join_button.clicked.connect (() => {
381- var dialog = get_join_dialog ();
382- dialog.show_all ();
383- dialog.run ();
384- });
385-
386- leave_button.clicked.connect (() => {
387- server_list.current_server.leave_channel (server_list.current_channel.name);
388- });
389-
390- add_server_buttton.clicked.connect (() => {
391- var dialog = Widgets.Server.get_add_dialog ();
392- dialog.show_all ();
393- dialog.run ();
394- });
395-
396- user_settings_button.clicked.connect (() => {
397- var settings_dialog = new Widgets.SettingsDialog ();
398- settings_dialog.show_all ();
399- settings_dialog.run ();
400- });
401-
402- server_list.item_selected.connect ((item) => {
403- if (item != null && item is Widgets.Channel) {
404- display_box.remove (display_box.get_children ().nth_data (0));
405- display_box.add ((item as Widgets.Channel).room);
406- display_box.show_all ();
407- }
408- });
409-
410- /*initial setup*/
411- var settings = Cable.Settings.get_default ();
412-
413- //we got something to do
414- if (settings.channels.length > 0) {
415-
416- } else {
417- welcome_shown = true;
418- layout.pack_start (welcome, true, true, 0);
419- window.add (layout);
420- window.show_all ();
421- }
422-
423- //configuration incomplete
424- if (settings.real_name == "" || settings.nick == "") {
425- var settings_dialog = new Widgets.SettingsDialog ();
426- settings_dialog.show_all ();
427- settings_dialog.run ();
428- }
429- }
430-
431- public void join_channel (string? server_name, string server_URI, string channel_name) {
432- var server = server_list.get_server_by_URI (server_URI)
433- ?? new Widgets.Server (server_name, server_URI);
434- server_list.add_server (server);
435-
436- server.joined_channel.connect ((channel) => {
437- if (welcome_shown) {
438- welcome_shown = false;
439-
440- layout.remove (welcome);
441- layout.pack_start (paned, true, true, 0);
442- this.window.add (layout);
443- this.window.show_all ();
444-
445- server_list.selected = channel;
446- }
447- });
448-
449- server.left_channel.connect ((channel) => {
450- if (server_list.get_n_servers () == 0) {
451- welcome_shown = true;
452-
453- layout.remove (paned);
454- layout.pack_start (welcome, true, true, 0);
455- this.window.add (layout);
456- this.window.show_all ();
457- }
458- });
459-
460- server.join_channel (channel_name);
461- }
462-
463- public Gtk.Dialog get_join_dialog () {
464- var dialog = new Gtk.Dialog ();
465- dialog.modal = true;
466-
467- var box = new Gtk.Grid ();
468- box.margin = 12;
469- box.column_spacing = 6;
470- box.row_spacing = 6;
471-
472- var entry = new Gtk.Entry ();
473- var serverlabel = new Gtk.Label (_("Server"));
474- entry.secondary_icon_name = "edit-redo-symbolic";
475-
476- var list = Widgets.Server.get_server_list ();
477-
478-
479- box.attach (serverlabel, 0, 0, 1, 1);
480- serverlabel.set_alignment ( 1, 0.5f);
481- box.attach (list, 1, 0, 1, 1);
482- box.attach (new Gtk.Label (_("Join Channel") + " #"), 0, 1, 1, 1);
483- box.attach (entry, 1, 1, 1, 1);
484- box.margin = 6;
485-
486- entry.icon_release.connect (() => entry.activate ());
487- entry.activate.connect (() => {
488- join_channel (list.get_active_text (), list.active_id, "#"+entry.text);
489- dialog.destroy ();
490- });
491-
492- (dialog.get_content_area () as Gtk.Container).add (box);
493- dialog.title = _("Join Channel");
494-
495- entry.grab_focus ();
496-
497- return dialog;
498- }
499-
500- public override void activate () {
501- build ();
502- }
503- }
504-}
505-
506-public static int main (string [] args) {
507- Gtk.init (ref args);
508- var cable = new Cable.App ();
509- return cable.run (args);
510-}
511+/***
512+ Copyright (C) 2013 Cable Developers
513+
514+ This program or library is free software; you can redistribute it
515+ and/or modify it under the terms of the GNU Lesser General Public
516+ License as published by the Free Software Foundation; either
517+ version 3 of the License, or (at your option) any later version.
518+
519+ This library is distributed in the hope that it will be useful,
520+ but WITHOUT ANY WARRANTY; without even the implied warranty of
521+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
522+ Lesser General Public License for more details.
523+
524+ You should have received a copy of the GNU Lesser General
525+ Public License along with this library; if not, write to the
526+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
527+ Boston, MA 02110-1301 USA.
528+***/
529+
530+/**
531+ * Main class of the application.
532+ */
533+public class Cable.App : Granite.Application {
534+
535+ construct {
536+ build_data_dir = Constants.DATADIR;
537+ build_pkg_data_dir = Constants.PKGDATADIR;
538+ build_release_name = Constants.RELEASE_NAME;
539+ build_version = Constants.VERSION;
540+ build_version_info = Constants.VERSION_INFO;
541+
542+ program_name = "Cable";
543+ exec_name = "cable";
544+
545+ app_years = "2012-2013";
546+ app_icon = "internet-chat";
547+ app_launcher = "cable.desktop";
548+ //application_id = "net.launchpad.cable";
549+
550+ main_url = "https://code.launchpad.net/cable";
551+ bug_url = "https://bugs.launchpad.net/cable";
552+ help_url = "https://answers.launchpad.net/cable";
553+ translate_url = "https://translations.launchpad.net/cable";
554+
555+ about_authors = {"Tom Beckmann <tombeckmann@online.de>", "Akshay Shekher <voldyman666@gmail.com", "Julien Spautz <spautz.julien@gmail.com"};
556+ about_documenters = {"Tom Beckmann <tombeckmann@online.de>"};
557+ about_artists = {"Harvey Cabaguio <harveycabaguio@gmail.com"};
558+ about_comments = "Development release, not all features implemented";
559+ about_translators = "Launchpad Translators";
560+ about_license_type = Gtk.License.GPL_3_0;
561+ }
562+
563+ public App () {
564+ Granite.Services.Logger.initialize ("Cable");
565+ Granite.Services.Logger.DisplayLevel = Granite.Services.LogLevel.DEBUG;
566+ }
567+
568+ public override void activate () {
569+ var window = new Cable.Window (this);
570+ this.add_window (window);
571+ window.show ();
572+ }
573+
574+ static const OptionEntry[] entries = {
575+ { null }
576+ // version
577+ // reset - reset all settings
578+ };
579+
580+ public static int main (string[] args) {
581+ var context = new OptionContext ("File");
582+ context.add_main_entries (entries, Constants.GETTEXT_PACKAGE);
583+
584+ try {
585+ context.parse (ref args);
586+ }
587+ catch (Error e) {
588+ print (e.message + "\n");
589+ }
590+
591+ var cable = new Cable.App ();
592+ return cable.run (args);
593+ }
594+}
595+
596
597=== modified file 'src/Config.vala.cmake'
598--- src/Config.vala.cmake 2013-05-16 13:18:25 +0000
599+++ src/Config.vala.cmake 2013-06-28 19:09:26 +0000
600@@ -16,11 +16,11 @@
601 //
602
603 namespace Constants {
604-public const string DATADIR = "@DATADIR@";
605-public const string PKGDATADIR = "@PKGDATADIR@";
606-public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@";
607-public const string RELEASE_NAME = "@RELEASE_NAME@";
608-public const string VERSION = "@VERSION@";
609-public const string VERSION_INFO = "@VERSION_INFO@";
610-public const string PLUGINDIR = "@PLUGINDIR@";
611+ public const string DATADIR = "@DATADIR@";
612+ public const string PKGDATADIR = "@PKGDATADIR@";
613+ public const string GETTEXT_PACKAGE = "@GETTEXT_PACKAGE@";
614+ public const string RELEASE_NAME = "@RELEASE_NAME@";
615+ public const string VERSION = "@VERSION@";
616+ public const string VERSION_INFO = "@VERSION_INFO@";
617+ public const string PLUGINDIR = "@PLUGINDIR@";
618 }
619
620=== added directory 'src/Dialogs'
621=== added file 'src/Dialogs/JoinChannel.vala'
622--- src/Dialogs/JoinChannel.vala 1970-01-01 00:00:00 +0000
623+++ src/Dialogs/JoinChannel.vala 2013-06-28 19:09:26 +0000
624@@ -0,0 +1,97 @@
625+/***
626+ Copyright (C) 2013 Cable Developers
627+
628+ This program or library is free software; you can redistribute it
629+ and/or modify it under the terms of the GNU Lesser General Public
630+ License as published by the Free Software Foundation; either
631+ version 3 of the License, or (at your option) any later version.
632+
633+ This library is distributed in the hope that it will be useful,
634+ but WITHOUT ANY WARRANTY; without even the implied warranty of
635+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
636+ Lesser General Public License for more details.
637+
638+ You should have received a copy of the GNU Lesser General
639+ Public License along with this library; if not, write to the
640+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
641+ Boston, MA 02110-1301 USA.
642+***/
643+
644+public class Cable.Dialogs.JoinChannel : Granite.Widgets.LightWindow {
645+
646+ public signal void done (Settings.Network network, Settings.Identity identity, string channel);
647+
648+ public JoinChannel () {
649+ this.modal = true;
650+ this.window_position = Gtk.WindowPosition.CENTER;
651+
652+ var grid = new Gtk.Grid ();
653+ grid.margin = 12;
654+ grid.column_spacing = 6;
655+ grid.row_spacing = 6;
656+
657+ // Labels
658+ var server_label = new Gtk.Label (_("Network:"));
659+ server_label.halign = Gtk.Align.END;
660+ server_label.valign = Gtk.Align.CENTER;
661+
662+ var id_label = new Gtk.Label (_("Identity:"));
663+ id_label.halign = Gtk.Align.END;
664+ id_label.valign = Gtk.Align.CENTER;
665+
666+ var channel_label = new Gtk.Label (_("Channel:"));
667+ channel_label.halign = Gtk.Align.END;
668+ channel_label.valign = Gtk.Align.CENTER;
669+
670+ // Entries/Comboboxes
671+ var server_entry = new Gtk.ComboBoxText.with_entry ();
672+ for (int i = 0; i < Settings.networks.size; i++)
673+ server_entry.append (i.to_string (), Settings.networks[i].name);
674+ server_entry.active = 0;
675+
676+ var id_entry = new Gtk.ComboBoxText.with_entry ();
677+ for (int i = 0; i < Settings.identities.size; i++)
678+ id_entry.append (i.to_string (), Settings.identities[i].nick_name);
679+ id_entry.active = 0;
680+
681+ var channel_entry = new Gtk.Entry ();
682+ channel_entry.secondary_icon_name = "edit-redo-symbolic";
683+
684+ grid.attach (server_label, 0, 0, 1, 1);
685+ grid.attach (server_entry, 1, 0, 1, 1);
686+ grid.attach (id_label, 0, 1, 1, 1);
687+ grid.attach (id_entry, 1, 1, 1, 1);
688+ grid.attach (channel_label, 0, 2, 1, 1);
689+ grid.attach (channel_entry, 1, 2, 1, 1);
690+ grid.margin = 6;
691+
692+ add (grid);
693+ this.title = _("Join Channel");
694+
695+ channel_entry.text = "#";
696+ channel_entry.grab_focus ();
697+ channel_entry.set_position (-1);
698+
699+ channel_entry.icon_release.connect (() => channel_entry.activate ());
700+ channel_entry.activate.connect (() => {
701+ Settings.Network network;
702+ Settings.Identity identity;
703+
704+ if (server_entry.active_id == null) {
705+ network = new Settings.Network (server_entry.get_active_text ());
706+ } else {
707+ network = Settings.networks[int.parse (server_entry.active_id)];
708+ }
709+
710+ if (id_entry.active_id == null) {
711+ identity = new Settings.Identity (id_entry.get_active_text ());
712+ } else {
713+ identity = Settings.identities[int.parse (id_entry.active_id)];
714+ }
715+
716+ done (network, identity, channel_entry.text);
717+
718+ this.destroy ();
719+ });
720+ }
721+}
722
723=== added file 'src/Dialogs/ManageIdentity.vala'
724--- src/Dialogs/ManageIdentity.vala 1970-01-01 00:00:00 +0000
725+++ src/Dialogs/ManageIdentity.vala 2013-06-28 19:09:26 +0000
726@@ -0,0 +1,117 @@
727+/***
728+ Copyright (C) 2013 Cable Developers
729+
730+ This program or library is free software; you can redistribute it
731+ and/or modify it under the terms of the GNU Lesser General Public
732+ License as published by the Free Software Foundation; either
733+ version 3 of the License, or (at your option) any later version.
734+
735+ This library is distributed in the hope that it will be useful,
736+ but WITHOUT ANY WARRANTY; without even the implied warranty of
737+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
738+ Lesser General Public License for more details.
739+
740+ You should have received a copy of the GNU Lesser General
741+ Public License along with this library; if not, write to the
742+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
743+ Boston, MA 02110-1301 USA.
744+***/
745+
746+/**
747+ * Add or edit an identity.
748+ */
749+public class Cable.Dialogs.ManageIdentity : Granite.Widgets.LightWindow {
750+
751+ /**
752+ * @param identity Resulting identity.
753+ */
754+ public signal void done (Settings.Identity identity);
755+
756+ /**
757+ * @param identity Identity to be edited or null if you want to create
758+ * a new one.
759+ */
760+ public ManageIdentity (Settings.Identity? identity = null) {
761+ this.modal = true;
762+ this.window_position = Gtk.WindowPosition.CENTER;
763+
764+ var grid = new Gtk.Grid ();
765+ grid.margin = 12;
766+ grid.column_spacing = 6;
767+ grid.row_spacing = 6;
768+
769+ var nick_name = new Gtk.Entry ();
770+ nick_name.placeholder_text = _("displayed in chats");
771+ nick_name.width_request = 250;
772+ var real_name = new Gtk.Entry ();
773+ real_name.placeholder_text = _("your real name");
774+ var part_message = new Gtk.Entry ();
775+ part_message.placeholder_text = _("displayed when you leave a room");
776+
777+ grid.attach (new Utils.Label.right (_("Nick Name:")), 0, 0, 1, 1);
778+ grid.attach (nick_name, 1, 0, 1, 1);
779+ grid.attach (new Utils.Label.right (_("Real Name:")), 0, 1, 1, 1);
780+ grid.attach (real_name, 1, 1, 1, 1);
781+ grid.attach (new Utils.Label.right (_("Part Message:")), 0, 2, 1, 1);
782+ grid.attach (part_message, 1, 2, 1, 1);
783+
784+ var cancel_button = new Gtk.Button.with_label (_("Cancel"));
785+ var apply_button = new Gtk.Button ();
786+ apply_button.label = (identity == null) ? _("Add Identity")
787+ : _("Apply Changes");
788+ apply_button.sensitive = (identity != null);
789+
790+ var button_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
791+ button_box.layout_style = Gtk.ButtonBoxStyle.END;
792+ button_box.add (cancel_button);
793+ button_box.add (apply_button);
794+
795+ grid.attach (button_box, 0, 3, 2, 1);
796+
797+ this.add (grid);
798+ this.title = (identity == null) ? _("Add Identity")
799+ : _("Edit Identity");
800+
801+ if (identity != null) {
802+ nick_name.text = identity.nick_name;
803+ real_name.text = identity.real_name;
804+ part_message.text = identity.part_message;
805+ }
806+
807+ nick_name.changed.connect (() => {
808+ apply_button.sensitive = (nick_name.text != "");
809+ });
810+
811+ apply_button.clicked.connect (() => {
812+ if (identity == null) {
813+ done (create_identity (nick_name.text, real_name.text, part_message.text));
814+ } else {
815+ identity.real_name = real_name.text.strip ();
816+ identity.nick_name = nick_name.text.strip ();
817+ identity.part_message = part_message.text.strip ();
818+ done (identity);
819+ }
820+
821+ this.destroy ();
822+ });
823+
824+ cancel_button.clicked.connect (() => {
825+ this.destroy ();
826+ });
827+ }
828+
829+ Settings.Identity create_identity (string nick_name, string real_name,
830+ string part_message)
831+ requires (nick_name.strip () != "") {
832+
833+ if (nick_name.strip () == "")
834+ return (Settings.Identity) null;
835+
836+ if (real_name.strip () == "")
837+ real_name = null;
838+ if (part_message.strip () == "")
839+ part_message = null;
840+
841+ return new Settings.Identity (nick_name, real_name, part_message);
842+ }
843+}
844
845=== added file 'src/Dialogs/ManageNetwork.vala'
846--- src/Dialogs/ManageNetwork.vala 1970-01-01 00:00:00 +0000
847+++ src/Dialogs/ManageNetwork.vala 2013-06-28 19:09:26 +0000
848@@ -0,0 +1,116 @@
849+/***
850+ Copyright (C) 2013 Cable Developers
851+
852+ This program or library is free software; you can redistribute it
853+ and/or modify it under the terms of the GNU Lesser General Public
854+ License as published by the Free Software Foundation; either
855+ version 3 of the License, or (at your option) any later version.
856+
857+ This library is distributed in the hope that it will be useful,
858+ but WITHOUT ANY WARRANTY; without even the implied warranty of
859+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
860+ Lesser General Public License for more details.
861+
862+ You should have received a copy of the GNU Lesser General
863+ Public License along with this library; if not, write to the
864+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
865+ Boston, MA 02110-1301 USA.
866+***/
867+
868+/**
869+ * Add or edit a network.
870+ */
871+public class Cable.Dialogs.ManageNetwork : Granite.Widgets.LightWindow {
872+
873+ /**
874+ * @param network Resulting network.
875+ */
876+ public signal void done (Settings.Network network);
877+
878+ /**
879+ * @param network Network to be edited or null if you want to create
880+ * a new one.
881+ */
882+ public ManageNetwork (Settings.Network? network = null) {
883+ this.modal = true;
884+ this.window_position = Gtk.WindowPosition.CENTER;
885+
886+ var grid = new Gtk.Grid ();
887+ grid.margin = 12;
888+ grid.column_spacing = 6;
889+ grid.row_spacing = 6;
890+
891+ var address = new Gtk.Entry ();
892+ address.placeholder_text = _("irc.network.net");
893+ address.width_request = 250;
894+ var name = new Gtk.Entry ();
895+ name.placeholder_text = _("display name");
896+ var password = new Gtk.Entry ();
897+ password.placeholder_text = _("optional");
898+
899+ grid.attach (new Utils.Label.right (_("Address:")), 0, 0, 1, 1);
900+ grid.attach (address, 1, 0, 1, 1);
901+ grid.attach (new Utils.Label.right (_("Name:")), 0, 1, 1, 1);
902+ grid.attach (name, 1, 1, 1, 1);
903+ grid.attach (new Utils.Label.right (_("Password:")), 0, 2, 1, 1);
904+ grid.attach (password, 1, 2, 1, 1);
905+
906+ var cancel_button = new Gtk.Button.with_label (_("Cancel"));
907+ var apply_button = new Gtk.Button ();
908+ apply_button.label = (network == null) ? _("Add Network")
909+ : _("Apply Changes");
910+ apply_button.sensitive = (network != null);
911+
912+ var button_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
913+ button_box.layout_style = Gtk.ButtonBoxStyle.END;
914+ button_box.add (cancel_button);
915+ button_box.add (apply_button);
916+
917+ grid.attach (button_box, 0, 3, 2, 1);
918+
919+ this.add (grid);
920+ this.title = (network == null) ? _("Add Network")
921+ : _("Change Network");
922+
923+ if (network != null) {
924+ address.text = network.address;
925+ name.text = network.name;
926+ password.text = network.password;
927+ }
928+
929+ address.changed.connect (() => {
930+ apply_button.sensitive = (address.text != "");
931+ });
932+
933+ apply_button.clicked.connect (() => {
934+ if (network == null) {
935+ done (create_network (address.text, name.text, password.text));
936+ } else {
937+ network.address = address.text.strip ();
938+ network.name = name.text.strip ();
939+ network.password = password.text.strip ();
940+ done (network);
941+ }
942+ this.destroy ();
943+ });
944+
945+ cancel_button.clicked.connect (() => {
946+ this.destroy ();
947+ });
948+ }
949+
950+ Settings.Network create_network (string address, string name,
951+ string password)
952+ requires (address.strip () != "") {
953+
954+ if (address.strip () == "")
955+ return (Settings.Network) null;
956+
957+ if (name.strip () == "")
958+ name = null;
959+ if (password.strip () == "")
960+ password = null;
961+
962+ return new Settings.Network (address, name, password);
963+ }
964+}
965
966=== added file 'src/Dialogs/Preferences.vala'
967--- src/Dialogs/Preferences.vala 1970-01-01 00:00:00 +0000
968+++ src/Dialogs/Preferences.vala 2013-06-28 19:09:26 +0000
969@@ -0,0 +1,214 @@
970+/***
971+ Copyright (C) 2013 Cable Developers
972+
973+ This program or library is free software; you can redistribute it
974+ and/or modify it under the terms of the GNU Lesser General Public
975+ License as published by the Free Software Foundation; either
976+ version 3 of the License, or (at your option) any later version.
977+
978+ This library is distributed in the hope that it will be useful,
979+ but WITHOUT ANY WARRANTY; without even the implied warranty of
980+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
981+ Lesser General Public License for more details.
982+
983+ You should have received a copy of the GNU Lesser General
984+ Public License along with this library; if not, write to the
985+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
986+ Boston, MA 02110-1301 USA.
987+***/
988+
989+public class Cable.Dialogs.Preferences : Granite.Widgets.LightWindow {
990+
991+ public Preferences () {
992+ this.window_position = Gtk.WindowPosition.CENTER;
993+
994+ var static_notebook = new Granite.Widgets.StaticNotebook (false);
995+ static_notebook.margin = 12;
996+ static_notebook.expand = true;
997+ static_notebook.append_page (new NetworkPrefs (), new Gtk.Label (_("Networks")));
998+ static_notebook.append_page (new IdentityPrefs (), new Gtk.Label (_("Identities")));
999+
1000+ this.add (static_notebook);
1001+ }
1002+}
1003+
1004+public class Cable.Dialogs.NetworkPrefs : Gtk.Grid {
1005+
1006+ public NetworkPrefs () {
1007+ var tree = new Gtk.TreeView ();
1008+ var scroll = new Gtk.ScrolledWindow(null, null);
1009+
1010+ sync (tree);
1011+
1012+ var cell = new Gtk.CellRendererText ();
1013+ tree.insert_column_with_attributes (-1, "Name", cell, "text", 0);
1014+ tree.insert_column_with_attributes (-1, "Address", cell, "text", 1);
1015+
1016+ scroll.set_size_request (300, 300);
1017+ scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
1018+ scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
1019+ scroll.shadow_type = Gtk.ShadowType.IN;
1020+ scroll.expand = true;
1021+ scroll.add (tree);
1022+
1023+ var toolbar = new Gtk.Toolbar();
1024+ toolbar.set_style(Gtk.ToolbarStyle.ICONS);
1025+ toolbar.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR);
1026+ toolbar.set_show_arrow(false);
1027+ toolbar.hexpand = true;
1028+
1029+ scroll.get_style_context().set_junction_sides(Gtk.JunctionSides.BOTTOM);
1030+ toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);
1031+ toolbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP);
1032+
1033+ var add_button = new Gtk.ToolButton (null, _("Add…"));
1034+ var remove_button = new Gtk.ToolButton (null, _("Remove"));
1035+
1036+ add_button.set_tooltip_text (_("Add…"));
1037+ remove_button.set_tooltip_text (_("Remove"));
1038+
1039+ add_button.set_icon_name ("list-add-symbolic");
1040+ remove_button.set_icon_name ("list-remove-symbolic");
1041+
1042+ toolbar.insert (add_button, -1);
1043+ toolbar.insert (remove_button, -1);
1044+
1045+ this.attach (scroll, 0, 0, 1, 1);
1046+ this.attach (toolbar, 0, 1, 1, 1);
1047+
1048+ add_button.clicked.connect (() => {
1049+ var dialog = new Dialogs.ManageNetwork ();
1050+ dialog.done.connect ((network) => {
1051+ Settings.networks.add (network);
1052+ this.sync (tree);
1053+ });
1054+ dialog.show_all ();
1055+ });
1056+
1057+ remove_button.clicked.connect (() => {
1058+ Gtk.TreePath? path;
1059+ tree.get_cursor (out path, null);
1060+
1061+ if (path == null)
1062+ return;
1063+
1064+ var index = path.get_indices ()[0];
1065+ Settings.networks.remove (Settings.networks[index]);
1066+ sync (tree);
1067+ });
1068+
1069+ tree.row_activated.connect ((path) => {
1070+ var index = path.get_indices ()[0];
1071+ var dialog = new Dialogs.ManageNetwork (Settings.networks[index]);
1072+ dialog.done.connect (() => {
1073+ //Settings.networks[index] = network;
1074+ this.sync (tree);
1075+ });
1076+ dialog.show_all ();
1077+ });
1078+ }
1079+
1080+ private void sync (Gtk.TreeView tree) {
1081+ var store = new Gtk.ListStore (2, typeof (string), typeof (string));
1082+
1083+ Gtk.TreeIter iter;
1084+
1085+ foreach (var network in Settings.networks) {
1086+ store.append (out iter);
1087+ store.set (iter, 0, network.name, 1, network.address, -1);
1088+ }
1089+
1090+ tree.model = store;
1091+ }
1092+}
1093+
1094+ public class Cable.Dialogs.IdentityPrefs : Gtk.Grid {
1095+
1096+ public IdentityPrefs () {
1097+ var store = new Gtk.ListStore (2, typeof (string), typeof (string));
1098+ var tree = new Gtk.TreeView ();
1099+ var scroll = new Gtk.ScrolledWindow(null, null);
1100+
1101+ sync (tree);
1102+
1103+ var cell = new Gtk.CellRendererText ();
1104+ tree.insert_column_with_attributes (-1, "Nick", cell, "text", 0);
1105+ tree.insert_column_with_attributes (-1, "Real Name", cell, "text", 1);
1106+
1107+ scroll.set_size_request (300, 300);
1108+ scroll.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
1109+ scroll.vscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
1110+ scroll.shadow_type = Gtk.ShadowType.IN;
1111+ scroll.expand = true;
1112+ scroll.add (tree);
1113+
1114+ var toolbar = new Gtk.Toolbar();
1115+ toolbar.set_style(Gtk.ToolbarStyle.ICONS);
1116+ toolbar.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR);
1117+ toolbar.set_show_arrow(false);
1118+ toolbar.hexpand = true;
1119+
1120+ scroll.get_style_context().set_junction_sides(Gtk.JunctionSides.BOTTOM);
1121+ toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);
1122+ toolbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP);
1123+
1124+ var add_button = new Gtk.ToolButton (null, _("Add"));
1125+ var remove_button = new Gtk.ToolButton (null, _("Remove"));
1126+
1127+ add_button.set_tooltip_text (_("Add"));
1128+ remove_button.set_tooltip_text (_("Remove"));
1129+
1130+ add_button.set_icon_name ("list-add-symbolic");
1131+ remove_button.set_icon_name ("list-remove-symbolic");
1132+
1133+ toolbar.insert (add_button, -1);
1134+ toolbar.insert (remove_button, -1);
1135+
1136+ this.attach (scroll, 0, 0, 1, 1);
1137+ this.attach (toolbar, 0, 1, 1, 1);
1138+
1139+ add_button.clicked.connect (() => {
1140+ var dialog = new Dialogs.ManageIdentity ();
1141+ dialog.done.connect ((identitie) => {
1142+ Settings.identities.add (identitie);
1143+ this.sync (tree);
1144+ });
1145+ dialog.show_all ();
1146+ });
1147+
1148+ remove_button.clicked.connect (() => {
1149+ Gtk.TreePath? path;
1150+ tree.get_cursor (out path, null);
1151+
1152+ if (path == null)
1153+ return;
1154+
1155+ var index = path.get_indices ()[0];
1156+ Settings.identities.remove (Settings.identities[index]);
1157+ sync (tree);
1158+ });
1159+
1160+ tree.row_activated.connect ((path) => {
1161+ var index = path.get_indices ()[0];
1162+ var dialog = new Dialogs.ManageIdentity (Settings.identities[index]);
1163+ dialog.done.connect (() => {
1164+ //Settings.identities[index] = id;
1165+ this.sync (tree);
1166+ });
1167+ dialog.show_all ();
1168+ });
1169+ }
1170+
1171+ private void sync (Gtk.TreeView tree) {
1172+ var store = new Gtk.ListStore (2, typeof (string), typeof (string));
1173+
1174+ Gtk.TreeIter iter;
1175+
1176+ foreach (var identity in Settings.identities) {
1177+ store.append (out iter);
1178+ store.set (iter, 0, identity.nick_name, 1, identity.real_name, -1);
1179+ }
1180+
1181+ tree.model = store;
1182+ }
1183+}
1184
1185=== removed file 'src/Global.vala'
1186--- src/Global.vala 2013-05-29 00:24:15 +0000
1187+++ src/Global.vala 1970-01-01 00:00:00 +0000
1188@@ -1,18 +0,0 @@
1189-namespace Cable {
1190-
1191- public class Global : Object {
1192-
1193- public string user_nick { get; set; }
1194-
1195- Global () {
1196- }
1197-
1198- static Global? instance;
1199-
1200- public static Global get_default () {
1201- if (instance == null)
1202- instance = new Global ();
1203- return instance;
1204- }
1205- }
1206-}
1207\ No newline at end of file
1208
1209=== added directory 'src/Services'
1210=== added file 'src/Services/Client.vala'
1211--- src/Services/Client.vala 1970-01-01 00:00:00 +0000
1212+++ src/Services/Client.vala 2013-06-28 19:09:26 +0000
1213@@ -0,0 +1,278 @@
1214+/***
1215+ Copyright (C) 2013 Cable Developers
1216+
1217+ This program or library is free software; you can redistribute it
1218+ and/or modify it under the terms of the GNU Lesser General Public
1219+ License as published by the Free Software Foundation; either
1220+ version 3 of the License, or (at your option) any later version.
1221+
1222+ This library is distributed in the hope that it will be useful,
1223+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1224+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1225+ Lesser General Public License for more details.
1226+
1227+ You should have received a copy of the GNU Lesser General
1228+ Public License along with this library; if not, write to the
1229+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1230+ Boston, MA 02110-1301 USA.
1231+***/
1232+
1233+/**
1234+ * This is a dbus interface to the maki daemon from the SushiIRC project.
1235+ * Use the methods to send requests or messages to the server and the
1236+ * signals to react to the server's replies.
1237+ *
1238+ * TODO document each function or take the actual documentation, if it exists
1239+ */
1240+[DBus (name = "de.ikkoku.sushi", timeout = 120000)]
1241+private interface Cable.Services.Client : GLib.Object {
1242+
1243+ [DBus (name = "action")]
1244+ public abstract void action (string server, string channel, string message) throws GLib.IOError;
1245+
1246+ [DBus (name = "away")]
1247+ public abstract void away (string server, string message) throws GLib.IOError;
1248+
1249+ [DBus (name = "back")]
1250+ public abstract void back (string server) throws GLib.IOError;
1251+
1252+ [DBus (name = "channel_nicks")]
1253+ public abstract void channel_nicks (string server, string channel, out string[] nicks, out string[] prefixes) throws GLib.IOError;
1254+
1255+ [DBus (name = "channel_topic")]
1256+ public abstract string channel_topic (string server, string channel) throws GLib.IOError;
1257+
1258+ [DBus (name = "channels")]
1259+ public abstract string[] channels (string server) throws GLib.IOError;
1260+
1261+ [DBus (name = "config_get")]
1262+ public abstract string config_get (string group, string key) throws GLib.IOError;
1263+
1264+ [DBus (name = "config_set")]
1265+ public abstract void config_set (string group, string key, string value) throws GLib.IOError;
1266+
1267+ [DBus (name = "connect")]
1268+ public abstract void connect (string server) throws GLib.IOError;
1269+
1270+ [DBus (name = "ctcp")]
1271+ public abstract void ctcp (string server, string target, string message) throws GLib.IOError;
1272+
1273+ [DBus (name = "dcc_send")]
1274+ public abstract void dcc_send(string server, string target, string path) throws GLib.IOError;
1275+
1276+ [DBus (name = "dcc_sends")]
1277+ public abstract void dcc_sends (out uint64[] ids, out string[] servers, out string[] froms, out string[] filenames, out uint64[] sizes, out uint64[] progresses, out uint64[] speeds, out uint64[] statuses) throws GLib.IOError;
1278+
1279+ [DBus (name = "dcc_send_accept")]
1280+ public abstract void dcc_send_accept (uint64 id) throws GLib.IOError;
1281+
1282+ [DBus (name = "dcc_send_get")]
1283+ public abstract string dcc_send_get (uint64 id, string key) throws GLib.IOError;
1284+
1285+ [DBus (name = "dcc_send_remove")]
1286+ public abstract void dcc_send_remove (uint64 id) throws GLib.IOError;
1287+
1288+ [DBus (name = "dcc_send_resume")]
1289+ public abstract void dcc_send_resume (uint64 id) throws GLib.IOError;
1290+
1291+ [DBus (name = "dcc_send_set")]
1292+ public abstract void dcc_send_set (uint64 id, string key, string value) throws GLib.IOError;
1293+
1294+ [DBus (name = "ignore")]
1295+ public abstract void ignore (string server, string pattern) throws GLib.IOError;
1296+
1297+ [DBus (name = "ignores")]
1298+ public abstract string[] ignores (string server) throws GLib.IOError;
1299+
1300+ [DBus (name = "invite")]
1301+ public abstract void invite (string server, string channel, string who) throws GLib.IOError;
1302+
1303+ [DBus (name = "join")]
1304+ public abstract void join (string server, string channel, string key) throws GLib.IOError;
1305+
1306+ [DBus (name = "kick")]
1307+ public abstract void kick (string server, string channel, string who, string message) throws GLib.IOError;
1308+
1309+ [DBus (name = "list")]
1310+ public abstract void list (string server, string channel) throws GLib.IOError;
1311+
1312+ [DBus (name = "log")]
1313+ public abstract string[] log (string server, string target, uint64 lines) throws GLib.IOError;
1314+
1315+ [DBus (name = "message")]
1316+ public abstract void message (string server, string target, string message) throws GLib.IOError;
1317+
1318+ [DBus (name = "mode")]
1319+ public abstract void mode (string server, string target, string mode) throws GLib.IOError;
1320+
1321+ [DBus (name = "names")]
1322+ public abstract void names (string server, string channel) throws GLib.IOError;
1323+
1324+ [DBus (name = "nick")]
1325+ public abstract void nick (string server, string nick) throws GLib.IOError;
1326+
1327+ [DBus (name = "nickserv")]
1328+ public abstract void nickserv (string server) throws GLib.IOError;
1329+
1330+ [DBus (name = "notice")]
1331+ public abstract void notice (string server, string target, string message) throws GLib.IOError;
1332+
1333+ [DBus (name = "oper")]
1334+ public abstract void oper (string server, string name, string password) throws GLib.IOError;
1335+
1336+ [DBus (name = "part")]
1337+ public abstract void part (string server, string channel, string message) throws GLib.IOError;
1338+
1339+ [DBus (name = "quit")]
1340+ public abstract void quit (string server, string message) throws GLib.IOError;
1341+
1342+ [DBus (name = "raw")]
1343+ public abstract void raw (string server, string command) throws GLib.IOError;
1344+
1345+ [DBus (name = "server_get")]
1346+ public abstract string server_get (string server, string group, string key) throws GLib.IOError;
1347+
1348+ [DBus (name = "server_get_list")]
1349+ public abstract string[] server_get_list (string server, string group, string key) throws GLib.IOError;
1350+
1351+ [DBus (name = "server_list")]
1352+ public abstract string[] server_list (string server, string group) throws GLib.IOError;
1353+
1354+ [DBus (name = "server_remove")]
1355+ public abstract void server_remove (string server, string group, string key) throws GLib.IOError;
1356+
1357+ [DBus (name = "server_rename")]
1358+ public abstract void server_rename (string old, string new_) throws GLib.IOError;
1359+
1360+ [DBus (name = "server_set")]
1361+ public abstract void server_set (string server, string group, string key, string value) throws GLib.IOError;
1362+
1363+ [DBus (name = "server_set_list")]
1364+ public abstract void server_set_list (string server, string group, string key, string[] list) throws GLib.IOError;
1365+
1366+ [DBus (name = "servers")]
1367+ public abstract string[] servers () throws GLib.IOError;
1368+
1369+ [DBus (name = "shutdown")]
1370+ public abstract void shutdown (string message) throws GLib.IOError;
1371+
1372+ [DBus (name = "support_chantypes")]
1373+ public abstract string support_chantypes (string server) throws GLib.IOError;
1374+
1375+ [DBus (name = "support_prefix")]
1376+ public abstract string[] support_prefix (string server) throws GLib.IOError;
1377+
1378+ [DBus (name = "topic")]
1379+ public abstract void topic (string server, string channel, string topic) throws GLib.IOError;
1380+
1381+ [DBus (name = "unignore")]
1382+ public abstract void unignore (string server, string pattern) throws GLib.IOError;
1383+
1384+ [DBus (name = "user_away")]
1385+ public abstract bool user_away (string server, string nick) throws GLib.IOError;
1386+
1387+ [DBus (name = "user_channel_mode")]
1388+ public abstract string user_channel_mode (string server, string channel, string nick) throws GLib.IOError;
1389+
1390+ [DBus (name = "user_channel_prefix")]
1391+ public abstract string user_channel_prefix (string server, string channel, string nick) throws GLib.IOError;
1392+
1393+ [DBus (name = "user_from")]
1394+ public abstract string user_from (string server, string nick) throws GLib.IOError;
1395+
1396+ [DBus (name = "version")]
1397+ public abstract uint64[] version () throws GLib.IOError;
1398+
1399+ [DBus (name = "who")]
1400+ public abstract void who (string server, string mask, bool operators_only) throws GLib.IOError;
1401+
1402+ [DBus (name = "whois")]
1403+ public abstract void whois (string server, string mask) throws GLib.IOError;
1404+
1405+ [DBus (name = "action")]
1406+ public signal void event_action (int64 time, string server, string from, string target, string message);
1407+
1408+ [DBus (name = "away")]
1409+ public signal void event_away (int64 time, string server);
1410+
1411+ [DBus (name = "away_message")]
1412+ public signal void event_away_message (int64 time, string server, string nick, string message);
1413+
1414+ [DBus (name = "back")]
1415+ public signal void event_back (int64 time, string server);
1416+
1417+ [DBus (name = "banlist")]
1418+ public signal void event_banlist (int64 time, string server, string channel, string mask, string who, int64 when);
1419+
1420+ [DBus (name = "cannot_join")]
1421+ public signal void event_cannot_join (int64 time, string server, string channel, string reason);
1422+
1423+ [DBus (name = "connect")]
1424+ public signal void event_connect (int64 time, string server);
1425+
1426+ [DBus (name = "connected")]
1427+ public signal void event_connected (int64 time, string server);
1428+
1429+ [DBus (name = "ctcp")]
1430+ public signal void event_ctcp (int64 time, string server, string from, string target, string message);
1431+
1432+ [DBus (name = "dcc_send")]
1433+ public signal void event_dcc_send (int64 time, string server, uint64 id, string from, string filename, uint64 size, uint64 progress, uint64 speed, uint64 status);
1434+
1435+ [DBus (name = "error")]
1436+ public signal void event_error (int64 time, string server, string domain, string reason, string[] arguments);
1437+
1438+ [DBus (name = "invite")]
1439+ public signal void event_invite (int64 time, string server, string from, string channel, string who);
1440+
1441+ [DBus (name = "join")]
1442+ public signal void event_join (int64 time, string server, string from, string channel);
1443+
1444+ [DBus (name = "kick")]
1445+ public signal void event_kick (int64 time, string server, string from, string channel, string who, string message);
1446+
1447+ [DBus (name = "list")]
1448+ public signal void event_list (int64 time, string server, string channel, int64 users, string topic);
1449+
1450+ [DBus (name = "message")]
1451+ public signal void event_message (int64 time, string server, string from, string target, string message);
1452+
1453+ [DBus (name = "mode")]
1454+ public signal void event_mode (int64 time, string server, string from, string target, string mode, string parameter);
1455+
1456+ [DBus (name = "motd")]
1457+ public signal void event_motd (int64 time, string server, string message);
1458+
1459+ [DBus (name = "names")]
1460+ public signal void event_names (int64 time, string server, string channel, string[] nicks, string[] prefixes);
1461+
1462+ [DBus (name = "nick")]
1463+ public signal void event_nick (int64 time, string server, string from, string new_nick);
1464+
1465+ [DBus (name = "no_such")]
1466+ public signal void event_no_such (int64 time, string server, string target, string type);
1467+
1468+ [DBus (name = "notice")]
1469+ public signal void event_notice (int64 time, string server, string from, string target, string message);
1470+
1471+ [DBus (name = "oper")]
1472+ public signal void event_oper (int64 time, string server);
1473+
1474+ [DBus (name = "part")]
1475+ public signal void event_part (int64 time, string server, string from, string channel, string message);
1476+
1477+ [DBus (name = "quit")]
1478+ public signal void event_quit (int64 time, string server, string from, string message);
1479+
1480+ [DBus (name = "shutdown")]
1481+ public signal void event_shutdown (int64 time);
1482+
1483+ [DBus (name = "topic")]
1484+ public signal void event_topic (int64 time, string server, string from, string channel, string topic);
1485+
1486+ [DBus (name = "user_away")]
1487+ public signal void event_user_away (int64 time, string server, string from, bool away);
1488+
1489+ [DBus (name = "whois")]
1490+ public signal void event_whois (int64 time, string server, string nick, string message);
1491+}
1492
1493=== added file 'src/Services/Identity.vala'
1494--- src/Services/Identity.vala 1970-01-01 00:00:00 +0000
1495+++ src/Services/Identity.vala 2013-06-28 19:09:26 +0000
1496@@ -0,0 +1,123 @@
1497+/***
1498+ Copyright (C) 2013 Cable Developers
1499+
1500+ This program or library is free software; you can redistribute it
1501+ and/or modify it under the terms of the GNU Lesser General Public
1502+ License as published by the Free Software Foundation; either
1503+ version 3 of the License, or (at your option) any later version.
1504+
1505+ This library is distributed in the hope that it will be useful,
1506+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1507+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1508+ Lesser General Public License for more details.
1509+
1510+ You should have received a copy of the GNU Lesser General
1511+ Public License along with this library; if not, write to the
1512+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1513+ Boston, MA 02110-1301 USA.
1514+***/
1515+
1516+/**
1517+ * This class stores one identity and provides some convenience over a
1518+ * simple struct.
1519+ */
1520+public class Cable.Settings.Identity : GLib.Object {
1521+
1522+ /**
1523+ * Nick name displayed to other users.
1524+ */
1525+ public string nick_name { get; construct set; }
1526+
1527+ /**
1528+ * Real name, can be anything pretty much.
1529+ */
1530+ public string real_name { get; construct set; }
1531+
1532+ /**
1533+ * ...
1534+ */
1535+ public string user_name { get; construct set; }
1536+
1537+ /**
1538+ * Message displayed when leaving a channel.
1539+ */
1540+ public string part_message { get; construct set; }
1541+
1542+ /**
1543+ * Message send in reply to a private message when marked away.
1544+ */
1545+ public string away_message { get; construct set; }
1546+
1547+ /**
1548+ * Message displayed when quitting a server.
1549+ */
1550+ public string quit_message { get; construct set; }
1551+
1552+ /**
1553+ * List of all identities.
1554+ */
1555+ public static Utils.Array <Identity> all { get; private set; }
1556+
1557+ /**
1558+ * Create a new identity, only the nick name is required.
1559+ */
1560+ public Identity (string nick_name,
1561+ string? real_name = null,
1562+ string? user_name = null,
1563+ string? part_message = null,
1564+ string? away_message = null,
1565+ string? quit_message = null)
1566+ // TODO check for invalid characters and stuff
1567+ requires (/^[a-z_\-\[\]\\^{}|`][a-z0-9_\-\[\]\\^{}|`]*$/i.match (nick_name)) {
1568+
1569+ this.nick_name = nick_name;
1570+ this.real_name = real_name ?? nick_name;
1571+ this.part_message = part_message ?? _("Bye.");
1572+ this.quit_message = quit_message ?? _("Quit server.");
1573+ this.away_message = away_message ?? _("%s is away.").printf (nick_name);
1574+
1575+ this.all.add (this);
1576+ this.notify.connect (() => Settings.identities.changed ());
1577+ }
1578+
1579+ ~Identity () {
1580+ this.all.remove (this);
1581+ }
1582+
1583+ public static void init () {
1584+ if (all != null)
1585+ return;
1586+
1587+ all = new Utils.Array <Identity> ();
1588+
1589+ foreach (var identity in settings.get_strv ("identities")) {
1590+ var values = identity.split (":");
1591+
1592+ if (values.length != 3) {
1593+ warning ("Invalid identity settings");
1594+ continue;
1595+ }
1596+
1597+ new Settings.Identity (values[0], values[1], values[2]);
1598+ }
1599+
1600+ all.changed.connect (() => {
1601+ string[] ids = {};
1602+
1603+ foreach (var id in all)
1604+ ids += string.join (":", id.nick_name, id.real_name, id.part_message);
1605+
1606+ settings.set_strv ("identities", ids);
1607+ });
1608+ }
1609+
1610+ /**
1611+ * Creates the default identity from your current login.
1612+ *
1613+ * @returns Default identity.
1614+ */
1615+ public static Identity get_default () {
1616+ // TODO
1617+ return new Identity ("default");
1618+ }
1619+}
1620
1621=== added file 'src/Services/Network.vala'
1622--- src/Services/Network.vala 1970-01-01 00:00:00 +0000
1623+++ src/Services/Network.vala 2013-06-28 19:09:26 +0000
1624@@ -0,0 +1,103 @@
1625+/***
1626+ Copyright (C) 2013 Cable Developers
1627+
1628+ This program or library is free software; you can redistribute it
1629+ and/or modify it under the terms of the GNU Lesser General Public
1630+ License as published by the Free Software Foundation; either
1631+ version 3 of the License, or (at your option) any later version.
1632+
1633+ This library is distributed in the hope that it will be useful,
1634+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1635+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1636+ Lesser General Public License for more details.
1637+
1638+ You should have received a copy of the GNU Lesser General
1639+ Public License along with this library; if not, write to the
1640+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1641+ Boston, MA 02110-1301 USA.
1642+***/
1643+
1644+/**
1645+ * This class represents a network. All used networks must be contained in Settings.networks,
1646+ * changes to this class will emit the Settings.networks.changed () signal.
1647+ */
1648+
1649+public class Cable.Settings.Network : GLib.Object {
1650+
1651+ /**
1652+ * The address of the network, i.e., "irc.freenode.net"
1653+ */
1654+ public string address { get; construct set; }
1655+
1656+ /**
1657+ * A name to display to the user when selecting a network for instance.
1658+ */
1659+ public string name { get; construct set; }
1660+
1661+ /**
1662+ * Password, defaults to "" if it isn't required.
1663+ */
1664+ public string password { get; construct set; }
1665+
1666+ /**
1667+ * Array of all networks. Checked for duplicates.
1668+ */
1669+ public static Utils.Array <Network> all { get; private set; }
1670+
1671+
1672+ public Network (string address, string? name = null, string? password = null)
1673+ requires (address.split (".").length == 3) {
1674+
1675+ this.address = address;
1676+ this.name = name ?? address.split (".")[1];
1677+ this.password = password ?? "";
1678+
1679+ this.all.add (this);
1680+ this.notify.connect (() => Settings.networks.changed ());
1681+ }
1682+
1683+ ~Network () {
1684+ this.all.remove (this);
1685+ }
1686+
1687+ public static void init () {
1688+ if (all != null)
1689+ return;
1690+
1691+ all = new Utils.Array <Network> ();
1692+
1693+ foreach (var network in settings.get_strv ("networks")) {
1694+ var values = network.split (":");
1695+
1696+ if (values.length != 3) {
1697+ warning ("Invalid network settings");
1698+ continue;
1699+ }
1700+
1701+ new Settings.Network (values[0], values[1], values[2]);
1702+ }
1703+
1704+ networks.changed.connect (() => {
1705+ string[] networks = {};
1706+
1707+ foreach (var network in all)
1708+ networks += string.join (":", network.address, network.name, network.password);
1709+
1710+ settings.set_strv ("networks", networks);
1711+ });
1712+ }
1713+
1714+ /**
1715+ *
1716+ */
1717+ public bool is_duplicate (string address, string? name = null) {
1718+ foreach (var network in all) {
1719+ if (network.address == address)
1720+ return false;
1721+ if (network.name == name)
1722+ return false;
1723+ }
1724+
1725+ return true;
1726+ }
1727+}
1728
1729=== added file 'src/Services/Settings.vala'
1730--- src/Services/Settings.vala 1970-01-01 00:00:00 +0000
1731+++ src/Services/Settings.vala 2013-06-28 19:09:26 +0000
1732@@ -0,0 +1,146 @@
1733+/***
1734+ Copyright (C) 2013 Cable Developers
1735+
1736+ This program or library is free software; you can redistribute it
1737+ and/or modify it under the terms of the GNU Lesser General Public
1738+ License as published by the Free Software Foundation; either
1739+ version 3 of the License, or (at your option) any later version.
1740+
1741+ This library is distributed in the hope that it will be useful,
1742+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1743+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1744+ Lesser General Public License for more details.
1745+
1746+ You should have received a copy of the GNU Lesser General
1747+ Public License along with this library; if not, write to the
1748+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1749+ Boston, MA 02110-1301 USA.
1750+***/
1751+
1752+/**
1753+ * Pseudo static class for dealing with gsettings.
1754+ *
1755+ * How this works:
1756+ *
1757+ * All settings are stored as public and static members of this class.
1758+ * On startup they are read from gsettings. They can be modified in several
1759+ * ways (Through the user interface, through gsettings, by the program
1760+ * itself…). The settings will then emit a "changed" signal, so the change
1761+ * can be immediately propagated to the server, gsettings, the UI and so
1762+ * on.
1763+ */
1764+namespace Cable.Settings {
1765+
1766+ public GLib.Settings settings;
1767+
1768+ public Utils.Array <Network> networks;
1769+ public Utils.Array <Identity> identities;
1770+
1771+ /**
1772+ * Load values from gsettings.
1773+ */
1774+ public static void init () {
1775+ settings = new GLib.Settings ("org.pantheon.cable");
1776+
1777+ Network.init ();
1778+ networks = Network.all;
1779+
1780+ Identity.init ();
1781+ identities = Identity.all;
1782+ }
1783+}
1784+
1785+ /*
1786+class Cable.Settings : GLib.Object {
1787+
1788+ public static Array <Services.Identity> identities;
1789+ public static Array <Services.Network> networks;
1790+
1791+ static string[] _chans;
1792+ public static string[] channels {
1793+ get { return _chans = settings.get_strv ("channels"); }
1794+ set { settings.set_strv ("channels", _chans = value); }
1795+ }
1796+
1797+ private static GLib.Settings settings;
1798+
1799+ public static void init () {
1800+ settings = new GLib.Settings ("org.pantheon.cable");
1801+
1802+ identities = new Array <Services.Identity> ();
1803+ networks = new Array <Services.Network> ();
1804+
1805+ foreach (var id in settings.get_strv ("identities")) {
1806+ var values = id.split (":");
1807+
1808+ if (values.length != 3)
1809+ warning ("Invalid identity settings");
1810+
1811+ identities.add (
1812+ new Services.Identity (values[0], values[1], values[2])
1813+ );
1814+ }
1815+
1816+ identities.changed.connect (() => {
1817+ string[] ids = {};
1818+
1819+ foreach (var id in identities)
1820+ ids += string.join (":", id.nick_name, id.real_name, id.part_message);
1821+
1822+ settings.set_strv ("identities", ids);
1823+ });
1824+
1825+ foreach (var nw in settings.get_strv ("networks")) {
1826+ var values = nw.split (":");
1827+
1828+ if (values.length != 3) {
1829+ warning ("Invalid network settings");
1830+ continue;
1831+ }
1832+
1833+ networks.add (
1834+ new Services.Network (values[0], values[1], values[2])
1835+ );
1836+ }
1837+
1838+ networks.changed.connect (() => {
1839+ string[] nws = {};
1840+
1841+ foreach (var nw in networks)
1842+ nws += string.join (":", nw.address, nw.name, nw.password);
1843+
1844+ settings.set_strv ("networks", nws);
1845+ });
1846+ }
1847+
1848+ private Settings () {
1849+ }
1850+}
1851+
1852+public class Cable.Array <G> : Gee.ArrayList <G> {
1853+
1854+ public signal void changed ();
1855+
1856+ public override bool add (G item) {
1857+ var ret = base.add (item);
1858+ changed ();
1859+ return ret;
1860+ }
1861+
1862+ public override bool remove (G item) {
1863+ var ret = base.remove (item);
1864+ changed ();
1865+ return ret;
1866+ }
1867+
1868+ public override G remove_at (int index) {
1869+ var ret = base.remove_at (index);
1870+ changed ();
1871+ return ret;
1872+ }
1873+
1874+ public override void @set (int index, G item) {
1875+ base.set (index, item);
1876+ changed ();
1877+ }
1878+}*/
1879
1880=== removed file 'src/Settings.vala'
1881--- src/Settings.vala 2013-05-29 00:24:15 +0000
1882+++ src/Settings.vala 1970-01-01 00:00:00 +0000
1883@@ -1,23 +0,0 @@
1884-namespace Cable {
1885-
1886- public class Settings : Granite.Services.Settings {
1887-
1888- public string[] servers { get; set; }
1889- public string nick { get; set; }
1890- public string[] channels { get; set; }
1891- public string real_name { get; set; }
1892- public string login_name { get; set; }
1893-
1894- static Settings? instance;
1895-
1896- Settings () {
1897- base ("org.pantheon.cable");
1898- }
1899-
1900- public static Settings get_default () {
1901- if (instance == null)
1902- instance = new Settings ();
1903- return instance;
1904- }
1905- }
1906-}
1907
1908=== added file 'src/Utils.vala'
1909--- src/Utils.vala 1970-01-01 00:00:00 +0000
1910+++ src/Utils.vala 2013-06-28 19:09:26 +0000
1911@@ -0,0 +1,69 @@
1912+/***
1913+ Copyright (C) 2013 Cable Developers
1914+
1915+ This program or library is free software; you can redistribute it
1916+ and/or modify it under the terms of the GNU Lesser General Public
1917+ License as published by the Free Software Foundation; either
1918+ version 3 of the License, or (at your option) any later version.
1919+
1920+ This library is distributed in the hope that it will be useful,
1921+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1922+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1923+ Lesser General Public License for more details.
1924+
1925+ You should have received a copy of the GNU Lesser General
1926+ Public License along with this library; if not, write to the
1927+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1928+ Boston, MA 02110-1301 USA.
1929+***/
1930+
1931+class Cable.Utils.Label : Gtk.Label {
1932+
1933+ public Label (string text) {
1934+ label = text;
1935+ halign = Gtk.Align.START;
1936+ }
1937+
1938+ public Label.right (string text) {
1939+ label = text;
1940+ halign = Gtk.Align.END;
1941+ valign = Gtk.Align.CENTER;
1942+ }
1943+}
1944+
1945+public class Cable.Utils.Array <G> : Gee.ArrayList <G> {
1946+
1947+ public signal void changed ();
1948+
1949+ public override bool add (G item) {
1950+ var ret = base.add (item);
1951+ changed ();
1952+ return ret;
1953+ }
1954+
1955+ public override bool remove (G item) {
1956+ var ret = base.remove (item);
1957+ changed ();
1958+ return ret;
1959+ }
1960+
1961+ public override G remove_at (int index) {
1962+ var ret = base.remove_at (index);
1963+ changed ();
1964+ return ret;
1965+ }
1966+
1967+ public override void @set (int index, G item) {
1968+ base.set (index, item);
1969+ changed ();
1970+ }
1971+}
1972+
1973+// FIXME
1974+namespace Cable.Utils {
1975+ public void filter (Gtk.Editable editable, string text, string[] needles) {
1976+ foreach (var needle in needles)
1977+ if (needle in text)
1978+ Signal.stop_emission_by_name (editable, "insert-text");
1979+ }
1980+}
1981
1982=== modified file 'src/Widgets/Channel.vala'
1983--- src/Widgets/Channel.vala 2013-05-29 18:15:05 +0000
1984+++ src/Widgets/Channel.vala 2013-06-28 19:09:26 +0000
1985@@ -1,58 +1,112 @@
1986-namespace Cable.Widgets {
1987-
1988- /**
1989- * This class represents a channel and owns the Widgets.Room
1990- * associated to its channel.
1991- */
1992- public class Channel : Granite.Widgets.SourceList.Item {
1993-
1994- /**
1995- * Get the room object.
1996- */
1997- public Room room { get; private set; }
1998-
1999- public Server server {
2000- get { return parent as Server; }
2001- }
2002-
2003- doodleIRC.DoodleIRCServer backend_server;
2004-
2005- // context menu
2006- Gtk.Menu menu;
2007- Gtk.MenuItem leave_menu_item;
2008- Gtk.MenuItem away_menu_item;
2009-
2010- public Channel (string channel, doodleIRC.DoodleIRCServer backend_server) {
2011- this.name = channel;
2012- this.backend_server = backend_server;
2013- this.room = new Room (channel);
2014-
2015- this.menu = new Gtk.Menu ();
2016- this.leave_menu_item = new Gtk.MenuItem.with_label (_("Leave Channel"));
2017- this.away_menu_item = new Gtk.MenuItem.with_label (_("Mark Away"));
2018- menu.append (leave_menu_item);
2019- menu.append (new Gtk.SeparatorMenuItem ());
2020- menu.append (away_menu_item);
2021-
2022- leave_menu_item.activate.connect (() => {
2023- server.leave_channel (name);
2024- });
2025- away_menu_item.activate.connect (() => {
2026- backend_server.toggle_away (_("Away"));
2027- });
2028- }
2029+/***
2030+ Copyright (C) 2013 Cable Developers
2031+
2032+ This program or library is free software; you can redistribute it
2033+ and/or modify it under the terms of the GNU Lesser General Public
2034+ License as published by the Free Software Foundation; either
2035+ version 3 of the License, or (at your option) any later version.
2036+
2037+ This library is distributed in the hope that it will be useful,
2038+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2039+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2040+ Lesser General Public License for more details.
2041+
2042+ You should have received a copy of the GNU Lesser General
2043+ Public License along with this library; if not, write to the
2044+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2045+ Boston, MA 02110-1301 USA.
2046+***/
2047+
2048+/**
2049+ * This class represents a channel and owns the Widgets.Room
2050+ * associated to its channel.
2051+ */
2052+public class Cable.Widgets.Channel : Granite.Widgets.SourceList.Item {
2053+
2054+ /**
2055+ * Get the room object.
2056+ */
2057+ public Room room { get; private set; }
2058+
2059+ /**
2060+ * The server this channel belongs to.
2061+ */
2062+ public Server server {
2063+ get { return parent as Server; }
2064+ }
2065+
2066+ // context menu
2067+ Gtk.Menu menu;
2068+ Gtk.MenuItem leave_menu_item;
2069+ Gtk.MenuItem away_menu_item;
2070+
2071+ public Channel (string channel_name) {
2072+ this.name = channel_name;
2073+ this.room = new Room (channel_name);
2074+
2075+ this.menu = new Gtk.Menu ();
2076+ this.leave_menu_item = new Gtk.MenuItem.with_label (_("Leave Channel"));
2077+ menu.append (leave_menu_item);
2078+ menu.show_all ();
2079
2080- public void list_names (string[] names) {
2081- foreach (var name in names) {
2082- room.add_user (name, 0);
2083- debug ("Listing name: %s", name);
2084+ leave_menu_item.activate.connect (() => {
2085+ server.leave_channel (name);
2086+ });
2087+ }
2088+
2089+ /**
2090+ * Add names to the source list.
2091+ *
2092+ * @prefix names Array of names to add.
2093+ * @prefix prefixes Array of corresponding prefixes.
2094+ */
2095+ public void list_names (string[] names, string[] prefixes) {
2096+ UserType user_type = UserType.REGULAR;
2097+
2098+ for (int i = 0; i < names.length; i++) {
2099+ switch (prefixes[i]) {
2100+ case "@":
2101+ user_type = UserType.OPERATOR;
2102+ break;
2103+ case "+":
2104+ user_type = UserType.VOICED;
2105+ break;
2106+ default:
2107+ user_type = UserType.REGULAR;
2108+ break;
2109 }
2110- }
2111-
2112- public override Gtk.Menu? get_context_menu () {
2113- menu.show_all ();
2114- return menu;
2115- }
2116- }
2117-
2118+
2119+ room.add_user (names[i], user_type, true);
2120+ }
2121+ }
2122+
2123+ /**
2124+ * Tell the room widget that a new user has been added.
2125+ *
2126+ * @param name The user's nickname (including @ or + prefix).
2127+ * @param silent If true, don't display a join message.
2128+ */
2129+ public void add_user (string name, bool silent = false) {
2130+ if (name.has_prefix ("@"))
2131+ room.add_user (name.replace ("@", ""), UserType.OPERATOR, silent);
2132+ else if (name.has_prefix ("+"))
2133+ room.add_user (name.replace ("+", ""), UserType.VOICED, silent);
2134+ else
2135+ room.add_user (name, UserType.REGULAR, silent);
2136+ }
2137+
2138+ /**
2139+ * Remove a user from the sidebar and display a leave message.
2140+ *
2141+ * @param name The users nickname without prefix.
2142+ */
2143+ public void remove_user (string name) {
2144+ room.remove_user (name);
2145+ }
2146+
2147+ public override Gtk.Menu? get_context_menu () {
2148+ if (menu != null && menu.get_attach_widget () != null)
2149+ menu.detach ();
2150+ return menu;
2151+ }
2152 }
2153
2154=== modified file 'src/Widgets/Room.vala'
2155--- src/Widgets/Room.vala 2013-06-10 18:12:26 +0000
2156+++ src/Widgets/Room.vala 2013-06-28 19:09:26 +0000
2157@@ -1,32 +1,213 @@
2158-namespace Cable.Widgets {
2159-
2160- public enum UserType {
2161- OPERATOR,
2162- VOICED,
2163- REGULAR
2164- }
2165-
2166- public enum MessageType {
2167- NORMAL,
2168- ENTER,
2169- LEAVE
2170- }
2171-
2172- /**
2173- * This class represents a chat room, i.e, the topic, the message display,
2174- * a list of users and is associated to a channel.
2175- * This class is always accessed through its related channel.
2176- */
2177- public class Room : Gtk.Box {
2178-
2179- Granite.Widgets.SourceList.ExpandableItem operators;
2180- Granite.Widgets.SourceList.ExpandableItem voiced;
2181- Granite.Widgets.SourceList.ExpandableItem regular;
2182-
2183- Granite.Widgets.SourceList users;
2184- Gtk.TreeView chat;
2185- Gtk.ScrolledWindow left_scrolled;
2186+/***
2187+ Copyright (C) 2013 Cable Developers
2188+
2189+ This program or library is free software; you can redistribute it
2190+ and/or modify it under the terms of the GNU Lesser General Public
2191+ License as published by the Free Software Foundation; either
2192+ version 3 of the License, or (at your option) any later version.
2193+
2194+ This library is distributed in the hope that it will be useful,
2195+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2196+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2197+ Lesser General Public License for more details.
2198+
2199+ You should have received a copy of the GNU Lesser General
2200+ Public License along with this library; if not, write to the
2201+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2202+ Boston, MA 02110-1301 USA.
2203+***/
2204+
2205+public enum Cable.Widgets.UserType {
2206+ OPERATOR,
2207+ VOICED,
2208+ REGULAR
2209+}
2210+
2211+public enum Cable.Widgets.MessageType {
2212+ NORMAL,
2213+ ENTER,
2214+ LEAVE,
2215+ NICK,
2216+ AWAY
2217+}
2218+
2219+/**
2220+ * This class represents a chat room, i.e, the topic, the message display,
2221+ * a list of users and is associated to a channel.
2222+ * This class is always accessed through its related channel.
2223+ */
2224+public class Cable.Widgets.Room : Gtk.Box {
2225+
2226+ Granite.Widgets.SourceList.ExpandableItem operators;
2227+ Granite.Widgets.SourceList.ExpandableItem voiced;
2228+ Granite.Widgets.SourceList.ExpandableItem regular;
2229+
2230+ Granite.Widgets.SourceList users;
2231+ Gtk.TreeView chat;
2232+ Gtk.ScrolledWindow left_scrolled;
2233+
2234+
2235+ Gtk.Menu menu;
2236+ Gtk.MenuItem kick_item;
2237+ Gtk.MenuItem ban_item;
2238+ Gtk.MenuItem ignore_item;
2239+
2240+ public Gtk.InfoBar topic;
2241+ public Gtk.Label topic_name;
2242+
2243+ public signal void send_message (string message);
2244+
2245+ public signal bool kick_user (string nick_name);
2246+ public signal bool ban_user (string nick_name);
2247+ public signal void ignore (string nick_name, bool ignore = true);
2248+
2249+ public Room (string channel) {
2250+
2251+ //var web_view = new WebKit.WebView ();
2252+
2253+ this.orientation = Gtk.Orientation.VERTICAL;
2254+ var paned = new Granite.Widgets.ThinPaned ();
2255+ var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
2256+ users = new Granite.Widgets.SourceList ();
2257+ var entry = new Gtk.Entry ();
2258+ chat = new Gtk.TreeView.with_model (new Gtk.ListStore (2, typeof(string), typeof(string)));
2259+ var topic = new Gtk.InfoBar ();
2260+ topic_name = new Gtk.Label (_("Loading Topic…"));
2261+ topic_name.wrap = true;
2262+ var bottom = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
2263+ left_scrolled = new Gtk.ScrolledWindow (null, null);
2264+ //var user = new Gtk.Button.with_label (Global.get_default ().user_nick);
2265+
2266+ var left = new Gtk.CellRendererText ();
2267+ left.xalign = 1.0f;
2268+ left.width = 90;
2269+ left.font_desc = Pango.FontDescription.from_string (
2270+ new GLib.Settings ("org.gnome.desktop.interface").get_string ("document-font-name"));
2271+
2272+ var right = new Gtk.CellRendererText ();
2273+ right.wrap_mode = Pango.WrapMode.WORD_CHAR;
2274+ right.wrap_width = -1;
2275+ right.font_desc = left.font_desc;
2276+
2277+ chat.enable_grid_lines = Gtk.TreeViewGridLines.VERTICAL;
2278+ chat.headers_visible = false;
2279+ chat.insert_column_with_attributes (-1, null, left, "markup", 0);
2280+ chat.insert_column_with_attributes (-1, null, right, "markup", 1);
2281+ chat.button_press_event.connect (() => true );
2282+
2283+ var css = new Gtk.CssProvider ();
2284+ try {
2285+ css.load_from_data ("* {
2286+ -GtkTreeView-grid-line-pattern: '1';
2287+ }", -1);
2288+ } catch (Error e) { warning (e.message); }
2289+
2290+ chat.get_style_context ().add_provider (css, 40000);
2291+ topic_name.halign = Gtk.Align.FILL;
2292+ topic_name.valign = Gtk.Align.FILL;
2293+
2294+ var content = topic.get_content_area () as Gtk.Container;
2295+ content.add (topic_name);
2296+
2297+ operators = new Granite.Widgets.SourceList.ExpandableItem (_("Operators"));
2298+ regular = new Granite.Widgets.SourceList.ExpandableItem ("Regular");
2299+ voiced = new Granite.Widgets.SourceList.ExpandableItem ("Voiced");
2300+ users.root.add (operators);
2301+ users.root.add (voiced);
2302+ users.root.add (regular);
2303+ users.set_sort_func ((a,b) => {
2304+ return a.name.collate (b.name);
2305+ });
2306+
2307+ operators.expanded = true;
2308+ regular.expanded = true;
2309+ voiced.expanded = true;
2310+
2311+ css = new Gtk.CssProvider ();
2312+ try {
2313+ css.load_from_data ("*{
2314+ background-color: #fff;
2315+ }", -1);
2316+ } catch (Error e) { warning (e.message); }
2317+ users.get_style_context ().add_provider (css, 40000);
2318+
2319+ users.hscrollbar_policy = Gtk.PolicyType.NEVER;
2320+ users.width_request = 150;
2321+
2322+
2323+ paned.pack1 (box, true, false);
2324+ paned.pack2 (users, false, false);
2325+
2326+ /*user.width_request = 99;
2327+ user.margin_right = 5;
2328+ user.xalign = 1.0f;*/
2329+
2330+
2331+ css = new Gtk.CssProvider ();
2332+ try {
2333+ css.load_from_data ("*{
2334+ background-image: none;
2335+ background-color: transparent;
2336+ -unico-inner-stroke-width: 0px;
2337+ -unico-outer-stroke-width: 0px;
2338+ border-left: 1px solid #666;
2339+ border-width: 0px 0px 0px 1px;
2340+ }
2341+ *:active, *:prelight {
2342+ border-color: #666;
2343+ }", -1);
2344+ } catch (Error e) { warning (e.message); }
2345+ entry.get_style_context ().add_provider (css, 40000);
2346+
2347+ //bottom.pack_start (user, false);
2348+ bottom.pack_start (entry);
2349+
2350+ left_scrolled.add (chat);
2351+
2352+ box.pack_start (topic, false);
2353+ box.pack_start (left_scrolled);
2354+ //box.pack_start (bottom, false);
2355+
2356+ this.pack_start (paned);
2357+
2358+ /*user.clicked.connect (() => {
2359+
2360+ var settings_dialog = new Widgets.SettingsDialog ();
2361+
2362+ settings_dialog.show_all ();
2363+ //settings_dialog.run ();
2364+
2365+ });*/
2366+
2367+ entry.activate.connect (() => {
2368+ send_message (entry.text);
2369+ entry.text = "";
2370+ });
2371+
2372+ bottom.draw.connect ((cr) => {
2373+ var grad = new Cairo.Pattern.linear (0, 0, 0, bottom.get_allocated_height () - 4);
2374+ grad.add_color_stop_rgb (0.0, 0.9, 0.9, 0.9);
2375+ grad.add_color_stop_rgb (1.0, 1.0, 1.0, 1.0);
2376+ cr.rectangle (0, 0, bottom.get_allocated_width (), bottom.get_allocated_height ());
2377+ cr.set_source (grad);
2378+ cr.fill ();
2379+
2380+ cr.move_to (0, 0);
2381+ cr.line_to (this.get_allocated_width (), 0);
2382+ cr.close_path ();
2383+ cr.set_source_rgba (0.1, 0.1, 0.1, 1.0);
2384+ cr.set_line_width (1);
2385+ cr.stroke ();
2386+
2387+ return false;
2388+ });
2389+ }
2390+
2391+ public void rename_user (string old_name, string new_name, UserType type, bool silent = false) {
2392+ remove_user (old_name, true);
2393+ add_user (new_name, type, true);
2394
2395+<<<<<<< TREE
2396 public Gtk.InfoBar topic;
2397 public Gtk.Label topic_name;
2398
2399@@ -175,49 +356,81 @@
2400 else
2401 regular.add (new Granite.Widgets.SourceList.Item (name));
2402
2403+=======
2404+ if (!silent)
2405+ message (new_name, "", MessageType.NICK);
2406+ }
2407+
2408+ public void add_user (string name, UserType type, bool silent = false) {
2409+ var user = new Granite.Widgets.SourceList.Item (name);
2410+ user.selectable = false;
2411+
2412+ if (type == UserType.OPERATOR)
2413+ operators.add (user);
2414+ else if (type == UserType.VOICED)
2415+ voiced.add (user);
2416+ else
2417+ regular.add (user);
2418+
2419+ if (!silent)
2420+>>>>>>> MERGE-SOURCE
2421 message (name, "", MessageType.ENTER);
2422- }
2423-
2424- public void remove_user (string name) {
2425- Granite.Widgets.SourceList.ExpandableItem[] lists = {voiced, operators, regular};
2426- foreach (var list in lists) {
2427- foreach (var child in list.children) {
2428- if (child.name == name) {
2429- list.remove (child);
2430-
2431+
2432+ regular.name = _("Regular") + " (" + regular.n_children.to_string () + ")";
2433+ operators.name = _("Operators") + " (" + operators.n_children.to_string () + ")";
2434+ voiced.name = _("Voiced") + " (" + voiced.n_children.to_string () + ")";
2435+ }
2436+
2437+ public void remove_user (string name, bool silent = false) {
2438+ Granite.Widgets.SourceList.ExpandableItem[] lists = {voiced, operators, regular};
2439+ foreach (var list in lists) {
2440+ foreach (var child in list.children) {
2441+ if (child.name == name) {
2442+ list.remove (child);
2443+
2444+ if (!silent)
2445 message (child.name, "", MessageType.LEAVE);
2446-
2447- return;
2448- }
2449-
2450+
2451+ regular.name = _("Regular") + " (" + regular.n_children.to_string () + ")";
2452+ operators.name = _("Operators") + " (" + operators.n_children.to_string () + ")";
2453+ voiced.name = _("Voiced") + " (" + voiced.n_children.to_string () + ")";
2454+
2455 return;
2456 }
2457 }
2458 }
2459-
2460- public void message (owned string from, string message, MessageType type=MessageType.NORMAL) {
2461- bool do_scroll = left_scrolled.vadjustment.value + 10 > left_scrolled.vadjustment.upper;
2462-
2463- Gtk.TreeIter iter;
2464- (chat.model as Gtk.ListStore).append (out iter);
2465-
2466- if (type == MessageType.NORMAL) {
2467-
2468- if (from == Global.get_default ().user_nick)
2469- from = "<span color='#999'>"+from+"</span>";
2470- else if (message.index_of (Global.get_default ().user_nick) != -1)
2471- from = "<span color='#a00'>"+from+"</span>";
2472-
2473- (chat.model as Gtk.ListStore).set (iter, 0, from, 1, message);
2474- } else
2475- (chat.model as Gtk.ListStore).set (iter, 0, "",
2476- 1, "<span color='#999'>%s has %s the room.</span>".printf (from, type == MessageType.ENTER ? "entered" : "left"));
2477-
2478- Timeout.add (10, () => {
2479+
2480+ }
2481+
2482+ public void message (owned string from, string message, MessageType type = MessageType.NORMAL) {
2483+ bool do_scroll = left_scrolled.vadjustment.value + 10 > left_scrolled.vadjustment.upper;
2484+
2485+ Gtk.TreeIter iter;
2486+ var model = chat.model as Gtk.ListStore;
2487+ model.append (out iter);
2488+
2489+ switch (type) {
2490+ case MessageType.NORMAL:
2491+ model.set (iter, 0, from, 1, message);
2492+ break;
2493+ case MessageType.ENTER:
2494+ model.set (iter, 0, "", 1, @"<span color='#9a9'>$from joined</span>");
2495+ break;
2496+ case MessageType.LEAVE:
2497+ model.set (iter, 0, "", 1, @"<span color='#a99'>$from left</span>");
2498+ break;
2499+ case MessageType.AWAY:
2500+ model.set (iter, 0, "", 1, @"<span color='#999'>$from is away</span>");
2501+ break;
2502+ case MessageType.NICK:
2503+ model.set (iter, 0, "", 1, @"<span color='#999'>$from</span>");
2504+ break;
2505+ }
2506+
2507+ Timeout.add (1, () => {
2508 if (do_scroll)
2509 left_scrolled.vadjustment.value = left_scrolled.vadjustment.upper;
2510 return false;
2511- });
2512- }
2513+ });
2514 }
2515 }
2516
2517=== modified file 'src/Widgets/Server.vala'
2518--- src/Widgets/Server.vala 2013-06-06 21:07:29 +0000
2519+++ src/Widgets/Server.vala 2013-06-28 19:09:26 +0000
2520@@ -1,233 +1,384 @@
2521-namespace Cable.Widgets {
2522-
2523- public class Server : Granite.Widgets.SourceList.ExpandableItem {
2524-
2525- //some default servers
2526- public static const string [] DEFAULT_SERVERS = {
2527- "Freenode", "irc.freenode.net",
2528- "GimpNET", "irc.gimp.org"
2529- };
2530-
2531- /**
2532- * List of all channels of this Server.
2533- */
2534- GLib.List <Channel> _channels = null;
2535- public GLib.List <Channel> channels {
2536- get {
2537- _channels = new GLib.List <Channel> ();
2538- foreach (var child in children)
2539- _channels.append (child as Channel);
2540- return _channels;
2541- }
2542- }
2543-
2544- doodleIRC.DoodleIRCServer backend_server;
2545-
2546- public string uri;
2547-
2548-
2549- public signal void left_channel (Channel channel);
2550- public signal void joined_channel (Channel channel);
2551-
2552- /**
2553- * Create and join server.
2554- */
2555- public Server (string _name, string _uri) {
2556- var settings = Settings.get_default ();
2557- name = _name;
2558- uri = _uri;
2559-
2560- doodleIRC.User user = doodleIRC.User () {
2561- realname = settings.real_name,
2562- hostname = settings.nick,
2563- username = settings.nick,
2564- servername = uri
2565- };
2566-
2567- backend_server = new doodleIRC.DoodleIRCServer ("irc.freenode.net", user, settings.nick);
2568- Global.get_default ().user_nick = settings.nick; //TODO use fallback nicks
2569-
2570- try {
2571- backend_server.connect ();
2572- } catch (Error e) {
2573- //Needs Fixing
2574- Gtk.main_quit ();
2575- }
2576-
2577- backend_server.on_message.connect ((sender, chan, msg) => {
2578- channels.foreach ((channel) => {
2579- if (channel.name == chan) {
2580- channel.room.message (sender, msg);
2581- return;
2582- }
2583- });
2584-
2585- critical ("Channel '%s' has not been opened", chan);
2586- });
2587-
2588- backend_server.on_names_listed.connect ((chan, names) => {
2589- channels.foreach ((channel) => {
2590- if (channel.name == chan)
2591- channel.list_names (names);
2592- });
2593- });
2594- }
2595-
2596- /**
2597- * Retrieve a channel by its name
2598- */
2599- public Channel? get_channel_by_name (string channel_name) {
2600+/***
2601+ Copyright (C) 2013 Cable Developers
2602+
2603+ This program or library is free software; you can redistribute it
2604+ and/or modify it under the terms of the GNU Lesser General Public
2605+ License as published by the Free Software Foundation; either
2606+ version 3 of the License, or (at your option) any later version.
2607+
2608+ This library is distributed in the hope that it will be useful,
2609+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2610+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2611+ Lesser General Public License for more details.
2612+
2613+ You should have received a copy of the GNU Lesser General
2614+ Public License along with this library; if not, write to the
2615+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
2616+ Boston, MA 02110-1301 USA.
2617+***/
2618+
2619+public class Cable.Widgets.Server : Granite.Widgets.SourceList.ExpandableItem {
2620+
2621+ /**
2622+ * List of all channels of this Server.
2623+ */
2624+ Gee.ArrayList <Channel> _channels = null;
2625+ public Gee.ArrayList <Channel> channels {
2626+ get {
2627+ _channels = new Gee.ArrayList <Channel> ();
2628+ foreach (var child in children)
2629+ _channels.add (child as Channel);
2630+ return _channels;
2631+ }
2632+ }
2633+
2634+ /**
2635+ * Information about the network we are connected to.
2636+ */
2637+ public Settings.Network network { get; private set; }
2638+
2639+ /**
2640+ * Information about the identity we are using for this connection.
2641+ */
2642+ public Settings.Identity identity { get; private set; }
2643+
2644+ Services.Client client = null;
2645+ string server_id;
2646+ bool away;
2647+ bool connected = false;
2648+ string to_join;
2649+ // menu
2650+ Gtk.Menu menu;
2651+ Gtk.MenuItem away_menu_item;
2652+ Gtk.MenuItem part_menu_item;
2653+
2654+ /**
2655+ * Emitted when the server emits a PART message for us.
2656+ *
2657+ * @param channel Channel that has been parted.
2658+ */
2659+ public signal void left_channel (Channel channel);
2660+
2661+ /**
2662+ * Emitted when a server confirms that we have joined successfully.
2663+ *
2664+ * @param channel Channel that has been joined.
2665+ */
2666+ public signal void joined_channel (Channel channel);
2667+
2668+ /**
2669+ * Create and connect to a server.
2670+ */
2671+ public Server (Settings.Network network, Settings.Identity identity) {
2672+
2673+ this.network = network;
2674+ this.identity = identity;
2675+ this.name = network.name;
2676+ this.server_id = string.join (":", network.address, identity.nick_name);
2677+
2678+ try {
2679+ client = GLib.Bus.get_proxy_sync (
2680+ GLib.BusType.SESSION, "de.ikkoku.sushi", "/de/ikkoku/sushi"
2681+ );
2682+ } catch (IOError e) {
2683+ print (e.message);
2684+ return;
2685+ }
2686+
2687+ debug ("Successfully connected to Sushi dbus session.\n");
2688+
2689+ setup_callbacks ();
2690+ setup_contextmenu ();
2691+ setup_settings_callbacks ();
2692+
2693+ foreach (var server in client.servers ()) {
2694+ if (client.server_get (server, "server", "nick") == identity.nick_name &&
2695+ client.server_get (server, "server", "address") == network.address) {
2696+
2697+ debug (@"Already connected to $server.");
2698+ connected = true;
2699+ this.server_id = server;
2700+
2701+ return;
2702+ }
2703+ }
2704+
2705+ try {
2706+ debug (@"Creating new server $server_id.");
2707+ client.server_set (server_id, "server", "address", network.address);
2708+ client.server_set (server_id, "server", "nickserv", network.password);
2709+ client.server_set (server_id, "server", "nick", identity.nick_name);
2710+ client.server_set (server_id, "server", "name", identity.real_name);
2711+ client.server_set (server_id, "server", "autoconnect", "true");
2712+ client.connect (server_id);
2713+ } catch (GLib.IOError e) {
2714+ print (e.message);
2715+ return;
2716+ }
2717+
2718+ debug ("Successfully set up server.\n");
2719+ }
2720+
2721+ public override Gtk.Menu? get_context_menu () {
2722+ if (menu != null && menu.get_attach_widget () != null)
2723+ menu.detach ();
2724+ return menu;
2725+ }
2726+
2727+ /**
2728+ * Create the context menu shown when right clicking a server entry.
2729+ */
2730+ private void setup_contextmenu () {
2731+ this.menu = new Gtk.Menu ();
2732+
2733+ this.away_menu_item = new Gtk.MenuItem.with_label (_("Mark Away"));
2734+ this.part_menu_item = new Gtk.MenuItem.with_label (_("Leave all channels"));
2735+
2736+ menu.append (away_menu_item);
2737+ menu.append (part_menu_item);
2738+
2739+ away_menu_item.activate.connect (() => {
2740+ if (!away) {
2741+ client.away (server_id, _("%s is away.").printf (identity.real_name));
2742+ away_menu_item.label = _("Mark Present");
2743+ } else {
2744+ client.away (server_id, _(""));
2745+ away_menu_item.label = _("Mark Away");
2746+ }
2747+ });
2748+
2749+ part_menu_item.activate.connect (() => {
2750 foreach (var channel in channels)
2751- if (channel.name == channel_name)
2752- return channel;
2753-
2754- return (Channel) null;
2755- }
2756-
2757- /**
2758- * Join a channel and return the Widget.Channel object
2759- */
2760- public Channel? join_channel (string channel_name) {
2761- var channel = new Channel (channel_name, backend_server);
2762-
2763- channel.room.send_message.connect ((msg) => {
2764- backend_server.write (channel_name, msg);
2765- });
2766-
2767- backend_server.join_chan (channel_name);
2768- backend_server.get_topic (channel_name, (channel_name, topic) => {
2769- print ("Topic :%s\n".printf (topic));
2770- // Set topic
2771- channel.room.topic_name.label = topic;
2772-
2773- // Now check for links TODO async this
2774- /*string parsed_topic = topic;
2775- bool done = false;
2776- int i = 0, start = 0, end = 0, p = 0, counter = 0;
2777- Array<string> links = new Array<string> ();
2778- start = topic.index_of ( "http", i);
2779- while(!done) {
2780- start = topic.index_of ( "http", start);
2781- if ( start == -1) {
2782- // No link
2783- done = true;
2784- } else {
2785- // Contains links
2786- end = topic.index_of ( " ", start);
2787- if ( end == -1) {
2788- // End of topic
2789- end = topic.length;
2790- done = true;
2791- }
2792- print ("URL :%s\n".printf (topic.slice ((long) start, (long) end)));
2793- links.insert_val ( (uint) p, topic.slice ((long) start, (long) end));
2794- print ("URL in Array :%s\n".printf (links.index(p)));
2795- p++;
2796- start = end;
2797- }
2798+ leave_channel (channel.name);
2799+ });
2800+
2801+ menu.show_all ();
2802+ }
2803+
2804+ /**
2805+ * Callbacks for the possible server replies.
2806+ */
2807+ private void setup_callbacks () {
2808+
2809+ // connected
2810+ client.event_connected.connect ((time, server) => {
2811+ debug (@"Connected to $server");
2812+ connected = true;
2813+ if (to_join != null)
2814+ join_channel (to_join);
2815+ });
2816+
2817+ // join
2818+ client.event_join.connect ((time, server, from, chan) => {
2819+
2820+ var channel = get_channel_if_valid (server, chan);
2821+
2822+ if (channel == null)
2823+ return;
2824+
2825+ var nick = from.split ("!")[0];
2826+
2827+ if (nick == identity.nick_name) {
2828+ debug (@"Joined $chan on $(network.address) as $(identity.nick_name)");
2829+ setup_channel_callbacks (channel);
2830+ } else {
2831+ channel.add_user (nick);
2832+ }
2833+ });
2834+
2835+ // no such channel
2836+ client.event_no_such.connect ((time, server, target, type) => {
2837+ var channel = get_channel_if_valid (server, target);
2838+
2839+ if (channel == null)
2840+ return;
2841+
2842+ warning ("No such channel '%s'.", channel.name);
2843+ remove (channel);
2844+ left_channel (channel); //signal
2845+ });
2846+
2847+ // topic
2848+ client.event_topic.connect ((time, server, from, chan, topic) => {
2849+ var channel = get_channel_if_valid (server, chan);
2850+
2851+ if (channel == null)
2852+ return;
2853+
2854+ channel.room.topic_name.label = topic;
2855+ });
2856+
2857+
2858+
2859+ // names
2860+ client.event_names.connect ((time, server, chan, nicks, prefixes) => {
2861+ var channel = get_channel_if_valid (server, chan);
2862+
2863+ if (channel == null)
2864+ return;
2865+
2866+ channel.list_names (nicks, prefixes);
2867+ });
2868+
2869+ // part
2870+ client.event_part.connect ((time, server, from, chan, message) => {
2871+ var channel = get_channel_if_valid (server, chan);
2872+
2873+ if (channel == null)
2874+ return;
2875+
2876+ debug (@"Parted from $chan on $(network.address) as $(identity.nick_name)");
2877+
2878+ var nick = from.split ("!")[0];
2879+
2880+ if (nick == identity.nick_name) {
2881+ remove (channel);
2882+ left_channel (channel); //signal
2883+ } else {
2884+ channel.remove_user (nick);
2885+ }
2886+ });
2887+
2888+ // message
2889+ client.event_message.connect ((time, server, from, target, message) => {
2890+ var channel = get_channel_if_valid (server, target);
2891+
2892+ if (channel == null)
2893+ return;
2894+
2895+ var nick = from.split ("!")[0];
2896+
2897+ channel.room.message (nick, message);
2898+ });
2899+
2900+ // away
2901+ client.event_user_away.connect ((time, server, from, away) => {
2902+ if (server != this.server_id)
2903+ return;
2904+
2905+ var nick = from.split ("!")[0];
2906+
2907+ debug (@"AWAY $server $nick $away");
2908+
2909+ if (nick == identity.nick_name)
2910+ this.away = away;
2911+ });
2912+
2913+ // nick
2914+ client.event_nick.connect ((time, server, from, new_nick) => {
2915+ if (server != this.server_id)
2916+ return;
2917+
2918+ if (identity.nick_name != new_nick)
2919+ identity.nick_name = new_nick;
2920+
2921+ client.server_set (server_id, "server", "nick", identity.nick_name);
2922+ });
2923+ }
2924+
2925+ /**
2926+ * Callbacks for GUI signals.
2927+ */
2928+ private void setup_channel_callbacks (Channel channel) {
2929+ channel.room.send_message.connect ((text) => {
2930+ if (text[0] == '/'){}
2931+ //TODO client.raw (this.server_id, text.replace ("/", ""));
2932+ else
2933+ client.message (this.server_id, channel.name, text);
2934+ });
2935+ }
2936+
2937+ private void setup_settings_callbacks () {
2938+ identity.notify["nick-name"].connect (() => {
2939+ debug ("Sending nick request %s", identity.nick_name);
2940+ client.nick (this.server_id, identity.nick_name);
2941+ });
2942+ }
2943+
2944+ private Channel get_channel_if_valid (string server, string chan) {
2945+ if (server != this.server_id)
2946+ return (Channel) null;
2947+
2948+ var channel = get_channel_by_name (chan);
2949+
2950+ if (channel == null)
2951+ critical ("Channel '%s' has not been opened", chan);
2952+
2953+ return channel;
2954+ }
2955+
2956+ public void send_message (Channel channel, string message) {
2957+ client.message (this.server_id, channel.name, message);
2958+ }
2959+
2960+ /**
2961+ * Retrieve a channel by its name.
2962+ *
2963+ * @param channel_name Name of the channel you are looking for.
2964+ */
2965+ public Channel? get_channel_by_name (string channel_name) {
2966+ foreach (var channel in channels)
2967+ if (channel.name == channel_name)
2968+ return channel;
2969+
2970+ return (Channel) null;
2971+ }
2972+
2973+ public bool channel_is_joined (string channel_name) {
2974+ foreach (var channel in channels)
2975+ if (channel.name == channel_name)
2976+ return true;
2977+
2978+ return false;
2979+ }
2980+
2981+ /**
2982+ * Join a channel and return the Widget.Channel object.
2983+ *
2984+ * @param channel_name Name of the channel to be joined.
2985+ * @returns The created channel.
2986+ */
2987+ public Channel? join_channel (string channel_name) {
2988+ if (connected == false) {
2989+
2990+ client.event_connected.connect ((time, server) => {
2991+ if (server == this.server_id) {
2992+ connected = true;
2993+ join_channel (channel_name);
2994 }
2995-
2996- for (counter = 0; counter < p; counter++) {
2997- string parsed = "<a href=\"" + links.index(counter) + "\">" + links.index(counter) + "</a>";
2998- print ("Link :%s\n".printf (links.index(counter)));
2999- print ("Parsed Link :%s\n".printf (parsed));
3000- parsed_topic = parsed_topic.replace (links.index(counter), parsed);
3001- }
3002-
3003- channel.room.topic_name.set_use_markup (true);
3004- print ("Parsed Topic :%s\n".printf (parsed_topic));
3005- channel.room.topic_name.label = parsed_topic;*/
3006- });
3007-
3008- this.add (channel);
3009-
3010- joined_channel (channel); //signal
3011-
3012- return channel;
3013- }
3014-
3015- /**
3016- * Leave a channel.
3017- */
3018- public void leave_channel (string channel_name) {
3019- var channel = get_channel_by_name (channel_name);
3020- backend_server.leave_chan (channel_name);
3021- remove (channel);
3022- left_channel (channel); // signal
3023- }
3024-
3025- public void quit () {
3026- backend_server.quit_server ("Quitting:");
3027- }
3028-
3029- //builds up a ComboBox offering some default and your custom servers
3030- /*modified by Xylon*/
3031- public static Gtk.ComboBoxText get_server_list () {
3032- var box = new Gtk.ComboBoxText.with_entry ();
3033-
3034- //add the default ones
3035- for (var i = 0; i < DEFAULT_SERVERS.length; i += 2) {
3036- box.append (DEFAULT_SERVERS[i + 1], DEFAULT_SERVERS[i]);
3037- }
3038-
3039- //add the custom ones
3040- foreach (var server in Settings.get_default ().servers) {
3041- if (server == "")
3042- continue;
3043-
3044- var details = server.split (":");
3045- box.append (details[1], details[0]);
3046- }
3047-
3048- box.active = 0;
3049-
3050- return box;
3051- }
3052-
3053- public static Gtk.Dialog get_add_dialog ()
3054- {
3055- var dialog = new Gtk.Dialog.with_buttons (_("Add Server"), null, Gtk.DialogFlags.MODAL);
3056- var grid = new Gtk.Grid ();
3057- var servernamelabel = new Gtk.Label (_("Server Name:"));
3058- var serverurllabel = new Gtk.Label (_("Server URL:"));
3059- var name = new Gtk.Entry ();
3060- var url = new Gtk.Entry ();
3061- var add = new Gtk.Button.with_label (_("Add Server"));
3062-
3063- name.placeholder_text = "Server";
3064- url.placeholder_text = "irc.server.net";
3065- grid.margin = 12;
3066- grid.column_spacing = 6;
3067- grid.row_spacing = 6;
3068-
3069- grid.attach (servernamelabel, 0, 0, 1, 1);
3070- servernamelabel.set_alignment ( 1, 0.5f);
3071- grid.attach (name, 1, 0, 1, 1);
3072- grid.attach (serverurllabel, 0, 1, 1, 1);
3073- serverurllabel.set_alignment ( 1, 0.5f);
3074- grid.attach (url, 1, 1, 1, 1);
3075- grid.attach (add, 1, 2, 1, 1);
3076-
3077- url.activate.connect (() => add.clicked ());
3078-
3079- add.clicked.connect (() => {
3080- var servers = Settings.get_default ().servers;
3081- servers.resize (servers.length + 1);
3082- servers[servers.length - 1] = name.text + ":" + url.text;
3083- Settings.get_default ().servers = servers;
3084-
3085- dialog.destroy ();
3086- });
3087-
3088- name.changed.connect (() => add.sensitive = name.text != "" && url.text != "");
3089- url.changed.connect (() => add.sensitive = name.text != "" && url.text != "");
3090-
3091- add.sensitive = false;
3092-
3093- (dialog.get_content_area () as Gtk.Container).add (grid);
3094- dialog.title = _("Add Server");
3095-
3096- return dialog;
3097- }
3098+ });
3099+
3100+ return (Channel) null;
3101+ }
3102+
3103+ if (channel_is_joined (channel_name)) {
3104+ warning (@"Channel '$channel_name' already joined.");
3105+ return (Channel) null;
3106+ }
3107+
3108+ var channel = new Channel (channel_name);
3109+ this.add (channel);
3110+
3111+ client.join (this.server_id, channel_name, "");
3112+ joined_channel (channel); //signal
3113+
3114+ return channel;
3115+ }
3116+
3117+ /**
3118+ * Send PART message to server.
3119+ *
3120+ * @param channel_name Name of the channel you want to leave.
3121+ */
3122+ public void leave_channel (string channel_name) {
3123+ var channel = get_channel_by_name (channel_name);
3124+ client.part (this.server_id, channel_name, identity.part_message);
3125+ }
3126+
3127+ /**
3128+ * Quit the server.
3129+ */
3130+ public void quit () {
3131+ client.quit (this.server_id, "Quit.");
3132 }
3133 }
3134
3135=== modified file 'src/Widgets/ServerList.vala'
3136--- src/Widgets/ServerList.vala 2013-05-29 18:15:05 +0000
3137+++ src/Widgets/ServerList.vala 2013-06-28 19:09:26 +0000
3138@@ -1,77 +1,104 @@
3139-namespace Cable.Widgets {
3140-
3141- /**
3142- * This class stores all servers (Widget.Server) of the current window in
3143- * a Granite.Widgets.SourceList.
3144- */
3145- public class ServerList : Granite.Widgets.SourceList {
3146-
3147- /**
3148- * List of all servers in the ServerList.
3149- */
3150- GLib.List <Server> _servers = null;
3151- public GLib.List <Server> servers {
3152- get {
3153- _servers = new GLib.List <Server> ();
3154- foreach (var child in root.children)
3155- _servers.append (child as Server);
3156- return _servers;
3157- }
3158- }
3159-
3160- /**
3161- * Get the server of the currently selected channel.
3162- */
3163- public Server? current_server {
3164- get { return selected.parent as Server; }
3165- }
3166-
3167- /**
3168- * Get the currently selected channel.
3169- */
3170- public Channel? current_channel {
3171- get { return selected as Channel; }
3172- }
3173-
3174- /**
3175- * Get the currently selected channel's room.
3176- */
3177- public Room? current_room {
3178- get { return current_channel.room as Room; }
3179- }
3180-
3181- public ServerList () {
3182- }
3183-
3184- public Server? get_server_by_URI (string URI) {
3185- foreach (var server in servers)
3186- if (server.uri == URI)
3187- return server;
3188-
3189- return (Server) null;
3190- }
3191-
3192- /**
3193- * Amount of opened servers.
3194- */
3195- public uint get_n_servers () {
3196- return get_n_visible_children (root);
3197- }
3198-
3199- /**
3200- * Removes and quits a server from the List.
3201- */
3202- public void remove_server (Server server) {
3203- server.quit ();
3204- root.remove (server);
3205- }
3206-
3207- /**
3208- * Add and connect to server.
3209- */
3210- public void add_server (Server server) {
3211- root.add (server);
3212- }
3213- }
3214-
3215+/***
3216+ Copyright (C) 2013 Cable Developers
3217+
3218+ This program or library is free software; you can redistribute it
3219+ and/or modify it under the terms of the GNU Lesser General Public
3220+ License as published by the Free Software Foundation; either
3221+ version 3 of the License, or (at your option) any later version.
3222+
3223+ This library is distributed in the hope that it will be useful,
3224+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3225+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3226+ Lesser General Public License for more details.
3227+
3228+ You should have received a copy of the GNU Lesser General
3229+ Public License along with this library; if not, write to the
3230+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
3231+ Boston, MA 02110-1301 USA.
3232+***/
3233+
3234+/**
3235+ * This class stores all servers (Widget.Server) of the current window in
3236+ * a Granite.Widgets.SourceList.
3237+ */
3238+public class Cable.Widgets.ServerList : Granite.Widgets.SourceList {
3239+
3240+ /**
3241+ * List of all servers in the ServerList.
3242+ */
3243+ Gee.ArrayList <Server> _servers = null;
3244+ public Gee.ArrayList <Server> servers {
3245+ get {
3246+ _servers = new Gee.ArrayList <Server> ();
3247+ foreach (var child in root.children)
3248+ _servers.add (child as Server);
3249+ return _servers;
3250+ }
3251+ }
3252+
3253+ /**
3254+ * Get the server of the currently selected channel.
3255+ */
3256+ public Server? current_server {
3257+ get { return selected.parent as Server; }
3258+ }
3259+
3260+ /**
3261+ * Get the currently selected channel.
3262+ */
3263+ public Channel? current_channel {
3264+ get { return selected as Channel; }
3265+ }
3266+
3267+ /**
3268+ * Get the currently selected channel's room.
3269+ */
3270+ public Room? current_room {
3271+ get { return current_channel.room as Room; }
3272+ }
3273+
3274+ /**
3275+ * Amount of opened servers.
3276+ */
3277+ /*public uint n_servers {
3278+ get { return get_n_visible_children (root); }
3279+ }*/
3280+
3281+ public ServerList () {
3282+ width_request = 150;
3283+ }
3284+
3285+ /**
3286+ * Returns Server object from server URI or null
3287+ */
3288+ public Server? get_server (string URI, string nick) {
3289+ foreach (var server in servers)
3290+ if (server.network.address == URI &&
3291+ server.identity.nick_name == nick)
3292+ return server;
3293+
3294+ return (Server) null;
3295+ }
3296+
3297+ /**
3298+ * Amount of opened servers.
3299+ */
3300+ public uint get_n_servers () {
3301+ return get_n_visible_children (root);
3302+ }
3303+
3304+ /**
3305+ * Removes and quits a server from the List.
3306+ */
3307+ public void remove_server (Server server) {
3308+ server.quit ();
3309+ root.remove (server);
3310+ }
3311+
3312+ /**
3313+ * Add server.
3314+ */
3315+ public void add_server (Server server) {
3316+ root.add (server);
3317+ }
3318 }
3319
3320=== removed file 'src/Widgets/SettingsDialog.vala'
3321--- src/Widgets/SettingsDialog.vala 2013-06-06 21:07:29 +0000
3322+++ src/Widgets/SettingsDialog.vala 1970-01-01 00:00:00 +0000
3323@@ -1,65 +0,0 @@
3324-
3325-namespace Cable.Widgets {
3326-
3327- class LLabel : Gtk.Label {
3328-
3329- public LLabel (string text) {
3330- label = text;
3331- halign = Gtk.Align.START;
3332- }
3333-
3334- public LLabel.right (string text) {
3335- label = text;
3336- halign = Gtk.Align.END;
3337- }
3338- }
3339-
3340- Gtk.Entry nick;
3341- Gtk.Entry realname;
3342- Gtk.Button done;
3343-
3344- public class SettingsDialog : Gtk.Dialog {
3345-
3346- public SettingsDialog () {
3347- var main = new Gtk.Grid ();
3348- main.margin = 12;
3349- main.column_spacing = 6;
3350- main.row_spacing = 6;
3351-
3352- nick = new Gtk.Entry ();
3353- realname = new Gtk.Entry ();
3354-
3355- done = new Gtk.Button.with_label (_("Done"));
3356-
3357- main.attach (new LLabel.right (_("Nick:")), 0, 0, 1, 1);
3358- main.attach (nick, 1, 0, 1, 1);
3359- main.attach (new LLabel.right (_("Real Name:")), 0, 1, 1, 1);
3360- main.attach (realname, 1, 1, 1, 1);
3361- main.attach (done, 1, 2, 1, 1);
3362-
3363- modal = true;
3364- (get_content_area () as Gtk.Container).add (main);
3365- this.title = _("User Settings");
3366-
3367- nick.changed.connect (update_sensivity);
3368- realname.changed.connect (update_sensivity);
3369-
3370- done.clicked.connect (() => {
3371- var settings = Cable.Settings.get_default ();
3372- settings.real_name = realname.text;
3373- settings.nick = nick.text;
3374-
3375- destroy ();
3376- });
3377-
3378- nick.text = Settings.get_default ().nick;
3379- realname.text = Settings.get_default ().real_name;
3380-
3381- update_sensivity ();
3382- }
3383-
3384- void update_sensivity () {
3385- done.sensitive = nick.text != "" && realname.text != "";
3386- }
3387- }
3388-}
3389
3390=== added file 'src/Widgets/StatusBar.vala'
3391--- src/Widgets/StatusBar.vala 1970-01-01 00:00:00 +0000
3392+++ src/Widgets/StatusBar.vala 2013-06-28 19:09:26 +0000
3393@@ -0,0 +1,49 @@
3394+/***
3395+ Copyright (C) 2013 Cable Developers
3396+
3397+ This program or library is free software; you can redistribute it
3398+ and/or modify it under the terms of the GNU Lesser General Public
3399+ License as published by the Free Software Foundation; either
3400+ version 3 of the License, or (at your option) any later version.
3401+
3402+ This library is distributed in the hope that it will be useful,
3403+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3404+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3405+ Lesser General Public License for more details.
3406+
3407+ You should have received a copy of the GNU Lesser General
3408+ Public License along with this library; if not, write to the
3409+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
3410+ Boston, MA 02110-1301 USA.
3411+***/
3412+
3413+public class Cable.Widgets.StatusBar : Granite.Widgets.StatusBar {
3414+
3415+ public signal void send_message (string message);
3416+
3417+ public StatusBar () {
3418+ var item = get_nth_item (1);
3419+ item.remove (item.get_child ());
3420+ item.set_expand (true);
3421+ item.halign = Gtk.Align.FILL;
3422+
3423+ var entry = new Gtk.Entry ();
3424+ entry.halign = Gtk.Align.FILL;
3425+
3426+ item.add (entry);
3427+
3428+ get_nth_item (0).width_request = 156;
3429+ get_nth_item (2).width_request = 156;
3430+
3431+ insert_widget (main_actions.get_action ("JoinChannel").create_tool_item() as Gtk.ToolButton, true);
3432+ insert_widget (main_actions.get_action ("LeaveChannel").create_tool_item() as Gtk.ToolButton, true);
3433+ insert_widget (main_actions.get_action ("EditCurrentId").create_tool_item() as Gtk.ToolButton, true);
3434+ insert_widget (main_actions.get_action ("Preferences").create_tool_item() as Gtk.ToolButton);
3435+ insert_widget (main_actions.get_action ("About").create_tool_item() as Gtk.ToolButton);
3436+
3437+ entry.activate.connect (() => {
3438+ send_message (entry.text);
3439+ entry.text = "";
3440+ });
3441+ }
3442+}
3443
3444=== added file 'src/Widgets/Welcome.vala'
3445--- src/Widgets/Welcome.vala 1970-01-01 00:00:00 +0000
3446+++ src/Widgets/Welcome.vala 2013-06-28 19:09:26 +0000
3447@@ -0,0 +1,112 @@
3448+/***
3449+ Copyright (C) 2013 Cable Developers
3450+
3451+ This program or library is free software; you can redistribute it
3452+ and/or modify it under the terms of the GNU Lesser General Public
3453+ License as published by the Free Software Foundation; either
3454+ version 3 of the License, or (at your option) any later version.
3455+
3456+ This library is distributed in the hope that it will be useful,
3457+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3458+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3459+ Lesser General Public License for more details.
3460+
3461+ You should have received a copy of the GNU Lesser General
3462+ Public License along with this library; if not, write to the
3463+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
3464+ Boston, MA 02110-1301 USA.
3465+***/
3466+
3467+public class Cable.Widgets.Welcome : Granite.Widgets.Welcome {
3468+
3469+ public signal void done (Settings.Network network, Settings.Identity identity, string channel);
3470+
3471+ Gtk.Entry channel_entry;
3472+
3473+ public Welcome () {
3474+ base (_("Connect to the IRC world."), _("Join a Channel."));
3475+
3476+ var grid = new Gtk.Grid ();
3477+ grid.margin = 12;
3478+ grid.column_spacing = 6;
3479+ grid.row_spacing = 6;
3480+
3481+ // Labels
3482+ var server_label = new Gtk.Label (_("Network:"));
3483+ server_label.halign = Gtk.Align.END;
3484+ server_label.valign = Gtk.Align.CENTER;
3485+
3486+ var id_label = new Gtk.Label (_("Identity:"));
3487+ id_label.halign = Gtk.Align.END;
3488+ id_label.valign = Gtk.Align.CENTER;
3489+
3490+ var channel_label = new Gtk.Label (_("Channel:"));
3491+ channel_label.halign = Gtk.Align.END;
3492+ channel_label.valign = Gtk.Align.CENTER;
3493+
3494+ // Entries/Comboboxes
3495+ var server_entry = new Gtk.ComboBoxText.with_entry ();
3496+ for (int i = 0; i < Settings.networks.size; i++)
3497+ server_entry.append (i.to_string (), Settings.networks[i].name);
3498+ server_entry.active = 0;
3499+
3500+ var id_entry = new Gtk.ComboBoxText.with_entry ();
3501+ for (int i = 0; i < Settings.identities.size; i++)
3502+ id_entry.append (i.to_string (), Settings.identities[i].nick_name);
3503+ id_entry.active = 0;
3504+
3505+ channel_entry = new Gtk.Entry ();
3506+ channel_entry.secondary_icon_name = "edit-redo-symbolic";
3507+ channel_entry.text = "#";
3508+
3509+ // button
3510+ var join_button = new Gtk.Button.with_label (_("Join Channel"));
3511+ join_button.halign = Gtk.Align.END;
3512+
3513+ var button_box = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL);
3514+ button_box.layout_style = Gtk.ButtonBoxStyle.END;
3515+ button_box.add (join_button);
3516+
3517+ grid.attach (server_label, 0, 0, 1, 1);
3518+ grid.attach (server_entry, 1, 0, 1, 1);
3519+ grid.attach (id_label, 0, 1, 1, 1);
3520+ grid.attach (id_entry, 1, 1, 1, 1);
3521+ grid.attach (channel_label, 0, 2, 1, 1);
3522+ grid.attach (channel_entry, 1, 2, 1, 1);
3523+ grid.attach (button_box, 1, 3, 1, 1);
3524+ grid.margin = 6;
3525+
3526+ channel_entry.insert_text.connect ((text) =>
3527+ Utils.filter (channel_entry, text, {" ", ":"})
3528+ );
3529+
3530+ join_button.clicked.connect (() => channel_entry.activate ());
3531+ channel_entry.icon_release.connect (() => channel_entry.activate ());
3532+ channel_entry.activate.connect (() => {
3533+ Settings.Network network;
3534+ Settings.Identity identity;
3535+
3536+ if (server_entry.active_id == null) {
3537+ network = new Settings.Network (server_entry.get_active_text ());
3538+ } else {
3539+ network = Settings.networks[int.parse (server_entry.active_id)];
3540+ }
3541+
3542+ if (id_entry.active_id == null) {
3543+ identity = new Settings.Identity (id_entry.get_active_text ());
3544+ } else {
3545+ identity = Settings.identities[int.parse (id_entry.active_id)];
3546+ }
3547+
3548+ done (network, identity, channel_entry.text);
3549+ });
3550+
3551+ options.add (grid);
3552+ this.show_all ();
3553+ }
3554+
3555+ public void focus_channel_entry () {
3556+ channel_entry.grab_focus ();
3557+ channel_entry.set_position (-1);
3558+ }
3559+}
3560
3561=== added file 'src/Window.vala'
3562--- src/Window.vala 1970-01-01 00:00:00 +0000
3563+++ src/Window.vala 2013-06-28 19:09:26 +0000
3564@@ -0,0 +1,272 @@
3565+/***
3566+ Copyright (C) 2013 Cable Developers
3567+
3568+ This program or library is free software; you can redistribute it
3569+ and/or modify it under the terms of the GNU Lesser General Public
3570+ License as published by the Free Software Foundation; either
3571+ version 3 of the License, or (at your option) any later version.
3572+
3573+ This library is distributed in the hope that it will be useful,
3574+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3575+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3576+ Lesser General Public License for more details.
3577+
3578+ You should have received a copy of the GNU Lesser General
3579+ Public License along with this library; if not, write to the
3580+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
3581+ Boston, MA 02110-1301 USA.
3582+***/
3583+
3584+Gtk.ActionGroup main_actions;
3585+
3586+public class Cable.Window : Gtk.Window {
3587+
3588+ bool welcome_shown;
3589+
3590+ Gtk.EventBox display_box;
3591+ Widgets.ServerList server_list;
3592+
3593+ Gtk.Grid layout;
3594+ Gtk.Toolbar toolbar;
3595+ Granite.Widgets.ThinPaned paned;
3596+ Widgets.StatusBar statusbar;
3597+ Widgets.Welcome welcome;
3598+
3599+ Gtk.UIManager ui;
3600+
3601+ const string ui_string = """
3602+ <ui>
3603+ <popup name="MenuItemTool">
3604+ <menuitem name="Join Channel" action="JoinChannel"/>
3605+ <menuitem name="Leave Channel" action="LeaveChannel"/>
3606+ <menuitem name="Edit Identity" action="EditCurrentId"/>
3607+ </popup>
3608+
3609+ <popup name="AppMenu">
3610+ <menuitem name="Preferences" action="Preferences"/>
3611+ </popup>
3612+ </ui>
3613+ """;
3614+
3615+ public Window (Cable.App app) {
3616+ GLib.Object (application: app);
3617+ Settings.init ();
3618+ init_actions ();
3619+ init_layout ();
3620+ }
3621+
3622+ ~Window () {
3623+ string [] channels = {};
3624+
3625+ foreach (var server in server_list.servers) {
3626+ foreach (var channel in server.channels) {
3627+ channels += string.join (":", server.network.address,
3628+ server.identity.nick_name, channel.name);
3629+ server.leave_channel (channel.name);
3630+ }
3631+ }
3632+
3633+ Settings.settings.set_strv ("channels", channels);
3634+ }
3635+
3636+ public void init_actions () {
3637+ main_actions = new Gtk.ActionGroup ("MainActionGroup");
3638+ main_actions.set_translation_domain (Constants.GETTEXT_PACKAGE);
3639+ main_actions.add_actions (main_entries, this);
3640+
3641+ ui = new Gtk.UIManager ();
3642+
3643+ try {
3644+ ui.add_ui_from_string (ui_string, -1);
3645+ } catch (Error e) {
3646+ error ("Couldn't load the UI: %s", e.message);
3647+ }
3648+
3649+ Gtk.AccelGroup accel_group = ui.get_accel_group ();
3650+ add_accel_group (accel_group);
3651+
3652+ ui.insert_action_group (main_actions, 0);
3653+ ui.ensure_update ();
3654+ }
3655+
3656+ private void init_layout () {
3657+ layout = new Gtk.Grid ();
3658+ server_list = new Widgets.ServerList ();
3659+ display_box = new Gtk.EventBox ();
3660+ toolbar = new Gtk.Toolbar ();
3661+ paned = new Granite.Widgets.ThinPaned ();
3662+ welcome = new Widgets.Welcome ();
3663+ statusbar = new Widgets.StatusBar ();
3664+
3665+ layout.attach (toolbar, 0, 0, 1, 1);
3666+
3667+ var join_button = main_actions.get_action ("JoinChannel").create_tool_item() as Gtk.ToolButton;
3668+ var leave_button = main_actions.get_action ("LeaveChannel").create_tool_item() as Gtk.ToolButton;
3669+
3670+ toolbar.vexpand = false;
3671+ //toolbar.add (join_button);
3672+ //toolbar.add (leave_button);
3673+
3674+ /*var spacer = new Gtk.ToolItem ();
3675+ spacer.set_expand (true);
3676+ toolbar.add (spacer);
3677+
3678+ var menu = ui.get_widget ("ui/AppMenu") as Gtk.Menu;
3679+ app_menu = (application as Granite.Application).create_appmenu (menu);
3680+ toolbar.add (app_menu);
3681+ */
3682+
3683+ welcome.done.connect (join_channel);
3684+ welcome.hexpand = true;
3685+ welcome.vexpand = true;
3686+
3687+ paned.position = 150;
3688+ paned.pack1 (server_list, false, false);
3689+ paned.pack2 (display_box, true, false);
3690+
3691+ this.title = "Cable";
3692+ this.icon_name = "internet-chat";
3693+ this.set_default_size (740, 480);
3694+ this.window_position = Gtk.WindowPosition.CENTER;
3695+ this.show_all ();
3696+
3697+ statusbar.send_message.connect ((msg) => {
3698+ server_list.current_server.send_message (server_list.current_channel, msg);
3699+ });
3700+
3701+ server_list.item_selected.connect ((item) => {
3702+ if (item != null && item is Widgets.Channel) {
3703+ var channel = item as Widgets.Channel;
3704+ var content = display_box.get_children ().nth_data (0);
3705+
3706+ if (content != null)
3707+ display_box.remove (content);
3708+
3709+ display_box.add ((item as Widgets.Channel).room);
3710+ display_box.show_all ();
3711+ title = string.join (" — ", channel.name, channel.server.identity.nick_name);
3712+ }
3713+ });
3714+
3715+ var channels = Settings.settings.get_strv ("channels");
3716+
3717+ if (channels.length > 0) {
3718+ welcome_shown = false;
3719+ layout.attach (paned, 0, 1, 1, 1);
3720+ layout.attach (statusbar, 0, 2, 1, 1);
3721+ this.add (layout);
3722+ this.show_all ();
3723+
3724+ foreach (var channel in channels) {
3725+ var parts = channel.split (":");
3726+
3727+ Settings.Network network = null;
3728+ Settings.Identity identity = null;
3729+
3730+ foreach (var nw in Settings.networks)
3731+ if (nw.address == parts[0])
3732+ network = nw;
3733+
3734+ foreach (var id in Settings.identities)
3735+ if (id.nick_name == parts[1])
3736+ identity = id;
3737+
3738+ if (network == null)
3739+ network = new Settings.Network (parts[0]);
3740+
3741+ if (identity == null)
3742+ identity = new Settings.Identity (parts[1]);
3743+
3744+ join_channel (network, identity, parts[2]);
3745+ }
3746+
3747+ server_list.selected = server_list.servers[0].channels[0];
3748+ } else {
3749+ welcome_shown = true;
3750+ layout.attach (welcome, 0, 1, 1, 1);
3751+ this.add (layout);
3752+ this.show_all ();
3753+ welcome.focus_channel_entry ();
3754+ }
3755+ }
3756+
3757+ void join_channel (Settings.Network network, Settings.Identity identity, string channel_name) {
3758+ var server = server_list.get_server (network.address, identity.nick_name);
3759+
3760+ if (server == null) {
3761+
3762+ server = new Widgets.Server (network, identity);
3763+ server_list.add_server (server);
3764+
3765+ server.joined_channel.connect ((channel) => {
3766+ if (welcome_shown) {
3767+ welcome_shown = false;
3768+ layout.remove (welcome);
3769+ layout.attach (paned, 0, 1, 1, 1);
3770+ layout.attach (statusbar, 0, 2, 1, 1);
3771+ this.show_all ();
3772+ welcome.focus_channel_entry ();
3773+ server_list.selected = channel;
3774+ }
3775+ });
3776+
3777+ server.left_channel.connect ((channel) => {
3778+ if (server_list.get_n_servers () == 0) {
3779+ welcome_shown = true;
3780+ layout.remove (paned);
3781+ layout.remove (statusbar);
3782+ layout.attach (welcome, 0, 1, 1, 1);
3783+ this.show_all ();
3784+ }
3785+ });
3786+ }
3787+
3788+ server.join_channel (channel_name);
3789+ }
3790+
3791+ void action_join_channel () {
3792+ var dialog = new Dialogs.JoinChannel ();
3793+ dialog.done.connect (join_channel);
3794+ dialog.show_all ();
3795+ }
3796+
3797+ void action_leave_channel () {
3798+ var channel = server_list.current_channel;
3799+
3800+ if (channel != null)
3801+ server_list.current_server.leave_channel (channel.name);
3802+ else
3803+ warning ("No channel selected, cannot leave.");
3804+ }
3805+
3806+ void action_edit_identity () {
3807+ var dialog = new Dialogs.ManageIdentity (server_list.current_server.identity);
3808+ dialog.show_all ();
3809+ }
3810+
3811+ void action_about () {
3812+ (application as Cable.App).show_about (this);
3813+ }
3814+
3815+ void action_preferences () {
3816+ var dialog = new Dialogs.Preferences ();
3817+ dialog.show_all ();
3818+ }
3819+
3820+ private static const Gtk.ActionEntry[] main_entries = {
3821+ { "JoinChannel", "list-add-symbolic", N_("Join Channel…"), "<Control>j",
3822+ N_("Join Channel…"), action_join_channel },
3823+
3824+ { "LeaveChannel", "list-remove-symbolic", N_("Leave current Channel"), "<Control>l",
3825+ N_("Leave current channel"), action_leave_channel },
3826+
3827+ { "EditCurrentId", "avatar-default-symbolic", N_("Edit current Identity…"), "<Control>i",
3828+ N_("Edit current Identity…"), action_edit_identity },
3829+
3830+ { "Preferences", "document-properties-symbolic", N_("Preferences"), null,
3831+ N_("Preferences"), action_preferences },
3832+
3833+ { "About", "help-info-symbolic", N_("About"), null,
3834+ N_("About"), action_about }
3835+ };
3836+}
3837
3838=== removed file 'src/doodleIRC.vala'
3839--- src/doodleIRC.vala 2013-05-29 18:15:05 +0000
3840+++ src/doodleIRC.vala 1970-01-01 00:00:00 +0000
3841@@ -1,385 +0,0 @@
3842-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
3843-/***
3844- BEGIN LICENSE
3845-
3846- Copyright (C) 2013 Akshay Shekher <voldyman666@gmail.com>
3847- This program is free software: you can redistribute it and/or modify it
3848- under the terms of the GNU Lesser General Public License version 3, as published
3849- by the Free Software Foundation.
3850-
3851- This program is distributed in the hope that it will be useful, but
3852- WITHOUT ANY WARRANTY; without even the implied warranties of
3853- MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3854- PURPOSE. See the GNU General Public License for more details.
3855-
3856- You should have received a copy of the GNU General Public License along
3857- with this program. If not, see <http://www.gnu.org/licenses/>
3858-
3859- END LICENSE
3860-***/
3861-
3862-namespace doodleIRC {
3863-
3864- public errordomain IRCError {
3865- COULD_NOT_CONNECT,
3866- COULD_NOT_JOIN
3867- // ...
3868- }
3869-
3870- public class Channel {
3871-
3872- public string nick;
3873- public string topic;
3874- public List<string> users;
3875- public string name;
3876-
3877- public Channel (string name) {
3878- this.name = name;
3879- }
3880- }
3881-
3882- public class DoodleIRCServer {
3883-
3884- // Signals
3885- public signal void on_connect_complete ();
3886- public signal void on_message (string sender, string chan, string msg);
3887- public signal void on_action (string sender, string chan, string msg);
3888- public signal void on_notice (string notice);
3889- public signal void on_error (string error_msg);
3890- public signal void on_user_join (string chan, string nick);
3891- public signal void on_join_complete (string chan, string nick);
3892- public signal void on_user_quit (string chan, string nick, string msg);
3893- public signal void on_names_listed (string chan, string[] names);
3894-
3895- public delegate void GetTopicFunc (string chan, string topic);
3896- public List<Channel> chans;
3897-
3898- GetTopicFunc topic_received;
3899- string nick;
3900- bool away;
3901- string server_url;
3902- User user;
3903- SocketConnection connection;
3904- DataInputStream response;
3905- bool connected;
3906- List<string> to_send;
3907- Gee.HashMap<string, string> list_of_names;
3908-
3909- public DoodleIRCServer (string url, User user,string nick) {
3910- this.server_url = url;
3911- this.user = user;
3912- this.nick = nick;
3913- away = false;
3914-
3915- topic_received = (chan, topic) => {
3916- debug (chan + "=>" + topic);
3917- };
3918- this.chans = new List<Channel> ();
3919- connected = false;
3920- to_send = new List<string> ();
3921-
3922- list_of_names = new Gee.HashMap<string,string> ();
3923-
3924- on_connect_complete.connect (() => {
3925- to_send.foreach ((cmd) => {
3926- debug ("Sending "+cmd);
3927- raw_send (cmd);
3928- to_send.remove (cmd);
3929- });
3930- });
3931- }
3932-
3933- ~DoodleIRCServer () {
3934- print ("Exiting");
3935- quit_server ("Client Quit");
3936- }
3937-
3938- public async void connect (string server = "") {
3939- try {
3940- // Resolve hostname to IP address
3941- var resolver = Resolver.get_default ();
3942- var addresses = yield resolver.lookup_by_name_async (this.server_url, null);
3943- var address = addresses.nth_data (0);
3944- debug ("Resolved %s to %s\n".printf (this.server_url, address.to_string ()));
3945-
3946- // Connect
3947- var client = new SocketClient ();
3948- connection = yield client.connect_async (new InetSocketAddress (address, 6667));
3949- debug ("Connected to %s\n".printf (this.server_url));
3950- this.connected = true;
3951- //response stream
3952- response = new DataInputStream (connection.input_stream);
3953-
3954- // Send USER request
3955- var message = "USER %s %s %s :%s\r\n".printf (user.username, user.hostname,
3956- user.servername, user.realname);
3957- raw_send (message);
3958- debug ("Wrote request USER\n");
3959-
3960- // Send NICK request
3961- message = "NICK %s\r\n".printf (nick);
3962- raw_send (message);
3963- debug ("Wrote nick request\n");
3964-
3965- wait.begin ();
3966- } catch (Error e) {
3967- error ("Could not connect: %s".printf (e.message));
3968- }
3969-
3970- }
3971-
3972- public async void wait () {
3973- try {
3974- var line = yield response.read_line_async ();
3975- parse_line (line);
3976- } catch (Error e) {
3977- print ("Error: %s\n".printf (e.message));
3978- }
3979-
3980- if (connected)
3981- wait.begin ();
3982- }
3983-
3984- private void parse_line (string line) {
3985- print (line + "\n");
3986-
3987- if (line[0] != ':') {
3988- process_named_server_message (line);
3989- return;
3990- }
3991-
3992- if (line[0] == ':') {
3993- if ((line.split (" ")[1][0]).isdigit ()) {
3994- process_numeric_cmd (line);
3995- } else {
3996- process_named_message (line);
3997- }
3998- }
3999- }
4000-
4001- private void process_named_message (string line) {
4002- string sender="", cmd="", chan="", msg="";
4003- parse_named_msg (line, out sender,out cmd, out chan, out msg);
4004-
4005- switch (cmd.up ()) {
4006- case "PRIVMSG":
4007- if (msg.split (" ")[0] == "\001ACTION") {
4008- msg = msg.replace ("ACTION ", "");
4009- msg = msg.replace ("\001", "");
4010- on_action (sender, chan, msg);
4011- break;
4012- }
4013-
4014- print ("Chan-> "+chan+"\nMSG-> "+msg+"\n");
4015- on_message (sender, chan, msg);
4016- break;
4017-
4018- case "QUIT":
4019- print (" %s has quit\n".printf (sender));
4020- on_user_quit (chan, sender, msg);
4021- break;
4022-
4023- case "JOIN":
4024- if (sender == nick) {
4025- on_join_complete (chan, sender);
4026- break;
4027- }
4028- print ("User has Joined");
4029- on_user_join (chan, sender);
4030- break;
4031- }
4032- }
4033-
4034- private void process_named_server_message (string line) {
4035- var cmd = line.split (" ")[0].strip ();
4036- var msg = line.split (" :")[1].strip ();
4037-
4038- switch (cmd.up ()) {
4039- case "PING":
4040- print ("pinged\n");
4041- raw_send (line.replace ("PING","PONG"));
4042- break;
4043-
4044- case "NOTICE":
4045- print ("Noice: "+msg+"\n");
4046- on_notice (msg);
4047- break;
4048-
4049- case "ERROR":
4050- print ("An Error Occured: %s\n".printf (msg));
4051- on_error (msg);
4052- break;
4053- }
4054- }
4055-
4056- private void process_numeric_cmd (string line) {
4057- var first_split = line.split (" ");
4058- /* this might come handy in the future :) */
4059- //var sender = first_split[0].strip ();
4060- var cmd = first_split[1].strip ();
4061- var msg = line.split (" :")[1].strip ();
4062-
4063- /* more info about these commands can be found at the IRC RFC page */
4064- switch (cmd) {
4065- case "001":
4066- on_connect_complete ();
4067- break;
4068-
4069- case "005":
4070- // this.connect (msg);
4071- break;
4072-
4073- case "301":
4074- print ("Away: "+msg);
4075- break;
4076-
4077- case "433": // nick name is use
4078- change_nick (this.nick + "_");
4079- rejoin_channels ();
4080- break;
4081-
4082- case "353": //RPL_NAMESLISTED
4083- var chan = first_split[4];
4084- if (list_of_names.has_key (chan)) {
4085- var names = list_of_names.get (chan);
4086- names = " " + msg;
4087- list_of_names.set (chan, names);
4088- } else {
4089- list_of_names.set (chan, msg);
4090- }
4091-
4092- break;
4093-
4094- case "366": //RPL_ENDOFNAMES
4095- foreach (var channel in list_of_names.keys.to_array ()) {
4096- on_names_listed (channel, list_of_names.get (channel).split (" "));
4097- }
4098-
4099- list_of_names.clear ();
4100- break;
4101- case "332":
4102- var chan = first_split[3].strip ();
4103- chans.foreach((channel) => {
4104- if (channel.name == chan) {
4105- channel.topic = msg;
4106- topic_received (channel.name, msg);
4107- }
4108- });
4109- break;
4110- }
4111- }
4112-
4113- private void parse_named_msg (string line, out string sender,out string cmd,
4114- out string chan, out string msg) {
4115- // split the message from the info
4116- var first_split = line.split (":");
4117- var info = first_split[1];
4118- // msg = join_str_ar (2, first_split.length, first_split);
4119- msg = line.split (" :")[1];
4120-
4121- // split the info to extract sender and chan
4122- var second_split = info.split (" ");
4123- cmd = second_split[1].strip ();
4124- chan = second_split[2].strip ();
4125- sender = second_split[0].strip ().split ("!")[0];
4126- }
4127-
4128- private void raw_send (string line) {
4129- try {
4130- connection.output_stream.write (line.data);
4131- connection.output_stream.flush ();
4132- } catch (Error e) {
4133- error ("raw_send: %s".printf (e.message));
4134- }
4135- }
4136-
4137- public void send (string cmd) {
4138- if (connected)
4139- raw_send (cmd);
4140- else
4141- to_send.append (cmd);
4142- }
4143-
4144- private void rejoin_channels () {
4145- // Send JOIN request
4146- foreach (var chan in chans) {
4147- string chan_name = chan.name;
4148- raw_send ("JOIN %s\r\n".printf (chan_name));
4149- print ("Wrote request to join %s\n".printf (chan_name));
4150- }
4151- }
4152-
4153- public void kick_user (string chan, string user, string reason) {
4154- send ("KICK %s %s :%s\r\n".printf (chan, user, reason));
4155- }
4156-
4157- public void join_chan (string chan, string key="") /*throws IRCError*/ {
4158- send ("JOIN %s :%s\r\n".printf (chan, key));
4159- var channel = new Channel (chan);
4160- chans.append (channel);
4161- }
4162-
4163- public void quit_server (string message) {
4164- send ("QUIT :%s\r\n".printf (message));
4165- }
4166-
4167- public void leave_chan (string chan) {
4168- send ("PART %s\r\n".printf (chan));
4169- }
4170-
4171- public void write (string chan, string msg) {
4172- send ("PRIVMSG %s :%s\r\n".printf (chan, msg));
4173- }
4174-
4175- public void notice (string to, string text) {
4176- send ("NOTICE %s :%s\r\n".printf (to, text));
4177- }
4178-
4179- public void get_names (string chan) {
4180- send ("NAMES %s\r\n".printf (chan));
4181- }
4182-
4183- public void set_away (string reason) {
4184- away = true;
4185- send ("AWAY :%s\r\n".printf (reason));
4186- }
4187-
4188- public void set_back () {
4189- away = false;
4190- send ("AWAY \r\n");
4191- }
4192-
4193- public void toggle_away (string reason = "") {
4194- if (this.away)
4195- set_back ();
4196- else
4197- set_away (reason);
4198- }
4199-
4200- public void change_nick (string nick) {
4201- this.nick = nick;
4202- raw_send ("NICK %s\r\n".printf (this.nick));
4203- }
4204-
4205- public void write_action (string chan, string msg) {
4206- write (chan, "\001ACTION %s\001\r\n".printf (msg));
4207- }
4208-
4209- public void disconnect () {
4210- raw_send ("QUIT :bye");
4211- connected = false;
4212- }
4213-
4214- public void get_topic (string chan, GetTopicFunc func) {
4215- topic_received = func;
4216- send ("TOPIC %s\r\n".printf (chan));
4217- }
4218- }
4219-
4220- public struct User {
4221- public string username;
4222- public string hostname;
4223- public string servername;
4224- public string realname;
4225- }
4226-}

Subscribers

People subscribed via source and target branches

to all changes: