1 /*
2 * MessageStack - manages stack of active status messages
3 *
4 * Authors:
5 * MenTaLguY <mental@rydia.net>
6 *
7 * Copyright (C) 2004 MenTaLguY
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include <string.h>
13 #include <glib/gstrfuncs.h>
14 #include <cstring>
15 #include <string>
16 #include "message-stack.h"
18 namespace Inkscape {
20 MessageStack::MessageStack()
21 : _messages(NULL), _next_id(1)
22 {
23 }
25 MessageStack::~MessageStack()
26 {
27 while (_messages) {
28 _messages = _discard(_messages);
29 }
30 }
32 MessageId MessageStack::push(MessageType type, gchar const *message) {
33 return _push(type, 0, message);
34 }
36 MessageId MessageStack::pushF(MessageType type, gchar const *format, ...)
37 {
38 va_list args;
39 va_start(args, format);
40 MessageId id=pushVF(type, format, args);
41 va_end(args);
42 return id;
43 }
45 MessageId MessageStack::pushVF(MessageType type, gchar const *format, va_list args)
46 {
47 MessageId id;
48 gchar *message=g_strdup_vprintf(format, args);
49 id = push(type, message);
50 g_free(message);
51 return id;
52 }
54 void MessageStack::cancel(MessageId id) {
55 Message **ref;
56 for ( ref = &_messages ; *ref ; ref = &(*ref)->next ) {
57 if ( (*ref)->id == id ) {
58 *ref = _discard(*ref);
59 _emitChanged();
60 break;
61 }
62 }
63 }
65 MessageId MessageStack::flash(MessageType type, gchar const *message) {
66 switch (type) {
67 case INFORMATION_MESSAGE: // stay rather long so as to seem permanent, but eventually disappear
68 return _push(type, 6000 + 80*strlen(message), message);
69 break;
70 case ERROR_MESSAGE: // pretty important stuff, but temporary
71 return _push(type, 4000 + 60*strlen(message), message);
72 break;
73 case WARNING_MESSAGE: // a bit less important than error
74 return _push(type, 2000 + 40*strlen(message), message);
75 break;
76 case IMMEDIATE_MESSAGE: // same length as normal, higher priority
77 return _push(type, 1000 + 20*strlen(message), message);
78 break;
79 case NORMAL_MESSAGE: // something ephemeral
80 default:
81 return _push(type, 1000 + 20*strlen(message), message);
82 break;
83 }
84 }
86 MessageId MessageStack::flashF(MessageType type, gchar const *format, ...) {
87 va_list args;
88 va_start(args, format);
89 MessageId id = flashVF(type, format, args);
90 va_end(args);
91 return id;
92 }
94 MessageId MessageStack::flashVF(MessageType type, gchar const *format, va_list args)
95 {
96 gchar *message=g_strdup_vprintf(format, args);
97 MessageId id = flash(type, message);
98 g_free(message);
99 return id;
100 }
102 MessageId MessageStack::_push(MessageType type, guint lifetime, gchar const *message)
103 {
104 Message *m=new Message;
105 MessageId id=_next_id++;
107 m->stack = this;
108 m->id = id;
109 m->type = type;
110 m->message = g_strdup(message);
112 if (lifetime) {
113 m->timeout_id = g_timeout_add(lifetime, &MessageStack::_timeout, m);
114 } else {
115 m->timeout_id = 0;
116 }
118 m->next = _messages;
119 _messages = m;
121 _emitChanged();
123 return id;
124 }
126 MessageStack::Message *MessageStack::_discard(MessageStack::Message *m)
127 {
128 Message *next=m->next;
129 if (m->timeout_id) {
130 g_source_remove(m->timeout_id);
131 m->timeout_id = 0;
132 }
133 g_free(m->message);
134 m->message = NULL;
135 m->stack = NULL;
136 delete m;
137 return next;
138 }
140 void MessageStack::_emitChanged() {
141 if (_messages) {
142 _changed_signal.emit(_messages->type, _messages->message);
143 } else {
144 _changed_signal.emit(NORMAL_MESSAGE, NULL);
145 }
146 }
148 gboolean MessageStack::_timeout(gpointer data) {
149 Message *m=reinterpret_cast<Message *>(data);
150 m->timeout_id = 0;
151 m->stack->cancel(m->id);
152 return FALSE;
153 }
155 }
157 /*
158 Local Variables:
159 mode:c++
160 c-file-style:"stroustrup"
161 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
162 indent-tabs-mode:nil
163 fill-column:99
164 End:
165 */
166 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :