Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 6949)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java	(revision 6970)
@@ -376,5 +376,5 @@
                 return OsmPrimitive.getFilteredList(e.osm.getReferrers(), Way.class).isEmpty();
             }
-            return true;
+            return false;
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(revision 6949)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj	(revision 6970)
@@ -8,5 +8,5 @@
 package org.openstreetmap.josm.gui.mappaint.mapcss.parsergen;
 
-import java.awt.Color;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
@@ -28,44 +28,58 @@
 import org.openstreetmap.josm.tools.ColorHelper;
 import org.openstreetmap.josm.tools.Pair;
-import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.Main;
 
-/*************
- * <pre>
- * Parser definitions
- *
- *                       rule
- *  _______________________|______________________________
- * |                                                      |
- *        selector                      declaration
- *  _________|___________________   _________|____________
- * |                             | |                      |
- *
- * way|z11-12[highway=residential] { color: red; width: 3 }
- *
- *    |_____||___________________|   |_________|
- *       |            |                   |
- *     zoom       condition          instruction
- *
- * more general:
- *
- * way|z13-[a=b][c=d]::subpart, way|z-3[u=v]:closed::subpart2 { p1 : val; p2 : val; }
- *
- * 'val' can be a literal, or an expression like "prop(width, default) + 0.8".
- *
- * {@literal @media} { ... } queries are supported, following http://www.w3.org/TR/css3-mediaqueries/#syntax
- *
- *                               media_query
- *         ___________________________|_______________________________
- *        |                                                           |
- * {@literal @media} all and (min-josm-version: 7789) and (max-josm-version: 7790), all and (user-agent: xyz) { ... }
- *                |______________________|
- *                          |
- *                    media_expression
- * </pre>
+/**
+ * MapCSS parser.
+ *
+ * Contains two independent grammars:
+ * (a) the preprocessor and (b) the main mapcss parser.
+ *
+ * The preprocessor handles @media syntax. Basically this allows
+ * to write one style for different versions of JOSM (or different editors).
+ * When the @media condition is not fulfilled, it should simply skip over
+ * the whole section and not attempt to parse the possibly unknown
+ * grammar. It preserves whitespace and comments, in order to keep the
+ * line and column numbers in the error messages correct for the second pass.
+ *
  */
 
 public class MapCSSParser {
     MapCSSStyleSource sheet;
+    StringBuilder sb;
+
+    /**
+     * Nicer way to refer to a lexical state.
+     */
+    public static enum LexicalState {
+        PREPROCESSOR(0), /* the preprocessor */
+        DEFAULT(2);      /* the main parser */
+        
+        int idx; // the integer, which javacc assigns to this state
+        
+        LexicalState(int idx) {
+            if (!this.name().equals(MapCSSParserTokenManager.lexStateNames[idx])) {
+                throw new RuntimeException();
+            }
+            this.idx = idx;
+        }
+    };
+    
+    /**
+     * Constructor which initializes the parser with a certain lexical state.
+     */
+    public MapCSSParser(InputStream in, String encoding, LexicalState initState) {
+        this(createTokenManager(in, encoding, initState));
+    }
+
+    protected static MapCSSParserTokenManager createTokenManager(InputStream in, String encoding, LexicalState initState) {
+        SimpleCharStream scs;
+        try {
+            scs = new SimpleCharStream(in, encoding, 1, 1);
+        } catch(java.io.UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+        return new MapCSSParserTokenManager(scs, initState.idx);
+    }
 }
 PARSER_END(MapCSSParser)
@@ -73,29 +87,67 @@
 /*************
  * Token definitions
- */
+ *
+ * Lexical states for the preprocessor: <PREPROCESSOR>, <PP_COMMENT>
+ * Lexical states for the main parser: <DEFAULT>, <COMMENT>
+ */
+ 
+<PREPROCESSOR>
+TOKEN:
+{
+    < PP_AND: "and" >
+|   < PP_NOT: "not" >
+|   < PP_MEDIA: "@media" >
+|   < PP_NEWLINECHAR: "\n" | "\r" | "\f" >
+|   < PP_WHITESPACE: " " | "\t" >
+|   < PP_COMMENT_START: "/*" > : PP_COMMENT
+}
+
+<PP_COMMENT>
+TOKEN:
+{
+    < PP_COMMENT_END: "*/" > : PREPROCESSOR
+}
+
+<PP_COMMENT>
+MORE:
+{
+    < ~[] >
+}
 
 <DEFAULT>
 TOKEN [IGNORE_CASE]:
 {
- /* Special keywords in some contexts, ordinary identifiers in other contexts.
-    Don't use the javacc token contexts (except DEFAULT and COMMENT) because
-    they complicate error handling. Instead simply add a parsing rule <code>ident()</code>
-    that parses the IDENT token and in addition all the keyword tokens. */
-    < AND: "and" >
-|   < SET: "set" >
-|   < NOT: "not" >
-|   < MEDIA: "@media" >
-}
-
-<DEFAULT>
+ /* Special keyword in some contexts, ordinary identifier in other contexts.
+    Use the parsing rule <code>ident()</code> to refer to a general
+    identifier, including "set". */
+   < SET: "set" >
+}
+
+<DEFAULT,PREPROCESSOR>
 TOKEN:
 {
     < IDENT: ["a"-"z","A"-"Z","_"] ( ["a"-"z","A"-"Z","_","-","0"-"9"] )* >
 |   < UINT: ["1"-"9"] ( ["0"-"9"] )* >
-|   < UFLOAT: ( ["0"-"9"] )+ ( "." ( ["0"-"9"] )+ )? >
 |   < STRING: "\"" ( [" ","!","#"-"[","]"-"~","\u0080"-"\uFFFF"] | "\\\"" | "\\\\" )*  "\"" >
 |   < #PREDEFINED: "\\" ["d","D","s","S","w","W"] >
 |   < #REGEX_CHAR_WITHOUT_STAR: [" "-")","+"-".","0"-"[","]"-"~","\u0080"-"\uFFFF"] | "\\/" | "\\\\" | "\\[" | "\\]" | "\\+" | "\\." | "\\'" | "\\\"" | <PREDEFINED> >
 |   < REGEX: "/" <REGEX_CHAR_WITHOUT_STAR> ( <REGEX_CHAR_WITHOUT_STAR> | "*" )*  "/" >
+|   < LBRACE: "{" >
+|   < RBRACE: "}" >
+|   < LPAR: "(" >
+|   < RPAR: ")" >
+|   < COLON: ":" >
+}
+
+<PREPROCESSOR>
+TOKEN:
+{
+    < PP_SOMETHING_ELSE : ~[] >
+}
+
+<DEFAULT>
+TOKEN:
+{
+    < UFLOAT: ( ["0"-"9"] )+ ( "." ( ["0"-"9"] )+ )? >
 |   < #H: ["0"-"9","a"-"f","A"-"F"] >
 |   < HEXCOLOR: "#" ( <H><H><H><H><H><H><H><H> | <H><H><H><H><H><H> | <H><H><H> ) >
@@ -103,10 +155,6 @@
 |   < STAR: "*" >
 |   < SLASH: "/" >
-|   < LBRACE: "{" >
-|   < RBRACE: "}" >
 |   < LSQUARE: "[" >
 |   < RSQUARE: "]" >
-|   < LPAR: "(" >
-|   < RPAR: ")" >
 |   < GREATER_EQUAL: ">=" >
 |   < LESS_EQUAL: "<=" >
@@ -116,5 +164,4 @@
 |   < EXCLAMATION: "!" >
 |   < TILDE: "~" >
-|   < COLON: ":" >
 |   < DCOLON: "::" >
 |   < SEMICOLON: ";" >
@@ -147,127 +194,61 @@
 }
 
-int uint() :
-{
-    Token i;
-}
-{
-    i=<UINT> { return Integer.parseInt(i.image); }
-}
-
-int int_() :
-{
-    int i;
-}
-{
-    <MINUS> i=uint() { return -i; } | i=uint() { return i; }
-}
-
-float ufloat() :
-{
-    Token f;
-}
-{
-    ( f=<UFLOAT> | f=<UINT> )
-    { return Float.parseFloat(f.image); }
-}
-
-float float_() :
-{
-    float f;
-}
-{
-    <MINUS> f=ufloat() { return -f; } | f=ufloat() { return f; }
-}
-
-String string() :
-{
-    Token t;
-}
-{
-    t=<STRING>
-    { return t.image.substring(1, t.image.length() - 1).replace("\\\"", "\"").replace("\\\\", "\\"); }
-}
-
-String ident():
-{
-    Token t;
-    String s;
-}
-{
-    ( t=<IDENT> | t=<SET> | t=<NOT> | t=<AND> ) { return t.image; }
-}
-
-String string_or_ident() :
-{
-    Token t;
-    String s;
-}
-{
-    ( s=ident() | s=string() ) { return s; }
-}
-
-String regex() :
-{
-    Token t;
-}
-{
-    t=<REGEX>
-    { return t.image.substring(1, t.image.length() - 1); }
-}
+
+/*************
+ *
+ * Preprocessor parser definitions:
+ *
+ * <pre>
+ *
+ * {@literal @media} { ... } queries are supported, following http://www.w3.org/TR/css3-mediaqueries/#syntax
+ *
+ *                               media_query
+ *         ___________________________|_______________________________
+ *        |                                                           |
+ * {@literal @media} all and (min-josm-version: 7789) and (max-josm-version: 7790), all and (user-agent: xyz) { ... }
+ *                |______________________|
+ *                          |
+ *                    media_expression
+ * </pre>
+ */
+ 
 
 /**
- * white-space
- */
-void s() :
-{
-}
-{
-    ( <S> )?
+ * root method for the preprocessor.
+ */
+String pp_root(MapCSSStyleSource sheet):
+{
+}
+{
+    { sb = new StringBuilder(); this.sheet = sheet; }
+    pp_black_box(true) <EOF>
+    { return sb.toString(); }
 }
 
 /**
- * mix of white-space and comments
- */
-void w() :
-{
-}
-{
-    ( <S> | <COMMENT_START> <COMMENT_END> )*
-}
-
-/**
- * comma delimited list of floats (at least 2, all &gt;= 0)
- */
-List<Float> float_array() :
-{
-    float f;
-    List<Float> fs = new ArrayList<Float>();
-}
-{
-    f=ufloat() { fs.add(f); }
-    (
-        <COMMA> s()
-        f=ufloat() { fs.add(f); }
-    )+
-    {
-        return fs;
-    }
-}
-
-/**
- * root
- */
-void sheet(MapCSSStyleSource sheet):
-{
-    MapCSSRule r;
-}
-{
-    { this.sheet = sheet; }
-    w()
-    rules(true) ( media() w() rules(true) )*
-    <EOF>
-}
-
-void media():
+ * Parse any unknown grammar (black box).
+ *
+ * Only stop when "@media" is encountered and keep track of correct number of
+ * opening and closing curly brackets.
+ *
+ * @param write false if this content should be skipped (@pp_media condition is not fulfilled), true otherwise
+ */
+void pp_black_box(boolean write):
+{
+    Token t;
+}
+{
+    (
+        (t=<PP_AND> | t=<PP_NOT> | t=<UINT> | t=<STRING> | t=<REGEX> | t=<LPAR> | t=<RPAR> | t=<COLON> | t=<IDENT> | t=<PP_SOMETHING_ELSE>) { if (write) sb.append(t.image); }
+        |
+            pp_w1()
+        |
+            pp_media()
+        |
+            t=<LBRACE> { if (write) sb.append(t.image); } pp_black_box(write) t=<RBRACE> { if (write) sb.append(t.image); }
+    )*
+}
+
+void pp_media():
 {
     boolean pass = false;
@@ -276,14 +257,14 @@
 }
 {
-    <MEDIA> w()
-    ( q=media_query() { pass = pass || q; empty = false; }
-        ( <COMMA> w() q=media_query() { pass = pass || q; } )*
+    <PP_MEDIA> pp_w()
+    ( q=pp_media_query() { pass = pass || q; empty = false; }
+        ( <COMMA> pp_w() q=pp_media_query() { pass = pass || q; } )*
     )?
-    <LBRACE> w()
-    rules(empty || pass)
+    <LBRACE>
+    pp_black_box(empty || pass)
     <RBRACE>
 }
 
-boolean media_query():
+boolean pp_media_query():
 {
     Token t;
@@ -294,11 +275,11 @@
 }
 {
-    ( <NOT> { invert = true; } w() )?
-    (
-            t=<IDENT> { mediatype = t.image.toLowerCase(); } w()
-            ( <AND> w() e=media_expression() { pass = pass && e; } w() )*
-        |
-            e=media_expression() { pass = pass && e; } w()
-            ( <AND> w() e=media_expression() { pass = pass && e; } w() )*
+    ( <PP_NOT> { invert = true; } pp_w() )?
+    (
+            t=<IDENT> { mediatype = t.image.toLowerCase(); } pp_w()
+            ( <PP_AND> pp_w() e=pp_media_expression() { pass = pass && e; } pp_w() )*
+        |
+            e=pp_media_expression() { pass = pass && e; } pp_w()
+            ( <PP_AND> pp_w() e=pp_media_expression() { pass = pass && e; } pp_w() )*
     )
     { 
@@ -310,5 +291,12 @@
 }
 
-boolean media_expression():
+/**
+ * Parse an @media expression.
+ *
+ * The parsing rule {@link #literal()} from the main mapcss parser is reused here.
+ *
+ * @return true if the condition is fulfilled
+ */
+boolean pp_media_expression():
 {
     Token t;
@@ -317,16 +305,176 @@
 }
 {
-    <LPAR> w() t=<IDENT> { feature = t.image; } w() ( <COLON> w() val=literal() )? <RPAR>
+    <LPAR> pp_w() t=<IDENT> { feature = t.image; } pp_w() ( <COLON> pp_w() val=literal() )? <RPAR>
     { return this.sheet.evalMediaExpression(feature, val); }
 }
 
-void rules(boolean add):
+void pp_w1():
+{
+    Token t;
+}
+{
+    t=<PP_NEWLINECHAR> { sb.append(t.image); }
+        | 
+    t=<PP_WHITESPACE> { sb.append(t.image); }
+        |
+    t=<PP_COMMENT_START> { sb.append(t.image); } t=<PP_COMMENT_END> { sb.append(t.image); }
+}
+
+void pp_w():
+{
+}
+{
+ ( pp_w1() )*
+}
+
+/*************
+ *
+ * Parser definition for the main MapCSS parser:
+ *
+ * <pre>
+ *
+ *                       rule
+ *  _______________________|______________________________
+ * |                                                      |
+ *        selector                      declaration
+ *  _________|___________________   _________|____________
+ * |                             | |                      |
+ *
+ * way|z11-12[highway=residential] { color: red; width: 3 }
+ *
+ *    |_____||___________________|   |_________|
+ *       |            |                   |
+ *     zoom       condition          instruction
+ *
+ * more general:
+ *
+ * way|z13-[a=b][c=d]::subpart, way|z-3[u=v]:closed::subpart2 { p1 : val; p2 : val; }
+ *
+ * 'val' can be a literal, or an expression like "prop(width, default) + 0.8".
+ *
+ * </pre>
+ */
+
+int uint() :
+{
+    Token i;
+}
+{
+    i=<UINT> { return Integer.parseInt(i.image); }
+}
+
+int int_() :
+{
+    int i;
+}
+{
+    <MINUS> i=uint() { return -i; } | i=uint() { return i; }
+}
+
+float ufloat() :
+{
+    Token f;
+}
+{
+    ( f=<UFLOAT> | f=<UINT> )
+    { return Float.parseFloat(f.image); }
+}
+
+float float_() :
+{
+    float f;
+}
+{
+    <MINUS> f=ufloat() { return -f; } | f=ufloat() { return f; }
+}
+
+String string() :
+{
+    Token t;
+}
+{
+    t=<STRING>
+    { return t.image.substring(1, t.image.length() - 1).replace("\\\"", "\"").replace("\\\\", "\\"); }
+}
+
+String ident():
+{
+    Token t;
+    String s;
+}
+{
+    ( t=<IDENT> | t=<SET> ) { return t.image; }
+}
+
+String string_or_ident() :
+{
+    Token t;
+    String s;
+}
+{
+    ( s=ident() | s=string() ) { return s; }
+}
+
+String regex() :
+{
+    Token t;
+}
+{
+    t=<REGEX>
+    { return t.image.substring(1, t.image.length() - 1); }
+}
+
+/**
+ * white-space
+ */
+void s() :
+{
+}
+{
+    ( <S> )?
+}
+
+/**
+ * mix of white-space and comments
+ */
+void w() :
+{
+}
+{
+    ( <S> | <COMMENT_START> <COMMENT_END> )*
+}
+
+/**
+ * comma delimited list of floats (at least 2, all &gt;= 0)
+ */
+List<Float> float_array() :
+{
+    float f;
+    List<Float> fs = new ArrayList<Float>();
+}
+{
+    f=ufloat() { fs.add(f); }
+    (
+        <COMMA> s()
+        f=ufloat() { fs.add(f); }
+    )+
+    {
+        return fs;
+    }
+}
+
+/**
+ * entry point for the main parser
+ */
+void sheet(MapCSSStyleSource sheet):
 {
     MapCSSRule r;
 }
 {
+    { this.sheet = sheet; }
+    w()
     (
         try {
-            r=rule() { if (add && r != null) { sheet.rules.add(r); } } w()
+            r=rule() { if (r != null) { sheet.rules.add(r); } } w()
         } catch (MapCSSException mex) {
             error_skipto(RBRACE, mex);
@@ -337,4 +485,5 @@
         }
     )*
+    <EOF>
 }
 
@@ -663,5 +812,4 @@
 Expression function() :
 {
-    Token tmp;
     Expression arg;
     String name;
@@ -681,12 +829,12 @@
 Object literal() :
 {
-    String val;
-    Token t, t2;
+    String val, pref;
+    Token t;
     float f;
 }
 {
         LOOKAHEAD(2)
-        t2=<IDENT> t=<HEXCOLOR>
-        { return Main.pref.getColor("mappaint." + (sheet == null ? "MapCSS" : sheet.title) + "." + t2.image, ColorHelper.html2color(t.image)); }
+        pref=ident() t=<HEXCOLOR>
+        { return Main.pref.getColor("mappaint." + (sheet == null ? "MapCSS" : sheet.title) + "." + pref, ColorHelper.html2color(t.image)); }
     |
         t=<IDENT> { return new Keyword(t.image); }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 6949)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java	(revision 6970)
@@ -78,6 +78,13 @@
             InputStream in = getSourceInputStream();
             try {
-                MapCSSParser parser = new MapCSSParser(in, "UTF-8");
+                // evaluate @media { ... } blocks
+                MapCSSParser preprocessor = new MapCSSParser(in, "UTF-8", MapCSSParser.LexicalState.PREPROCESSOR);
+                String mapcss = preprocessor.pp_root(this);
+                
+                // do the actual mapcss parsing
+                InputStream in2 = new ByteArrayInputStream(mapcss.getBytes(Utils.UTF_8));
+                MapCSSParser parser = new MapCSSParser(in2, "UTF-8", MapCSSParser.LexicalState.DEFAULT);
                 parser.sheet(this);
+                
                 loadMeta();
                 loadCanvas();
