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 <glib/gstrfuncs.h>
13 #include "message-stack.h"
15 namespace Inkscape {
17 MessageStack::MessageStack()
18 : _messages(NULL), _next_id(1)
19 {
20 }
22 MessageStack::~MessageStack()
23 {
24 while (_messages) {
25 _messages = _discard(_messages);
26 }
27 }
29 MessageId MessageStack::push(MessageType type, gchar const *message) {
30 return _push(type, 0, message);
31 }
33 MessageId MessageStack::pushF(MessageType type, gchar const *format, ...)
34 {
35 va_list args;
36 va_start(args, format);
37 MessageId id=pushVF(type, format, args);
38 va_end(args);
39 return id;
40 }
42 MessageId MessageStack::pushVF(MessageType type, gchar const *format, va_list args)
43 {
44 MessageId id;
45 gchar *message=g_strdup_vprintf(format, args);
46 id = push(type, message);
47 g_free(message);
48 return id;
49 }
51 void MessageStack::cancel(MessageId id) {
52 Message **ref;
53 for ( ref = &_messages ; *ref ; ref = &(*ref)->next ) {
54 if ( (*ref)->id == id ) {
55 *ref = _discard(*ref);
56 _emitChanged();
57 break;
58 }
59 }
60 }
62 MessageId MessageStack::flash(MessageType type, gchar const *message) {
63 switch (type) {
64 case INFORMATION_MESSAGE: // stay rather long so as to seem permanent, but eventually disappear
65 return _push(type, 6000 + 80*strlen(message), message);
66 break;
67 case ERROR_MESSAGE: // pretty important stuff, but temporary
68 return _push(type, 4000 + 60*strlen(message), message);
69 break;
70 case WARNING_MESSAGE: // a bit less important than error
71 return _push(type, 2000 + 40*strlen(message), message);
72 break;
73 case IMMEDIATE_MESSAGE: // same length as normal, higher priority
74 return _push(type, 1000 + 20*strlen(message), message);
75 break;
76 case NORMAL_MESSAGE: // something ephemeral
77 default:
78 return _push(type, 1000 + 20*strlen(message), message);
79 break;
80 }
81 }
83 MessageId MessageStack::flashF(MessageType type, gchar const *format, ...) {
84 va_list args;
85 va_start(args, format);
86 MessageId id = flashVF(type, format, args);
87 va_end(args);
88 return id;
89 }
91 MessageId MessageStack::flashVF(MessageType type, gchar const *format, va_list args)
92 {
93 gchar *message=g_strdup_vprintf(format, args);
94 MessageId id = flash(type, message);
95 g_free(message);
96 return id;
97 }
99 MessageId MessageStack::_push(MessageType type, guint lifetime, gchar const *message)
100 {
101 Message *m=new Message;
102 MessageId id=_next_id++;
104 m->stack = this;
105 m->id = id;
106 m->type = type;
107 m->message = g_strdup(message);
109 if (lifetime) {
110 m->timeout_id = g_timeout_add(lifetime, &MessageStack::_timeout, m);
111 } else {
112 m->timeout_id = 0;
113 }
115 m->next = _messages;
116 _messages = m;
118 _emitChanged();
120 return id;
121 }
123 MessageStack::Message *MessageStack::_discard(MessageStack::Message *m)
124 {
125 Message *next=m->next;
126 if (m->timeout_id) {
127 g_source_remove(m->timeout_id);
128 m->timeout_id = 0;
129 }
130 g_free(m->message);
131 m->message = NULL;
132 m->stack = NULL;
133 delete m;
134 return next;
135 }
137 void MessageStack::_emitChanged() {
138 if (_messages) {
139 _changed_signal.emit(_messages->type, _messages->message);
140 } else {
141 _changed_signal.emit(NORMAL_MESSAGE, NULL);
142 }
143 }
145 gboolean MessageStack::_timeout(gpointer data) {
146 Message *m=reinterpret_cast<Message *>(data);
147 m->timeout_id = 0;
148 m->stack->cancel(m->id);
149 return FALSE;
150 }
152 }
154 /*
155 Local Variables:
156 mode:c++
157 c-file-style:"stroustrup"
158 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
159 indent-tabs-mode:nil
160 fill-column:99
161 End:
162 */
163 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :