1 /* Copyright (C) 2011-2013 by rickyrockrat <gpib at rickyrockrat dot net>
2  *
3  * This file is part of Parcellite.
4  *
5  * Parcellite 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  * Parcellite 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 /** \file ******************************************************************
20 \n\b File:        attr_list.c
21 \n\b Author:      Doug Springer
22 \n\b Company:     DNK Designs Inc.
23 \n\b Date:        01/09/2013  9:22 pm
24 \n\b Description: General attribute changing and list manipulation routines.
25 */ /************************************************************************
26 */
27 
28 #include "parcellite.h"
29 /***************************************************************************/
30 /** Get the underline on the given lable, or allocate new one.
31 \n\b Arguments:
32 \n\b Returns:
33 ****************************************************************************/
get_underline_attr(GtkLabel * label)34 PangoAttrInt *get_underline_attr(GtkLabel *label)
35 {
36 	PangoAttrList *attrs=gtk_label_get_attributes (label);
37 	PangoAttribute *attr;
38 
39   if (NULL == attrs){/**no existing list. Add one  */
40 		/*attrs = pango_attr_list_new ();
41 		attr=NULL;*/
42 		return(NULL);
43 	}else{ /**grab attribte, if there is one.  */
44 		PangoAttrIterator* iter;
45 		iter=pango_attr_list_get_iterator(attrs);
46 		attr=pango_attr_iterator_get (iter,PANGO_ATTR_UNDERLINE);
47 		pango_attr_iterator_destroy(iter);
48 	}
49 	return (PangoAttrInt *)attr;
50 }
51 /***************************************************************************/
52 /** Returns 0 if not strikethrough, 1 if it is.
53 \n\b Arguments:
54 \n\b Returns:
55 ****************************************************************************/
is_underline(GtkLabel * label)56 gboolean is_underline(GtkLabel *label)
57 {
58 	PangoAttrInt *strike=get_underline_attr(label);
59 	if(NULL == strike || strike->value == FALSE)
60 		return FALSE;
61 	return TRUE;
62 }
63 
64 /***************************************************************************/
65 /** Set the strike through on/off. Create a new strike through and/or attr
66 list.
67 \n\b Arguments:
68 \n\b Returns:
69 ****************************************************************************/
set_underline(GtkLabel * label,gboolean mode)70 void set_underline(GtkLabel *label, gboolean mode)
71 {
72 	PangoAttrInt *strike;
73 	PangoAttrList *attrs;
74 
75 	strike=get_underline_attr(label);
76 	if(NULL ==(attrs=gtk_label_get_attributes (label)) )
77 		attrs = pango_attr_list_new ();
78 
79 	/** printf("strike=%p attrs=%p\n",strike,attrs);	fflush(NULL);*/
80 	if(NULL ==strike || strike->value != mode){
81 		PangoAttribute *attr=pango_attr_underline_new(mode);
82 		pango_attr_list_change (attrs, attr);
83 		gtk_label_set_attributes (label, attrs);
84 	}
85 }
86 /***************************************************************************/
87 /** Get the strikethrough on the given lable, or allocate new one.
88 \n\b Arguments:
89 \n\b Returns:
90 ****************************************************************************/
get_strikethrough_attr(GtkLabel * label)91 PangoAttrInt *get_strikethrough_attr(GtkLabel *label)
92 {
93 	PangoAttrList *attrs=gtk_label_get_attributes (label);
94 	PangoAttribute *attr;
95 
96   if (NULL == attrs){/**no existing list. Add one  */
97 		/*attrs = pango_attr_list_new ();
98 		attr=NULL;*/
99 		return(NULL);
100 	}else{ /**grab attribte, if there is one.  */
101 		PangoAttrIterator* iter;
102 		iter=pango_attr_list_get_iterator(attrs);
103 		attr=pango_attr_iterator_get (iter,PANGO_ATTR_STRIKETHROUGH);
104 		pango_attr_iterator_destroy(iter);
105 	}
106 	if(0 && NULL == attr){ /**No existing strikethrough. Add the attribute.  */
107 		attr=pango_attr_strikethrough_new(FALSE);
108 		pango_attr_list_change (attrs, attr);
109 		gtk_label_set_attributes (label, attrs);
110 	}
111 	return (PangoAttrInt *)attr;
112 }
113 
114 /***************************************************************************/
115 /** Returns 0 if not strikethrough, 1 if it is.
116 \n\b Arguments:
117 \n\b Returns:
118 ****************************************************************************/
is_strikethrough(GtkLabel * label)119 gboolean is_strikethrough(GtkLabel *label)
120 {
121 	PangoAttrInt *strike=get_strikethrough_attr(label);
122 	if(NULL == strike || strike->value == FALSE)
123 		return FALSE;
124 	return TRUE;
125 }
126 
127 /***************************************************************************/
128 /** Set the strike through on/off. Create a new strike through and/or attr
129 list.
130 \n\b Arguments:
131 \n\b Returns:
132 ****************************************************************************/
set_strikethrough(GtkLabel * label,gboolean mode)133 void set_strikethrough(GtkLabel *label, gboolean mode)
134 {
135 	PangoAttrInt *strike;
136 	PangoAttrList *attrs;
137 
138 	strike=get_strikethrough_attr(label);
139 	if(NULL ==(attrs=gtk_label_get_attributes (label)) )
140 		attrs = pango_attr_list_new ();
141 
142 	/** printf("strike=%p attrs=%p\n",strike,attrs);	fflush(NULL);*/
143 	if(NULL ==strike || strike->value != mode){
144 		PangoAttribute *attr=pango_attr_strikethrough_new(mode);
145 		pango_attr_list_change (attrs, attr);
146 		gtk_label_set_attributes (label, attrs);
147 	}
148 }
149 /***************************************************************************/
150 /** Find the item in the delete list.
151 \n\b Arguments:
152 \n\b Returns:
153 ****************************************************************************/
find_h_item(GList * list,GtkWidget * w,GList * e)154 GList *find_h_item(GList *list,GtkWidget *w, GList *e)
155 {
156 	GList *i;
157 	for ( i=list; NULL != i; i=i->next){
158 		struct s_item_info *it=(struct s_item_info *)i->data;
159 		if( (NULL == w || it->item ==w) && it->element==e){/**found it  */
160 			  /*printf("Found %p\n",i);	fflush(NULL); */
161 			return i;
162 		}
163 	}
164 	return NULL;
165 }
166 
167 /***************************************************************************/
168 /** Add an item to the history delete list.
169 \n\b Arguments:
170 \n\b Returns:
171 ****************************************************************************/
add_h_item(struct history_info * h,GtkWidget * w,GList * element,gint which)172 void add_h_item(struct history_info *h, GtkWidget *w, GList* element, gint which)
173 {
174 	GList *ele;
175 	GList *op=NULL;
176 	switch(which){
177 		case OPERATE_DELETE:
178 			op=h->delete_list;
179 			break;
180 		case OPERATE_PERSIST:
181 			op=h->persist_list;
182 			break;
183 		default:
184 			g_fprintf(stderr,"Invalid list '%d'\n",which);
185 			return;
186 	}
187 	struct s_item_info *i;
188 	if(NULL == (ele=find_h_item(op,w,element) ) ){
189 		if(NULL != (i=g_malloc(sizeof(struct s_item_info)) ) ){
190 			i->item=w;
191 			i->element=element;
192 			switch(which){
193 				case OPERATE_DELETE:
194 					h->delete_list=g_list_prepend(op,(gpointer)i);
195 					break;
196 				case OPERATE_PERSIST:
197 					h->persist_list=g_list_prepend(op,(gpointer)i);
198 					break;
199 			}
200 
201 			/*g_printf("Added w %p e %p %p\n",w,element,h->delete_list);	fflush(NULL); */
202 		}/*else g_fprintf(stderr,"%s: NULL allocating element for delete list!\n",__func__);	 */
203 	}/*else g_printf("found element??\n"); */
204 }
205 
206 /***************************************************************************/
207 /** Delete an item from the history delete list.
208 h->delete_list is a GList. The data points to a struct s_item_info, which
209 contains a widget and an element - these latter two are part of the history
210 menu, so we just need to de-allocate the delete_list structure, and delete it
211 from the list.
212 \n\b Arguments:
213 \n\b Returns:
214 ****************************************************************************/
rm_h_item(struct history_info * h,GtkWidget * w,GList * element,gint which)215 void rm_h_item(struct history_info *h, GtkWidget *w, GList* element, gint which)
216 {
217 	GList *i;
218 	GList *op;
219 	switch(which){
220 		case OPERATE_DELETE:
221 			op=h->delete_list;
222 			break;
223 		case OPERATE_PERSIST:
224 			op=h->persist_list;
225 			break;
226 	}
227 	if(NULL != (i=find_h_item(op,w,element) ) ){
228 		/*printf("Freeing %p\n",i->data); */
229 		g_free(i->data);
230 		i->data=NULL;
231 		/*fflush(NULL); */
232 	  switch(which){
233 			case OPERATE_DELETE:
234 				h->delete_list=g_list_delete_link(op,i);
235 				break;
236 			case OPERATE_PERSIST:
237 				h->persist_list=g_list_delete_link(op,i);
238 				break;
239 		}
240 		/** printf("Removed %p\n",i);	fflush(NULL);*/
241 	}
242 
243 }
244 
245 
246 /***************************************************************************/
247 /** .
248 \n\b Arguments:
249 \n\b Returns:
250 ****************************************************************************/
remove_deleted_items(struct history_info * h)251 void remove_deleted_items(struct history_info *h)
252 {
253 	if(NULL != h && NULL != h->delete_list){/**have a list of items to delete.  */
254 		GList *i;
255 		g_mutex_lock(hist_lock);
256 		/*g_print("Deleting items\n"); */
257 		for (i=h->delete_list; NULL != i; i=i->next){
258 			struct s_item_info *it=(struct s_item_info *)i->data;
259 			/*printf("Free %p.. '%s' ",it->element->data,(char *)(it->((struct history_item *(element->data))->text))); */
260 			g_free(it->element->data);
261 			it->element->data=NULL;
262 			history_list = g_list_delete_link(history_list, it->element);
263 			/** printf("Free %p\n",it);
264 			fflush(NULL);*/
265 			g_free(it);
266 		}
267 		h->delete_list=NULL;
268 		g_mutex_unlock(hist_lock);
269 		if (get_pref_int32("save_history"))
270 		  save_history();
271 	}
272 }
273 /***************************************************************************/
274 /** Handle marking for history window. Also manages adding/removing from
275 the delete list, which gets called when the history window closes.
276 \n\b Arguments:
277 \n\b Returns:
278 ****************************************************************************/
handle_marking(struct history_info * h,GtkWidget * w,gint index,gint which)279 void handle_marking(struct history_info *h, GtkWidget *w, gint index, gint which)
280 {
281   GtkLabel *l=(GtkLabel *)(gtk_bin_get_child((GtkBin*)w)) ;
282 	GList* element = g_list_nth(history_list, index);
283 	if(OPERATE_DELETE == which){
284 		if(is_strikethrough(l)){ /**un-highlight  */
285 			set_strikethrough(l,FALSE);
286 			rm_h_item(h,w,element,OPERATE_DELETE);
287 		}
288 		else {
289 			/*g_printf("marking %p ",element); */
290 			set_strikethrough(l,TRUE);
291 			add_h_item(h,w,element,OPERATE_DELETE);
292 		}
293 	}else if(OPERATE_PERSIST == which){
294 		struct history_item *c=(struct history_item *)(element->data);
295 		if(NULL !=c){
296 			if(c->flags & CLIP_TYPE_PERSISTENT)
297 				c->flags&=~(CLIP_TYPE_PERSISTENT);
298 			else
299 				c->flags|=CLIP_TYPE_PERSISTENT;
300 			h->change_flag|=CLIP_TYPE_PERSISTENT;
301 			}
302 		if(is_underline(l)){ /**un-highlight  */
303 			set_underline(l,FALSE);
304 			rm_h_item(h,w,element,OPERATE_PERSIST);
305 		}
306 		else {
307 			set_underline(l,TRUE);
308 			add_h_item(h,w,element,OPERATE_PERSIST);
309 		}
310 	}
311 
312 }
313 
314