1
/****************************************************************************************
2
 * Copyright (c) 2004 Shintaro Matsuoka <shin@shoegazed.org>                            *
3
 * Copyright (c) 2006 Martin Aumueller <aumuell@reserv.at>                              *
4
 *                                                                                      *
5
 * This program is free software; you can redistribute it and/or modify it under        *
6
 * the terms of the GNU General Public License as published by the Free Software        *
7
 * Foundation; either version 2 of the License, or (at your option) any later           *
8
 * version.                                                                             *
9
 *                                                                                      *
10
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
11
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
12
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
13
 *                                                                                      *
14
 * You should have received a copy of the GNU General Public License along with         *
15
 * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
16
 ****************************************************************************************/
17
 
18
#ifndef AMAROK_QSTRINGX_H
19
#define AMAROK_QSTRINGX_H
20
21
#include <qglobal.h>
22
#include <QRegExp>
23
#include <QString>
24
#include <QStringList>
25
#include <qmap.h>
26
27
namespace Amarok
28
{
29
30
class QStringx : public QString
31
{
32
public:
33
    QStringx() {}
34
    QStringx( QChar ch ) : QString( ch ) {}
35
    QStringx( const QString& s ) : QString( s ) {}
36
    QStringx( const QByteArray& ba ) : QString( ba ) {}
37
    QStringx( const QChar* unicode, uint length ) : QString( unicode, length ) {}
38
    QStringx( const char* str ) : QString( str ) {}
39
    virtual ~QStringx() {}
40
41
    // the numbers following % obviously are not taken into account
42
    QString args( const QStringList& args ) const
43
    {
44
        const QStringList text = (*this).split( QRegExp( "%\\d+" ), QString::KeepEmptyParts );
45
46
        QList<QString>::ConstIterator itrText = text.constBegin();
47
        QList<QString>::ConstIterator itrArgs = args.constBegin();
48
        QList<QString>::ConstIterator endText = text.constEnd();
49
        QList<QString>::ConstIterator endArgs = args.constEnd();
50
        QString merged = (*itrText);
51
        ++itrText;
52
        while( itrText != endText && itrArgs != endArgs )
53
        {
54
            merged += (*itrArgs) + (*itrText);
55
            ++itrText;
56
            ++itrArgs;
57
        }
58
59
        Q_ASSERT( itrText == text.end() || itrArgs == args.end() );
60
61
        return merged;
62
    }
63
64
    // %something gets replaced by the value corresponding to key "something" in args
65
    QString namedArgs( const QMap<QString, QString> &args, bool opt=false ) const
66
    {
67
        QRegExp rxArg( "%[a-zA-Z0-9]+" );
68
69
        QString result;
70
        int start = 0;
71
        for( int pos = rxArg.indexIn( *this );
72
                pos != -1;
73
                pos = rxArg.indexIn( *this, start ) )
74
        {
75
            int len = rxArg.matchedLength();
76
            QString p = rxArg.capturedTexts()[0].mid(1, len-1);
77
78
            result += mid( start, pos-start );
79
            if( !args[p].isEmpty() )
80
                result += args[p];
81
            else if( opt )
82
                return QString();
83
84
            start = pos + len;
85
        }
86
        result += mid( start );
87
88
        return result;
89
    }
90
91
    // %something gets replaced by the value corresponding to key "something" in args,
92
    // however, if key "something" is not available,
93
    // then replace everything within surrounding { } by an empty string
94
    QString namedOptArgs( const QMap<QString, QString> &args ) const
95
    {
96
        QRegExp rxOptArg( "%[a-zA-Z0-9]+" );
97
98
        QString result = *this;
99
        for( int pos = rxOptArg.indexIn( result );
100
                pos != -1;
101
                pos = rxOptArg.indexIn( result ) )
102
        {
103
            int len = rxOptArg.matchedLength();
104
105
            // get bracket positions
106
            int leftMatchPos = pos;
107
            int rightMatchPos = pos + len - 1;
108
            int bracketCount = 1;
109
            int i = leftMatchPos;
110
111
            // find position of matching '{' on the left side
112
            while( ( i > 0 ) && ( bracketCount != 0 ) )
113
            {
114
                i--;
115
                if( result.at( i ) == '{' )
116
                    bracketCount--;
117
                else if( result.at( i ) == '}' )
118
                    bracketCount++;
119
            }
120
121
            if( bracketCount == 0 ) // syntax seems to be correct
122
                leftMatchPos = i;
123
124
            bracketCount = 1;
125
            i = rightMatchPos;
126
            // find position of matching '}' on the right side
127
            while( ( i < result.size()-1 ) && ( bracketCount != 0 ) )
128
            {
129
                i++;
130
                if( result.at( i ) == '}' )
131
                    bracketCount--;
132
                else if( result.at( i ) == '{' )
133
                    bracketCount++;
134
            }
135
136
            if( bracketCount == 0 ) // syntax seems to be correct
137
                rightMatchPos = i;
138
139
            if( !args.contains( rxOptArg.capturedTexts()[0].mid( 1, len ) ) ) // remove section
140
                result.remove( leftMatchPos, rightMatchPos - leftMatchPos + 1 );
141
            else // we have a map entry
142
            {
143
                if( result.at( rightMatchPos ) == '}' )
144
                    result.remove( rightMatchPos, 1 );
145
                if( result.at( leftMatchPos ) == '{' )
146
                {
147
                    result.remove( leftMatchPos, 1 );
148
                    pos--;
149
                }
150
151
                result.replace( pos, len, args[ rxOptArg.capturedTexts()[0].mid( 1, len-1 ) ] );
152
            }
153
        }
154
        return result;
155
    }
156
};
157
158
} // namespace Amarok
159
160
#endif // AMAROK_QSTRINGX_H