Added "search" architecture
[WebThing.git] / WebThing.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Text.RegularExpressions;
5 using System.Runtime.InteropServices;
6 using Gtk;
7 using GtkSharp;
8 using WebKit;
9
10 namespace bytex64.WebThing {
11     public enum AttachPoint {
12         N, E, S, W, Interior
13     }
14
15     public class WebThing {
16         private Gtk.Window _Window;
17         public Gtk.Window Window {
18             get { return _Window; }
19         }
20         public Gtk.Window w {
21             get { return _Window; }
22         }
23
24         public ScrolledWindow ScrolledWindow {
25             get { return Tabs.CurrentPageWidget as ScrolledWindow; }
26         }
27         public ScrolledWindow sw {
28             get { return ScrolledWindow; }
29         }
30
31         public WebView WebView {
32             get { return (Tabs.CurrentPageWidget as WebThingView).WebView; }
33         }
34         public WebView wv {
35             get { return WebView; }
36         }
37
38         private Gtk.Notebook _Tabs;
39         public Gtk.Notebook Tabs {
40             get { return _Tabs; }
41         }
42
43         private Gtk.Table WidgetGrid;
44         private Gtk.Alignment InteriorOverlay;
45
46         public PluginManager Plugins;
47         public SearchHandler Search;
48
49         [DllImport ("SoupSettings.dll")]
50         private static extern void soup_settings();
51
52         // Main setup
53         public void Run() {
54             Application.Init();
55
56             soup_settings();
57
58             Config.ParseCommandLine();
59             Config.Load();
60             //Config.DumpOptions();
61
62             // Initialize Window
63             _Window = new Gtk.Window("WebThing");
64             // The GTK+ docs say not to use this, but the defaults are
65             // based on the executable name, which I don't like.
66             _Window.SetWmclass("webthing", "WebThing");  
67             _Window.Role = "browser";
68             _Window.Destroyed += delegate { Quit(); };
69
70             // Initialize WidgetGrid
71             // The WidgetGrid holds the Tabs (and thus WebKit) and
72             // AttachPoint.Interior in the center, and allows widgets to
73             // be added on the sides of the browser
74             WidgetGrid = new Gtk.Table(3, 3, false);
75             _Window.Add(WidgetGrid);
76
77             // Initialize Tabs
78             // Tabs are a core feature of WebThing, not a plugin.  By
79             // default, they do nothing -- Tab manipulation is left to
80             // plugins to define.
81             _Tabs = new Gtk.Notebook();
82             _Tabs.ShowBorder = false;
83             _Tabs.Scrollable = true;
84             _Tabs.SwitchPage += Tabs_SwitchPage;
85             WidgetGrid.Attach(_Tabs, 1, 2, 1, 2);
86
87             // InteriorOverlay goes over top of the Tabs to contain
88             // widgets that hover over the content, like progress, or
89             // inline search.  This is not a very solid idea ATM.
90             InteriorOverlay = new Gtk.Alignment(1, 0, 0, 0);
91             WidgetGrid.Attach(InteriorOverlay, 1, 2, 1, 2);
92
93             _Window.ShowAll();
94
95             // Load Plugins
96             Plugins = new PluginManager(this);
97             Plugins.Load();
98
99             // Load Search Handlers
100             Search = new SearchHandler(this);
101
102             // Create a new, default WebThingView if one has not already
103             // been created.
104             if (Tabs.NPages == 0)
105                 OpenTab("http://dominionofawesome.com/");
106             WebView.GrabFocus();
107
108             Application.Run();
109         }
110
111         public void Quit() {
112             Plugins.Deinit();
113             Application.Quit();
114         }
115
116         // Widget attachment
117         public void AttachWidget(Gtk.Widget widget, AttachPoint direction, AttachOptions xoptions, AttachOptions yoptions) {
118             switch(direction) {
119             case AttachPoint.N:
120                 WidgetGrid.Attach(widget, 0, 3, 0, 1, xoptions, yoptions, 0, 0);
121                 break;
122             case AttachPoint.E:
123                 WidgetGrid.Attach(widget, 2, 3, 1, 2, xoptions, yoptions, 0, 0);
124                 break;
125             case AttachPoint.S:
126                 WidgetGrid.Attach(widget, 0, 3, 2, 3, xoptions, yoptions, 0, 0);
127                 break;
128             case AttachPoint.W:
129                 WidgetGrid.Attach(widget, 0, 1, 1, 2, xoptions, yoptions, 0, 0);
130                 break;
131             case AttachPoint.Interior:
132                 InteriorOverlay.Add(widget);
133                 break;
134             }
135         }
136
137         public void AttachWidget(Gtk.Widget widget, AttachPoint direction) {
138             AttachWidget(widget, direction, 0, 0);
139         }
140
141         // Tab management
142         public WebThingView NewTab() {
143             WebThingView newview = NewWebThingView();
144             Plugins.WebViewSetup(newview.WebView);
145             return newview;
146         }
147
148         private WebThingView NewWebThingView() {
149             WebThingView newview = new WebThingView();
150             Tabs.AppendPage(newview, new Label("Blank"));
151             newview.WebView.TitleChanged += delegate(object o, TitleChangedArgs e) {
152                 Tabs.SetTabLabelText((Gtk.Widget) newview, e.Title);
153                 if (newview == Tabs.CurrentPageWidget)
154                     _Window.Title = e.Title + " - WebThing";
155             };
156             newview.Show();
157             return newview;
158         }
159
160         public void CloseTab() {
161             CloseTab(_Tabs.Page);
162         }
163
164         public void CloseTab(int tab) {
165             if (_Tabs.NPages > 1) {
166                 try {
167                     WebThingView view = _Tabs.GetNthPage(tab) as WebThingView;
168                     _Tabs.RemovePage(tab);
169                     view.Dispose();
170                 } catch (ArgumentOutOfRangeException) {
171                     Console.WriteLine("Attempted to close tab out of range: {0}", tab);
172                 }
173             }
174         }
175
176         private void Tabs_SwitchPage(object o, SwitchPageArgs e) {
177             Gtk.Widget page = _Tabs.GetNthPage((int)e.PageNum);
178             _Window.Title = _Tabs.GetTabLabelText(page) + " - WebThing";
179         }
180
181         // Uri loading
182         private string GetUri(string query) {
183             Uri u;
184             try {
185                 u = new Uri(query);
186                 return u.ToString();
187             } catch(UriFormatException) {
188                 try {
189                     u = new Uri(String.Format("http://{0}", query));
190                     return u.ToString();
191                 } catch (UriFormatException) {
192                     return Search.Transform(query);
193                 }
194             }
195         }
196
197         public bool Open(string query) {
198             string uri = GetUri(query);
199             if (uri == null) return false;
200             
201             wv.Open(uri);
202             return true;
203         }
204
205         public bool OpenTab(string query) {
206             WebThingView wtv = NewTab();
207             string uri = GetUri(query);
208             if (uri == null) return false;
209
210             wtv.WebView.Open(uri);
211             return true;
212         }
213     }
214 }