New command SHOW SYSTEM to easily print information useful in bug reports.
[pspp] / src / ui / gui / help-menu.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013, 2015, 2016,
3    2021 Free Software Foundation
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
17
18
19 #include <config.h>
20
21 #include <gtk/gtk.h>
22
23 #include "libpspp/cast.h"
24 #include "libpspp/copyleft.h"
25 #include "libpspp/message.h"
26 #include "libpspp/version.h"
27 #include "ui/gui/executor.h"
28 #include "ui/gui/help-menu.h"
29 #include "ui/gui/psppire-data-window.h"
30
31 #include "gl/configmake.h"
32 #include "gl/relocatable.h"
33
34 #include <gettext.h>
35 #define _(msgid) gettext (msgid)
36 #define N_(msgid) msgid
37
38 /* Try to open html documentation uri via the default
39    browser on the operating system */
40 #ifdef __APPLE__
41 #define HTMLOPENAPP "open"
42 #elif  _WIN32
43 #define HTMLOPENAPP "wscript"
44 #else
45 #define HTMLOPENAPP "xdg-open"
46 #endif
47
48 static const gchar *artists[] = { "Bastián Díaz", "Hugo Alejandro", NULL};
49
50 /* Opening the htmluri in windows via cmd /start uri opens
51    the windows command shell for a moment. The alternative is
52    to start a script via wscript. This will not be visible*/
53 #ifdef _WIN32
54 static gboolean
55 open_windows_help (const gchar *helpuri, GError **err)
56 {
57   SHELLEXECUTEINFOA info;
58   memset (&info, 0, sizeof (info));
59
60   info.cbSize = sizeof (info);
61   info.fMask = SEE_MASK_FLAG_NO_UI;
62   info.lpVerb = "open";
63   info.lpFile = helpuri;
64   info.nShow = SW_SHOWNORMAL;
65
66   BOOL ret = ShellExecuteExA (&info);
67
68   if (ret)
69     return TRUE;
70
71   /* Contrary to what the microsoft documentation indicates, ShellExecuteExA does
72      not seem to setLastError.  So we have to deal with errors ourselves here.  */
73   const char *msg = 0;
74   switch (GPOINTER_TO_INT (info.hInstApp))
75     {
76     case SE_ERR_FNF:
77       msg = "File not found";
78       break;
79     case SE_ERR_PNF:
80       msg = "Path not found";
81       break;
82     case SE_ERR_ACCESSDENIED:
83       msg = "Access denied";
84       break;
85     case SE_ERR_OOM:
86       msg = "Out of memory";
87       break;
88     case SE_ERR_DLLNOTFOUND:
89       msg = "Dynamic-link library not found";
90       break;
91     case SE_ERR_SHARE:
92       msg = "Cannot share an open file";
93       break;
94     case SE_ERR_ASSOCINCOMPLETE:
95       msg = "File association information not complete";
96       break;
97     case SE_ERR_DDETIMEOUT:
98       msg = "DDE operation timed out";
99       break;
100     case SE_ERR_DDEFAIL:
101       msg = "DDE operation failed";
102       break;
103     case SE_ERR_DDEBUSY:
104       msg = "DDE operation is busy";
105       break;
106     case SE_ERR_NOASSOC:
107       msg = "File association not available";
108       break;
109     default:
110       msg = "Unknown error";
111       break;
112     }
113
114   *err = g_error_new_literal (g_quark_from_static_string ("pspp-help-error"),
115                        0,
116                        msg);
117
118   return FALSE;
119 }
120
121 static gboolean
122 on_activate_link (GtkAboutDialog *label,
123                gchar          *uri,
124                gpointer        user_data)
125 {
126   return  open_windows_help (uri, NULL);
127 }
128 #endif
129
130 static void
131 about_system_info (GtkMenuItem *mmm, GtkWindow *parent)
132 {
133   execute_const_syntax_string (psppire_default_data_window (), "SHOW SYSTEM.");
134 }
135
136 static void
137 about_new (GtkMenuItem *mmm, GtkWindow *parent)
138 {
139   GtkWidget *about =  gtk_about_dialog_new ();
140
141 #ifdef _WIN32
142   /* The default handler for Windows doesn't appear to work.  */
143   g_signal_connect (about, "activate-link", G_CALLBACK (on_activate_link), parent);
144 #endif
145
146   gtk_about_dialog_set_logo_icon_name (GTK_ABOUT_DIALOG (about), "pspp");
147
148   gtk_window_set_icon_name (GTK_WINDOW (about), "pspp");
149
150   gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (about), PACKAGE_URL);
151
152   gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (about),
153                                 announced_version);
154
155   gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (about),
156                                 (const gchar **) authors);
157
158   gtk_about_dialog_set_artists (GTK_ABOUT_DIALOG (about),
159                                 artists);
160
161   gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (about),
162                                 copyleft);
163
164   gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (about),
165                                  _("A program for the analysis of sampled data"));
166
167   gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (about),
168                                   "Free Software Foundation");
169
170   gtk_about_dialog_set_translator_credits
171     (
172      GTK_ABOUT_DIALOG (about),
173      /* TRANSLATORS: Do not translate this string.  Instead, put the names of the people
174         who have helped in the translation. */
175      _("translator-credits")
176 );
177
178   gtk_window_set_transient_for (GTK_WINDOW (about), parent);
179
180   gtk_window_set_modal (GTK_WINDOW (about), TRUE);
181
182   gtk_dialog_run (GTK_DIALOG (about));
183
184   gtk_widget_hide (about);
185 }
186
187
188
189 /* Open the manual at PAGE with the following priorities
190    First: local yelp help system
191    Second: browser with local html doc dir in path pspp.html/<helppage>.html
192    Third:  browers with Internet html help at gnu.org */
193 void
194 online_help (const char *page)
195 {
196   GError *htmlerr = NULL;
197   gchar *htmlfilename = NULL;
198   gchar *htmlfullname = NULL;
199   gchar *htmluri = NULL;
200
201   if (page == NULL)
202     {
203       htmlfilename = g_strdup ("index.html");
204     }
205   else
206     {
207       gchar **tokens = NULL;
208       const int maxtokens = 5;
209       int idx ;
210       /* The page will be translated to the htmlfilename
211          page                   htmlfilename
212          GRAPH#SCATTERPLOT      SCATTERPLOT.html
213          QUICK-CLUSTER          QUICK-CLUSTER.html
214          which is valid for the multiple page html doc*/
215       tokens = g_strsplit (page, "#", maxtokens);
216       for (idx = 0; idx < maxtokens && tokens[idx]; idx++)
217         ;
218       htmlfilename = g_strdup_printf ("%s.html", tokens[idx-1]);
219       g_strfreev (tokens);
220     }
221   /* Hint: pspp.html is a directory...*/
222   htmlfullname = g_strdup_printf ("%s/%s", relocate (DOCDIR "/pspp.html"),
223                                   htmlfilename);
224   if (g_file_test (relocate (DOCDIR "/pspp.html"), G_FILE_TEST_IS_DIR))
225     {
226       GError *urierr = NULL;
227       htmluri =  g_filename_to_uri (htmlfullname,NULL, &urierr);
228       if (!htmluri)
229         {
230           msg (ME, _("Help path conversion error: %s"), urierr->message);
231           htmluri = htmlfullname;
232         }
233       g_clear_error (&urierr);
234     }
235   else
236     htmluri = g_strdup_printf (PACKAGE_URL "manual/html_node/%s",
237                                htmlfilename);
238   g_free (htmlfullname);
239   g_free (htmlfilename);
240
241 #ifdef _WIN32
242   bool ok = open_windows_help (htmluri, &htmlerr);
243 #else
244   gchar *htmlargv[3] = {CONST_CAST (char *, HTMLOPENAPP), htmluri, 0};
245   bool ok = g_spawn_async (NULL, htmlargv,
246                            NULL, G_SPAWN_SEARCH_PATH,
247                            NULL, NULL, NULL, &htmlerr);
248 #endif
249   if (!ok)
250     {
251       msg (ME, _("Cannot open via html: %s "
252                  "with uri: %s "
253                  "The PSSP manual is also available at %s"),
254                   htmlerr->message,
255                   htmluri,
256                   PACKAGE_URL "documentation.html");
257     }
258
259   g_free (htmluri);
260   g_clear_error (&htmlerr);
261 }
262
263 static void
264 reference_manual (GtkMenuItem *menu, gpointer data)
265 {
266   online_help (NULL);
267 }
268
269 GtkWidget *
270 create_help_menu (GtkWindow *toplevel)
271 {
272   GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (_("_Help"));
273   GtkWidget *menu = gtk_menu_new ();
274
275   GtkWidget *help_about = gtk_menu_item_new_with_mnemonic (_("_About"));
276   GtkWidget *help_system_info = gtk_menu_item_new_with_mnemonic (_("_System Information"));
277   GtkWidget *help_ref = gtk_menu_item_new_with_mnemonic (_("_Reference Manual"));
278
279   GtkAccelGroup *accel_group = gtk_accel_group_new ();
280
281   gtk_window_add_accel_group (toplevel, accel_group);
282
283   gtk_widget_add_accelerator (help_ref,
284                               "activate", accel_group,
285                               GDK_KEY_F1, 0,
286                               GTK_ACCEL_VISIBLE);
287
288   gtk_menu_attach (GTK_MENU (menu), help_ref, 0, 1, 0, 1);
289   gtk_menu_attach (GTK_MENU (menu), help_system_info, 0, 1, 1, 2);
290   gtk_menu_attach (GTK_MENU (menu), help_about, 0, 1, 2, 3);
291
292   g_signal_connect (help_about, "activate", G_CALLBACK (about_new), toplevel);
293   g_signal_connect (help_system_info, "activate", G_CALLBACK (about_system_info), toplevel);
294   g_signal_connect (help_ref, "activate", G_CALLBACK (reference_manual), NULL);
295
296   g_object_set (menuitem, "submenu", menu, NULL);
297
298   gtk_widget_show_all (menuitem);
299
300   g_object_unref (accel_group);
301
302   return menuitem;
303 }