You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/konsole/konsole/schema.cpp

635 lines
16 KiB

/* schema.C
**
** Copyright (C) 1998-1999 by Lars Doelle <lars.doelle@on-line.de>
** Copyright (C) 2000 by Adriaan de Groot <groot@kde.org>
**
** A file that defines the objects for storing color schema's
** in konsole. This file is part of the KDE project, see
** http://www.kde.org/
** for more information.
*/
/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/
/* Lars' comments were the following. They are not true anymore: */
/*
** This is new stuff, so no docs yet.
**
** The identifier is the path. `m_numb' is guarantied to range from 0 to
** count-1. Note when reloading the path can be assumed to still identify
** a know schema, while the `m_numb' may vary.
*/
/*
** NUMB IS NOT GUARANTEED ANYMORE. Since schema's may be created and
** destroyed as the list is checked, there may be gaps in the serial
** m_numbers and m_numb may be .. whatever. The default schema always has
** m_number 0, the rest may vary. Use find(int) to find a schema with
** a particular m_number, but remember that find may return NULL.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "schema.h"
#include "tdeapplication.h"
#include <tqdir.h>
#include <tqdatetime.h>
#include <kstandarddirs.h>
#include <tdelocale.h>
#include <tdeconfig.h>
#include <kdebug.h>
typedef TQPtrListIterator<ColorSchema> ColorSchemaListIterator;
// Number all the new color schema's (non-default) from 1.
//
//
int ColorSchema::serial = 1;
// Names of all the colors, to be used as group names
// in the config files. These do not have to be i18n'ed.
//
//
static const char *colornames[TABLE_COLORS] =
{
"fgnormal",
"bgnormal",
"bg0",
"bg1",
"bg2",
"bg3",
"bg4",
"bg5",
"bg6",
"bg7",
"fgintense",
"bgintense",
"bg0i",
"bg1i",
"bg2i",
"bg3i",
"bg4i",
"bg5i",
"bg6i",
"bg7i"
} ;
static const ColorEntry default_table[TABLE_COLORS] =
// The following are almost IBM standard color codes, with some slight
// gamma correction for the dim colors to compensate for bright X screens.
// It contains the 8 ansiterm/xterm colors in 2 intensities.
{
ColorEntry( TQColor(0x00,0x00,0x00), 0, 0 ), ColorEntry(
TQColor(0xFF,0xFF,0xFF), 1, 0 ), // Dfore, Dback
ColorEntry( TQColor(0x00,0x00,0x00), 0, 0 ), ColorEntry(
TQColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
ColorEntry( TQColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry(
TQColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
ColorEntry( TQColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry(
TQColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
ColorEntry( TQColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry(
TQColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
// intensive
ColorEntry( TQColor(0x00,0x00,0x00), 0, 1 ), ColorEntry(
TQColor(0xFF,0xFF,0xFF), 1, 0 ),
ColorEntry( TQColor(0x68,0x68,0x68), 0, 0 ), ColorEntry(
TQColor(0xFF,0x54,0x54), 0, 0 ),
ColorEntry( TQColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry(
TQColor(0xFF,0xFF,0x54), 0, 0 ),
ColorEntry( TQColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry(
TQColor(0xFF,0x54,0xFF), 0, 0 ),
ColorEntry( TQColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry(
TQColor(0xFF,0xFF,0xFF), 0, 0 )
};
ColorSchema::ColorSchema(const TQString& pathname)
:m_fileRead(false)
,lastRead(new TQDateTime())
{
//start with a valid time, aleXXX
*lastRead = TQDateTime::currentDateTime();
TQString fPath = pathname.startsWith("/") ? pathname : locate("data", "konsole/"+pathname);
if (fPath.isEmpty() || !TQFile::exists(fPath))
{
fRelPath = TQString::null;
setDefaultSchema();
}
else
{
fRelPath = pathname;
clearSchema();
/* this is done on demand, see the headers, aleXXX
(void) rereadSchemaFile(); */
}
m_numb = serial++;
}
ColorSchema::ColorSchema()
:m_fileRead(false)
,fRelPath(TQString::null)
,lastRead(0L)
{
setDefaultSchema();
m_numb = 0;
}
ColorSchema::ColorSchema(TDEConfig& c)
:m_fileRead(false)
,fRelPath(TQString::null)
,lastRead(0L)
{
clearSchema();
c.setGroup("SchemaGeneral");
m_title = c.readEntry("Title",i18n("[no title]"));
m_imagePath = c.readEntry("ImagePath");
m_alignment = c.readNumEntry("ImageAlignment",1);
m_useTransparency = c.readBoolEntry("UseTransparency",false);
m_tr_r = c.readNumEntry("TransparentR",0);
m_tr_g = c.readNumEntry("TransparentG",0);
m_tr_b = c.readNumEntry("TransparentB",0);
m_tr_x = c.readDoubleNumEntry("TransparentX",0.0);
for (int i=0; i < TABLE_COLORS; i++)
{
readConfigColor(c,colorName(i),m_table[i]);
}
m_numb = serial++;
}
ColorSchema::~ColorSchema()
{
delete lastRead;
}
void ColorSchema::clearSchema()
{
int i;
for (i = 0; i < TABLE_COLORS; i++)
{
m_table[i].color = TQColor(0,0,0);
m_table[i].transparent = 0;
m_table[i].bold = 0;
}
m_title = i18n("[no title]");
m_imagePath = "";
m_alignment = 1;
m_useTransparency = false;
m_tr_x = 0.0;
m_tr_r = 0;
m_tr_g = 0;
m_tr_b = 0;
}
void ColorSchema::setDefaultSchema()
{
m_numb = 0;
m_title = i18n("Konsole Default");
m_imagePath = ""; // background pixmap
m_alignment = 1; // none
m_useTransparency = false; // not use pseudo-transparency by default
m_tr_r = m_tr_g = m_tr_b = 0; // just to be on the safe side
m_tr_x = 0.0;
for (int i = 0; i < TABLE_COLORS; i++)
{
m_table[i] = default_table[i];
}
}
/* static */ TQString ColorSchema::colorName(int i)
{
if ((i<0) || (i>=TABLE_COLORS))
{
kdWarning() << "Request for color name "
<< i
<< " out of range."
<< endl;
return TQString::null;
}
return TQString(colornames[i]);
}
void ColorSchema::writeConfigColor(TDEConfig& c,
const TQString& name,
const ColorEntry& e) const
{
TDEConfigGroupSaver(&c,name);
c.setGroup(name);
c.writeEntry("Color",e.color);
c.writeEntry("Transparency",(bool) e.transparent);
c.writeEntry("Bold",(bool) e.bold);
}
void ColorSchema::readConfigColor(TDEConfig& c,
const TQString& name,
ColorEntry& e)
{
TDEConfigGroupSaver(&c,name);
c.setGroup(name);
e.color = c.readColorEntry("Color");
e.transparent = c.readBoolEntry("Transparent",false);
e.bold = c.readBoolEntry("Bold",false);
}
void ColorSchema::writeConfig(const TQString& path) const
{
// KONSOLEDEBUG << "Writing schema " << relPath << " to file " << path << endl;
TDEConfig c(path,false,false);
c.setGroup("SchemaGeneral");
c.writeEntry("Title",m_title);
c.writeEntry("ImagePath",m_imagePath);
c.writeEntry("ImageAlignment",m_alignment);
c.writeEntry("UseTransparency",m_useTransparency);
c.writeEntry("TransparentR",m_tr_r);
c.writeEntry("TransparentG",m_tr_g);
c.writeEntry("TransparentB",m_tr_b);
c.writeEntry("TransparentX",m_tr_x);
for (int i=0; i < TABLE_COLORS; i++)
{
writeConfigColor(c,colorName(i),m_table[i]);
}
}
static int random_hue = -1;
bool ColorSchema::rereadSchemaFile()
{
TQString fPath = fRelPath.isEmpty() ? "" : (fRelPath.startsWith("/") ? fRelPath : locate("data", "konsole/"+fRelPath));
if (fPath.isEmpty() || !TQFile::exists(fPath))
return false;
//KONSOLEDEBUG << "Rereading schema file " << fPath << endl;
FILE *sysin = fopen(TQFile::encodeName(fPath),"r");
if (!sysin)
{
int e = errno;
kdWarning() << "Schema file "
<< fPath
<< " could not be opened ("
<< strerror(e)
<< ")"
<< endl;
return false;
}
char line[100];
*lastRead = TQDateTime::currentDateTime();
while (fscanf(sysin,"%80[^\n]\n",line) > 0)
{
if (strlen(line) > 5)
{
if (!strncmp(line,"title",5))
{
m_title = i18n(line+6);
}
if (!strncmp(line,"image",5))
{ char rend[100], path[100]; int attr = 1;
if (sscanf(line,"image %s %s",rend,path) != 2)
continue;
if (!strcmp(rend,"tile" )) attr = 2; else
if (!strcmp(rend,"center")) attr = 3; else
if (!strcmp(rend,"full" )) attr = 4; else
continue;
TQString qline(line);
m_imagePath = locate("wallpaper", qline.mid( qline.find(" ",7)+1 ) );
m_alignment = attr;
}
if (!strncmp(line,"transparency",12))
{ float rx;
int rr, rg, rb;
// Transparency needs 4 parameters: fade strength and the 3
// components of the fade color.
if (sscanf(line,"transparency %g %d %d %d",&rx,&rr,&rg,&rb) != 4)
continue;
m_useTransparency=true;
m_tr_x=rx;
m_tr_r=rr;
m_tr_g=rg;
m_tr_b=rb;
}
if (!strncmp(line,"rcolor",6))
{ int fi,ch,cs,cv,tr,bo;
if(sscanf(line,"rcolor %d %d %d %d %d",&fi,&cs,&cv,&tr,&bo) != 5)
continue;
if (!(0 <= fi && fi <= TABLE_COLORS)) continue;
if (random_hue == -1)
random_hue = (TDEApplication::random()%32) * 11;
ch = random_hue;
if (!(0 <= cs && cs <= 255 )) continue;
if (!(0 <= cv && cv <= 255 )) continue;
if (!(0 <= tr && tr <= 1 )) continue;
if (!(0 <= bo && bo <= 1 )) continue;
m_table[fi].color = TQColor();
m_table[fi].color.setHsv(ch,cs,cv);
m_table[fi].transparent = tr;
m_table[fi].bold = bo;
}
if (!strncmp(line,"color",5))
{ int fi,cr,cg,cb,tr,bo;
if(sscanf(line,"color %d %d %d %d %d %d",&fi,&cr,&cg,&cb,&tr,&bo) != 6)
continue;
if (!(0 <= fi && fi <= TABLE_COLORS)) continue;
if (!(0 <= cr && cr <= 255 )) continue;
if (!(0 <= cg && cg <= 255 )) continue;
if (!(0 <= cb && cb <= 255 )) continue;
if (!(0 <= tr && tr <= 1 )) continue;
if (!(0 <= bo && bo <= 1 )) continue;
m_table[fi].color = TQColor(cr,cg,cb);
m_table[fi].transparent = tr;
m_table[fi].bold = bo;
}
if (!strncmp(line,"sysfg",5))
{ int fi,tr,bo;
if(sscanf(line,"sysfg %d %d %d",&fi,&tr,&bo) != 3)
continue;
if (!(0 <= fi && fi <= TABLE_COLORS)) continue;
if (!(0 <= tr && tr <= 1 )) continue;
if (!(0 <= bo && bo <= 1 )) continue;
m_table[fi].color = kapp->palette().active().text();
m_table[fi].transparent = tr;
m_table[fi].bold = bo;
}
if (!strncmp(line,"sysbg",5))
{ int fi,tr,bo;
if(sscanf(line,"sysbg %d %d %d",&fi,&tr,&bo) != 3)
continue;
if (!(0 <= fi && fi <= TABLE_COLORS)) continue;
if (!(0 <= tr && tr <= 1 )) continue;
if (!(0 <= bo && bo <= 1 )) continue;
m_table[fi].color = kapp->palette().active().base();
m_table[fi].transparent = tr;
m_table[fi].bold = bo;
}
}
}
fclose(sysin);
m_fileRead=true;
return true;
}
bool ColorSchema::hasSchemaFileChanged() const
{
TQString fPath = fRelPath.isEmpty() ? "" : locate("data", "konsole/"+fRelPath);
//KONSOLEDEBUG << "Checking schema file " << fPath << endl;
// The default color schema never changes.
//
//
if (fPath.isEmpty()) return false;
TQFileInfo i(fPath);
if (i.exists())
{
TQDateTime written = i.lastModified();
if (written != (*lastRead))
{
// KONSOLEDEBUG << "Schema file was modified " << written.toString() << endl;
return true;
}
else
{
return false;
}
}
else
{
kdWarning() << "Schema file no longer exists."
<< endl;
return false;
}
}
void ColorSchema::updateLastRead(const TQDateTime& dt)
{
if (lastRead)
{
*lastRead=dt;
}
}
ColorSchemaList::ColorSchemaList() :
TQPtrList<ColorSchema> ()
{
// KONSOLEDEBUG << "Got new color list" << endl;
defaultSchema = new ColorSchema();
append(defaultSchema);
setAutoDelete(true);
ColorSchema::serial=1; // Needed for detached sessions
}
ColorSchemaList::~ColorSchemaList()
{
ColorSchema::serial=1;
}
ColorSchema *ColorSchemaList::find(const TQString& path)
{
if (path.isEmpty())
return find(0);
//KONSOLEDEBUG << "Looking for schema " << path << endl;
//kdDebug(1211)<<"ColorSchema::find() count()=="<<count()<<endl;
ColorSchemaListIterator it(*this);
ColorSchema *c;
if (path.startsWith("/")) {
//KONSOLEDEBUG << " schema given as a full path... " << path << endl;
ColorSchema *newSchema = new ColorSchema(path);
if (newSchema)
append(newSchema);
return newSchema;
}
while ((c=it.current()))
{
if ((*it)->relPath() == path)
return *it;
++it;
}
//list is empty except the default schema
if (count()==1)
{
//kdDebug(1211)<<"ColorSchema::find() empty"<<endl;
ColorSchema *newSchema = new ColorSchema(path);
if (newSchema)
append(newSchema);
return newSchema;
};
return 0;
}
ColorSchema *ColorSchemaList::find(int i)
{
//KONSOLEDEBUG << "Looking for schema m_number " << i << endl;
ColorSchemaListIterator it(*this);
ColorSchema *c;
while ((c=it.current()))
{
if ((*it)->numb() == i) return *it;
++it;
}
return 0;
}
bool ColorSchemaList::updateAllSchemaTimes(const TQDateTime& now)
{
// KONSOLEDEBUG << "Updating time stamps" << endl;
TQStringList list;
TDEGlobal::dirs()->findAllResources("data", "konsole/*.schema", false, true, list);
TQStringList::ConstIterator it;
bool r = false;
for (it=list.begin(); it!=list.end(); ++it)
{
TQString filename=*it;
int j=filename.findRev('/');
if (j>-1)
filename = filename.mid(8);
ColorSchema *sc = find(filename);
if (!sc)
{
// KONSOLEDEBUG << "Found new schema " << filename << endl;
ColorSchema *newSchema = new ColorSchema(filename);
if (newSchema)
{
append(newSchema);
r=true;
}
}
else
{
if (sc->hasSchemaFileChanged())
{
sc->rereadSchemaFile();
}
else
{
sc->updateLastRead(now);
}
}
}
//this has to be done explicitly now, to avoid reading all schema files on startup, aleXXX
// sort();
return r;
}
bool ColorSchemaList::deleteOldSchemas(const TQDateTime& now)
{
// KONSOLEDEBUG << "Checking for vanished schemas" << endl;
ColorSchemaListIterator it(*this);
ColorSchema *p ;
bool r = false;
while ((p=it.current()))
{
if ((p->getLastRead()) && (*(p->getLastRead())) < now)
{
KONSOLEDEBUG << "Found deleted schema "
<< p->relPath()
<< endl;
++it;
remove(p);
r=true;
if (!it.current())
{
break;
}
}
else
{
++it;
}
}
return r;
}
bool ColorSchemaList::checkSchemas()
{
// KONSOLEDEBUG << "Checking for new schemas" << endl;
bool r = false; // Any new schema's found?
// All schemas whose schema files can still be found
// will have their lastRead timestamps updated to
// now.
//
//
TQDateTime now = TQDateTime::currentDateTime();
r = updateAllSchemaTimes(now);
r = r || deleteOldSchemas(now);
return r;
}
int ColorSchemaList::compareItems(TQPtrCollection::Item item1, TQPtrCollection::Item item2)
{
ColorSchema* schema1=(ColorSchema*)item1;
ColorSchema* schema2=(ColorSchema*)item2;
return -1*TQString::compare(schema1->title(),schema2->title());
}