1 //////////////////////////////////////////////////////////////////////
2 //
3 // BeeBEEP Copyright (C) 2010-2021 Marco Mastroddi
4 //
5 // BeeBEEP is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published
7 // by the Free Software Foundation, either version 3 of the License,
8 // or (at your option) any later version.
9 //
10 // BeeBEEP 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 BeeBEEP. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // Author: Marco Mastroddi <marco.mastroddi(AT)gmail.com>
19 //
20 // $Id: EmoticonManager.cpp 1455 2020-12-23 10:17:53Z mastroddi $
21 //
22 //////////////////////////////////////////////////////////////////////
23
24 #include "EmoticonManager.h"
25
26 EmoticonManager* EmoticonManager::mp_instance = Q_NULLPTR;
27
28
EmoticonManager()29 EmoticonManager::EmoticonManager()
30 : m_emoticons(), m_oneCharEmoticons(), m_uniqueKeys(),
31 m_maxTextSize( 2 ), m_favoriteEmoticons(), m_recentEmoticons(),
32 m_recentEmoticonsCount( 48 )
33 {
34 #ifdef BEEBEEP_DEBUG
35 //createEmojiFiles();
36 #endif
37
38 addTextEmoticon();
39 addEmojis();
40 m_uniqueKeys = m_emoticons.uniqueKeys();
41
42 #ifdef BEEBEEP_DEBUG
43 QString s_debug = "";
44 qSort( m_uniqueKeys );
45 foreach( QChar c, m_uniqueKeys )
46 {
47 s_debug.append( c );
48 s_debug.append( " " );
49 }
50 qDebug() << "Emoticon manager has" << m_uniqueKeys.size() << "unique keys:" << qPrintable( s_debug );
51 qDebug() << "Emoticon manager has" << m_oneCharEmoticons.size() << "single char emoticons";
52 #endif
53
54 qDebug() << "Emoticon manager loads" << m_emoticons.size() << "emojis";
55 }
56
addTextEmoticon()57 void EmoticonManager::addTextEmoticon()
58 {
59 addEmoticon( ":)", "1f603", Emoticon::Text );
60 addEmoticon( ":-)", "1f603", Emoticon::Text );
61 addEmoticon( ":p", "1f61c", Emoticon::Text );
62 addEmoticon( ":-p", "1f61c", Emoticon::Text );
63 addEmoticon( ":P", "1f61d", Emoticon::Text );
64 addEmoticon( ":-P", "1f61d", Emoticon::Text );
65 addEmoticon( ":'", "1f62d", Emoticon::Text );
66 addEmoticon( ":'(", "1f62d", Emoticon::Text );
67 addEmoticon( ":D", "1f604", Emoticon::Text );
68 addEmoticon( ":-D", "1f604", Emoticon::Text );
69 addEmoticon( ":@", "1f621", Emoticon::Text );
70 addEmoticon( ":x", "1f61a", Emoticon::Text );
71 addEmoticon( ":*", "1f618", Emoticon::Text );
72 addEmoticon( ":-*", "1f618", Emoticon::Text );
73 addEmoticon( ":z", "1f634", Emoticon::Text );
74 addEmoticon( ":o", "1f628", Emoticon::Text );
75 addEmoticon( ":O", "1f631", Emoticon::Text );
76 addEmoticon( ":|", "1f613", Emoticon::Text );
77 addEmoticon( ":L", "1f60d", Emoticon::Text );
78 addEmoticon( ":w", "whistle", Emoticon::Unknown );
79 addEmoticon( ":$", "bandit", Emoticon::Unknown );
80 addEmoticon( ":!", "wizard", Emoticon::Unknown );
81 addEmoticon( ";)", "1f609", Emoticon::Text );
82 addEmoticon( ";-)", "1f609", Emoticon::Text );
83 addEmoticon( ":(", "1f614", Emoticon::Text );
84 addEmoticon( ":-(", "1f614", Emoticon::Text );
85 addEmoticon( ":T", "1f60b", Emoticon::Text );
86 addEmoticon( ":%", "1f616", Emoticon::Text );
87 addEmoticon( ":\"D", "1f602", Emoticon::Text );
88 addEmoticon( ":"D", "1f602", Emoticon::Text ); // for html
89 addEmoticon( "B)", "1f60e", Emoticon::Text );
90 addEmoticon( "B-)", "1f60e", Emoticon::Text );
91 addEmoticon( "<3", "2764", Emoticon::Text );
92 addEmoticon( "<3", "2764", Emoticon::Text ); // for html
93 addEmoticon( "</3", "1f494", Emoticon::Text );
94 addEmoticon( "</3", "1f494", Emoticon::Text ); // for html
95 addEmoticon( ">_<", "1f616", Emoticon::Text );
96 addEmoticon( ">_<", "1f616", Emoticon::Text ); // for html
97 addEmoticon( "=)", "1f60a", Emoticon::Text );
98 addEmoticon( "}:)", "1f608", Emoticon::Text );
99 addEmoticon( "o:)", "1f608", Emoticon::Text );
100 addEmoticon( "x(", "1f637", Emoticon::Text );
101 addEmoticon( "x-(", "1f637", Emoticon::Text );
102 addEmoticon( "X|", "1f632", Emoticon::Text );
103 addEmoticon( "X-|", "1f632", Emoticon::Text );
104 addEmoticon( "^_^", "1f601", Emoticon::Text );
105 addEmoticon( "O.o", "1f633", Emoticon::Text );
106 addEmoticon( "o.O", "1f633", Emoticon::Text );
107
108 }
109
addEmoticon(const QString & e_text,const QString & e_name,int emoticon_group,int sort_order)110 void EmoticonManager::addEmoticon( const QString& e_text, const QString& e_name, int emoticon_group, int sort_order )
111 {
112 int emoticon_key_size = e_text.size();
113 QChar key_char = e_text.at( 0 );
114
115 m_emoticons.insert( key_char, Emoticon( e_text, e_name, emoticon_group, sort_order ) );
116
117 if( emoticon_key_size == 1 && !m_oneCharEmoticons.contains( key_char ) )
118 m_oneCharEmoticons.append( key_char );
119
120 if( emoticon_key_size > m_maxTextSize )
121 m_maxTextSize = emoticon_key_size;
122 }
123
SortEmoticon(const Emoticon & e1,const Emoticon & e2)124 static bool SortEmoticon( const Emoticon& e1, const Emoticon& e2 )
125 {
126 if( e1.sortOrder() < 0 || e2.sortOrder() < 0 )
127 return e1.name() < e2.name();
128 else
129 return e1.sortOrder() < e2.sortOrder();
130 }
131
textEmoticons(bool remove_names_duplicated) const132 QList<Emoticon> EmoticonManager::textEmoticons( bool remove_names_duplicated ) const
133 {
134 QList<Emoticon> emoticon_list;
135 bool emoticon_to_add = false;
136 QMultiHash<QChar, Emoticon>::const_iterator it = m_emoticons.begin();
137 while( it != m_emoticons.end() )
138 {
139 if( !it.value().isInGroup() )
140 {
141 if( !remove_names_duplicated )
142 emoticon_list << *it;
143 else
144 {
145 emoticon_to_add = true;
146 QList<Emoticon>::iterator it2 = emoticon_list.begin();
147 while( it2 != emoticon_list.end() )
148 {
149 if( (*it2).name() == (*it).name() )
150 {
151 emoticon_to_add = false;
152 break;
153 }
154 ++it2;
155 }
156 if( emoticon_to_add )
157 emoticon_list << *it;
158 }
159 }
160 ++it;
161 }
162
163 std::sort( emoticon_list.begin(), emoticon_list.end(), SortEmoticon );
164
165 return emoticon_list;
166 }
167
emoticonsByGroup(int group_id) const168 QList<Emoticon> EmoticonManager::emoticonsByGroup( int group_id ) const
169 {
170 QList<Emoticon> emoticon_list;
171 QMultiHash<QChar, Emoticon>::const_iterator it = m_emoticons.begin();
172 while( it != m_emoticons.end() )
173 {
174 if( it.value().group() == group_id )
175 emoticon_list << *it;
176 ++it;
177 }
178
179 std::sort( emoticon_list.begin(), emoticon_list.end(), SortEmoticon );
180
181 return emoticon_list;
182 }
183
emoticon(const QString & e_text) const184 Emoticon EmoticonManager::emoticon( const QString& e_text ) const
185 {
186 if( !e_text.isEmpty() )
187 {
188 QChar emoticon_key = e_text.at( 0 );
189 QMultiHash<QChar, Emoticon>::const_iterator it = m_emoticons.find( emoticon_key );
190 while( it != m_emoticons.end() && it.key() == emoticon_key )
191 {
192 if( it.value().textToMatch() == e_text )
193 return it.value();
194 ++it;
195 }
196 }
197 return Emoticon();
198 }
199
emoticonSelected(const QString & e_text)200 Emoticon EmoticonManager::emoticonSelected( const QString& e_text )
201 {
202 if( !e_text.isEmpty() )
203 {
204 QChar emoticon_key = e_text.at( 0 );
205 QMultiHash<QChar, Emoticon>::iterator it = m_emoticons.find( emoticon_key );
206 while( it != m_emoticons.end() && it.key() == emoticon_key )
207 {
208 if( it.value().textToMatch() == e_text )
209 {
210 it.value().addToCount();
211 return it.value();
212 }
213 ++it;
214 }
215 }
216 return Emoticon();
217 }
218
textEmoticon(const QString & e_text) const219 Emoticon EmoticonManager::textEmoticon( const QString& e_text ) const
220 {
221 if( !e_text.isEmpty() )
222 {
223 QChar emoticon_key = e_text.at( 0 );
224 QMultiHash<QChar, Emoticon>::const_iterator it = m_emoticons.find( emoticon_key );
225 while( it != m_emoticons.end() && it.key() == emoticon_key )
226 {
227 if( !it.value().isInGroup() && it.value().textToMatch() == e_text )
228 return it.value();
229 ++it;
230 }
231 }
232 return Emoticon();
233 }
234
emoticonByFile(const QString & e_file_name) const235 Emoticon EmoticonManager::emoticonByFile( const QString& e_file_name ) const
236 {
237 if( !e_file_name.isEmpty() )
238 {
239 QMultiHash<QChar, Emoticon>::const_iterator it = m_emoticons.begin();
240 while( it != m_emoticons.end() )
241 {
242 if( it.value().fileName() == e_file_name && it.value().isInGroup() )
243 return it.value();
244 ++it;
245 }
246 }
247 return Emoticon();
248 }
249
parseEmoticons(const QString & msg,int emoticon_size,bool use_native_emoticons) const250 QString EmoticonManager::parseEmoticons( const QString& msg, int emoticon_size, bool use_native_emoticons ) const
251 {
252 QString s = "";
253 QString text_to_match = "";
254 QChar c;
255 bool parse_emoticons = true;
256
257 for( int pos = 0; pos < msg.size(); pos++ )
258 {
259 c = msg[ pos ];
260
261 if( c.isSpace() )
262 {
263 if( text_to_match.size() > 0 )
264 {
265 s += text_to_match;
266 text_to_match = "";
267 }
268 s += c;
269 parse_emoticons = true;
270 }
271 else if( text_to_match.size() > 0 )
272 {
273 text_to_match += c;
274
275 Emoticon e;
276 if( use_native_emoticons )
277 {
278 Emoticon text_emoticon = textEmoticon( text_to_match );
279 if( text_emoticon.isValid() )
280 {
281 Emoticon native_emoticon = emoticonByFile( text_emoticon.fileName() );
282 if( native_emoticon.isValid() )
283 {
284 s += native_emoticon.textToMatch();
285 text_to_match = "";
286 parse_emoticons = false;
287 }
288 }
289 }
290 else
291 e = emoticon( text_to_match );
292
293 if( e.isValid() )
294 {
295 s += e.toHtml( emoticon_size );
296 text_to_match = "";
297 parse_emoticons = true;
298 }
299 else
300 {
301 if( text_to_match.size() >= m_maxTextSize )
302 {
303 s += text_to_match;
304 text_to_match = "";
305 parse_emoticons = false;
306 }
307 }
308 }
309 else if( m_uniqueKeys.contains( c ) )
310 {
311 if( !use_native_emoticons && isOneCharEmoticon( c ) )
312 {
313 Emoticon e = emoticon( c );
314 if( e.isValid() )
315 {
316 s += e.toHtml( emoticon_size );
317 text_to_match = "";
318 parse_emoticons = true;
319 }
320 }
321 else if( parse_emoticons )
322 {
323 text_to_match = c;
324 parse_emoticons = false;
325 }
326 else
327 s += c;
328 }
329 else
330 {
331 s += c;
332 parse_emoticons = false;
333 }
334 }
335
336 if( text_to_match.size() > 0 )
337 s += text_to_match;
338
339 return s;
340 }
341
setEmoticonCount(const QString & e_text,int e_count)342 bool EmoticonManager::setEmoticonCount( const QString& e_text, int e_count )
343 {
344 if( !e_text.isEmpty() )
345 {
346 QChar emoticon_key = e_text.at( 0 );
347 QMultiHash<QChar, Emoticon>::iterator it = m_emoticons.find( emoticon_key );
348 while( it != m_emoticons.end() && it.key() == emoticon_key )
349 {
350 if( it.value().textToMatch() == e_text )
351 {
352 it.value().setCount( e_count );
353 return true;
354 }
355 ++it;
356 }
357 }
358 return false;
359 }
360
clearFavoriteEmoticons()361 void EmoticonManager::clearFavoriteEmoticons()
362 {
363 m_favoriteEmoticons.clear();
364 QMultiHash<QChar, Emoticon>::iterator it = m_emoticons.begin();
365 while( it != m_emoticons.end() )
366 {
367 it.value().resetCount();
368 ++it;
369 }
370 }
371
favoriteEmoticonsToSort() const372 QList<Emoticon> EmoticonManager::favoriteEmoticonsToSort() const
373 {
374 QList<Emoticon> favorite_emoticons_to_sort;
375 QMultiHash<QChar, Emoticon>::const_iterator it = m_emoticons.begin();
376 while( it != m_emoticons.end() )
377 {
378 if( it.value().count() > 0 )
379 favorite_emoticons_to_sort.append( it.value() );
380 ++it;
381 }
382 return favorite_emoticons_to_sort;
383 }
384
SortFavoriteEmoticon(const Emoticon & fe1,const Emoticon & fe2)385 static bool SortFavoriteEmoticon( const Emoticon& fe1, const Emoticon& fe2 )
386 {
387 if( fe1.count() <= 0 && fe2.count() <= 0 )
388 return SortEmoticon( fe1, fe2 );
389 else
390 return fe1.count() > fe2.count();
391 }
392
loadFavoriteEmoticons(const QStringList & sl)393 int EmoticonManager::loadFavoriteEmoticons( const QStringList& sl )
394 {
395 bool ok = false;
396 m_favoriteEmoticons.clear();
397 if( !sl.isEmpty() )
398 {
399 foreach( QString s, sl )
400 {
401 QStringList pieces = s.split( " " );
402 if( pieces.size() >= 2 )
403 {
404 QString text_to_match = pieces.at( 0 );
405 int emoticon_count = pieces.at( 1 ).toInt( &ok );
406 if( !ok )
407 emoticon_count = 0;
408 setEmoticonCount( text_to_match, emoticon_count );
409 }
410 }
411 }
412
413 m_favoriteEmoticons = favoriteEmoticonsToSort();
414 std::sort( m_favoriteEmoticons.begin(), m_favoriteEmoticons.end(), SortFavoriteEmoticon );
415 return m_favoriteEmoticons.size();
416 }
417
saveFavoriteEmoticons() const418 QStringList EmoticonManager::saveFavoriteEmoticons() const
419 {
420 QList<Emoticon> favorite_emoticon_to_sort = favoriteEmoticonsToSort();
421 QStringList sl;
422 foreach( Emoticon e, favorite_emoticon_to_sort )
423 sl.append( QString( "%1 %2" ).arg( e.textToMatch() ).arg( e.count() ) );
424 return sl;
425 }
426
loadRecentEmoticons(const QStringList & sl)427 int EmoticonManager::loadRecentEmoticons( const QStringList& sl )
428 {
429 m_recentEmoticons.clear();
430 foreach( QString s, sl )
431 {
432 Emoticon e = emoticon( s );
433 if( e.isValid() )
434 {
435 m_recentEmoticons.append( e );
436 if( m_recentEmoticons.size() == m_recentEmoticonsCount )
437 break;
438 }
439 }
440 return m_recentEmoticons.size();
441 }
442
saveRencentEmoticons() const443 QStringList EmoticonManager::saveRencentEmoticons() const
444 {
445 QStringList sl;
446 foreach( Emoticon e, m_recentEmoticons )
447 sl.append( e.textToMatch() );
448 return sl;
449 }
450
addToRecentEmoticons(const Emoticon & e)451 bool EmoticonManager::addToRecentEmoticons( const Emoticon& e )
452 {
453 if( m_recentEmoticons.contains( e ) )
454 return false;
455 m_recentEmoticons.prepend( e );
456 if( m_recentEmoticons.size() > m_recentEmoticonsCount )
457 m_recentEmoticons.removeLast();
458 return true;
459 }
460
createEmojiFiles()461 void EmoticonManager::createEmojiFiles()
462 {
463 QFile emoji_list_file( "../misc/emoji_list.txt" );
464 if( !emoji_list_file.open( QFile::ReadOnly | QFile::Text ) )
465 return;
466
467 QStringList emoji_parts;
468 QString emoji_key;
469 QString emoji_file;
470 QString emoji_line;
471 int sort_order = 0;
472 QList<Emoticon> emoji_list;
473
474 QTextStream text_stream_in( &emoji_list_file );
475 text_stream_in.setCodec( "UTF-8" );
476 while( !text_stream_in.atEnd() )
477 {
478 emoji_line = text_stream_in.readLine();
479 emoji_parts = emoji_line.split( "\t", QString::SkipEmptyParts );
480 if( emoji_parts.count() < 2 )
481 continue;
482
483 emoji_file = emoji_parts.at( 0 ).trimmed();
484 emoji_file.remove( ".png" );
485 emoji_key = emoji_parts.at( 1 ).trimmed();
486 sort_order++;
487
488 emoji_list.append( Emoticon( emoji_key, emoji_file, Emoticon::Unknown, sort_order ) );
489 #ifdef BEEBEEP_DEBUG
490 qDebug() << "Load Emoji: char" << qPrintable( emoji_key ) << "and file" << emoji_file;
491 #endif
492 }
493
494 emoji_list_file.close();
495 qDebug() << emoji_list.size() << "emojis load from list";
496
497 QStringList emoji_group_names;
498 emoji_group_names << "";
499 emoji_group_names << "Text";
500 emoji_group_names << "People";
501 emoji_group_names << "Objects";
502 emoji_group_names << "Nature";
503 emoji_group_names << "Places";
504 emoji_group_names << "Symbols";
505
506 QList<Emoticon>::iterator emoji_it = emoji_list.begin();
507 QString emoji_file_name;
508 while( emoji_it != emoji_list.end() )
509 {
510 for( int i = Emoticon::People; i < Emoticon::NumGroups; i++ )
511 {
512 emoji_file_name = QString( "../src/emojis/" ) + emoji_group_names.at( i ).toLower() + QString( "/" ) + emoji_it->name() + ".png";
513 if( QFile::exists( emoji_file_name ) )
514 {
515 qDebug() << "Found emoji" << qPrintable( emoji_it->textToMatch() ) << "in file" << emoji_file_name;
516 emoji_it->setGroup( i );
517 }
518 }
519 ++emoji_it;
520 }
521
522 int emoji_in_group = 0;
523 int emoji_not_in_group = 0;
524 int emoji_in_twitter = 0;
525 qDebug() << "Checking missed emoji in twitter folder";
526 foreach( Emoticon e, emoji_list )
527 {
528 if( !e.isInGroup() )
529 {
530 emoji_not_in_group++;
531 emoji_file_name = QString( "../src/emojis/twitter/%1.png" ).arg( e.name() );
532 if( QFile::exists( emoji_file_name ) )
533 {
534 qDebug() << qPrintable( QString( "cp twitter/%1.png ." ).arg( e.name() ) );
535 emoji_in_twitter++;
536 }
537 }
538 else
539 emoji_in_group++;
540 }
541
542 qDebug() << "Emoji in group:" << emoji_in_group;
543 qDebug() << "Emoji not in group:" << emoji_not_in_group;
544 qDebug() << "Emoji missed in twitter:" << emoji_in_twitter;
545
546 for( int i = Emoticon::People; i < Emoticon::NumGroups; i++ )
547 {
548 QString emoji_folder_name = QString( "../src/emojis/" ) + emoji_group_names.at( i ).toLower();
549 QDir emoji_folder( emoji_folder_name );
550 QStringList file_list = emoji_folder.entryList( QDir::NoDotAndDotDot | QDir::NoSymLinks );
551 foreach( QString s, file_list )
552 {
553 if( !s.contains( ".png" ) )
554 continue;
555
556 bool emoji_exists = false;
557 foreach( Emoticon e, emoji_list )
558 {
559 if( QString( "%1.png" ).arg( e.name() ) == s )
560 {
561 emoji_exists = true;
562 break;
563 }
564 }
565 if( !emoji_exists )
566 qDebug() << "Emoji not in text list:" << qPrintable( QString( "%1/%2" ).arg( emoji_folder_name ).arg( s ) );
567 }
568 }
569
570 QFile file_to_save( "../src/Emojis.cpp" );
571 if( file_to_save.exists() )
572 file_to_save.remove();
573
574 if( !file_to_save.open( QFile::ReadWrite ) )
575 {
576 qWarning() << file_to_save.fileName() << "is not writeable";
577 return;
578 }
579
580 QTextStream text_stream_out( &file_to_save );
581 text_stream_out.setCodec( "UTF-8" );
582
583 text_stream_out << "//////////////////////////////////////////////////////////////////////\n"
584 "//\n"
585 "// BeeBEEP Copyright (C) 2010-2021 Marco Mastroddi\n"
586 "//\n"
587 "// BeeBEEP is free software: you can redistribute it and/or modify\n"
588 "// it under the terms of the GNU General Public License as published\n"
589 "// by the Free Software Foundation, either version 3 of the License,\n"
590 "// or (at your option) any later version.\n"
591 "//\n"
592 "// BeeBEEP is distributed in the hope that it will be useful,\n"
593 "// but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
594 "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
595 "// GNU General Public License for more details.\n"
596 "//\n"
597 "// You should have received a copy of the GNU General Public License\n"
598 "// along with BeeBEEP. If not, see <http://www.gnu.org/licenses/>.\n"
599 "//\n"
600 "// Author: Marco Mastroddi <marco.mastroddi(AT)gmail.com>\n"
601 "//\n"
602 "// Emojis.cpp is generated in " << QDateTime::currentDateTime().toString( "yyyy-MM-dd hh:mm:ss" ) << "\n"
603 "//\n"
604 "//////////////////////////////////////////////////////////////////////\n"
605 "\n";
606
607 text_stream_out << "#include \"EmoticonManager.h\"\n\n\n";
608 text_stream_out << "void EmoticonManager::addEmojis()\n{\n";
609
610 foreach( Emoticon e, emoji_list )
611 {
612 if( e.isInGroup() )
613 text_stream_out << " addEmoticon( QString::fromUtf8( \"" << e.textToMatch() << "\" ), \"" << e.name() << "\", Emoticon::" << emoji_group_names.at( e.group() ) << ", " << e.sortOrder() << " ); \n";
614 }
615
616 text_stream_out << "\n}\n\n";
617 file_to_save.close();
618
619 QFile emoji_resource_file( "../src/emojis.qrc" );
620
621 if( emoji_resource_file.exists() )
622 emoji_resource_file.remove();
623
624 if( !emoji_resource_file.open( QFile::ReadWrite ) )
625 {
626 qWarning() << emoji_resource_file.fileName() << "is not writeable";
627 return;
628 }
629
630 QTextStream text_stream_resource( &emoji_resource_file );
631
632 text_stream_resource << "<RCC>\n\t<qresource prefix=\"/\">\n";
633
634 foreach( Emoticon e, emoji_list )
635 {
636 if( e.isInGroup() )
637 text_stream_resource << "\t\t<file>emojis/" << emoji_group_names.at( e.group() ).toLower() << "/" << e.name() << ".png</file>\n";
638 }
639
640 text_stream_resource << "\t</qresource>\n</RCC>\n\n";
641 emoji_resource_file.close();
642 }
643