├── README.md ├── images ├── body-bg.jpg ├── body-bg.png ├── download-button.png ├── github-button.png ├── header-bg.jpg ├── highlight-bg.jpg ├── hr.png ├── octocat-icon.png ├── sidebar-bg.jpg ├── tar-gz-icon.png └── zip-icon.png ├── index.html ├── javascripts └── main.js ├── params.json ├── plugin_code_examples ├── 01_hello_world │ ├── 01_hello_world.zip │ ├── README.md │ ├── qgis_hello_world.cpp │ ├── qgis_hello_world.h │ └── qgis_hello_world.pro ├── 02_map_tool_driller_part1 │ ├── 02_map_tool_driller_part1.zip │ ├── README.md │ ├── maptooldriller.cpp │ ├── maptooldriller.h │ ├── qgis_maptooldriller.cpp │ ├── qgis_maptooldriller.h │ └── qgis_maptooldriller.pro ├── 03_map_tool_driller_part2 │ ├── 03_map_tool_driller_part2.zip │ ├── README.md │ ├── maptooldriller.cpp │ ├── maptooldriller.h │ ├── qgis_maptooldriller.cpp │ ├── qgis_maptooldriller.h │ └── qgis_maptooldriller.pro ├── 04_map_tool_driller_part3 │ ├── 04_map_tool_driller_part3.zip │ ├── README.md │ ├── maptooldriller.cpp │ ├── maptooldriller.h │ ├── qgis_maptooldriller.cpp │ ├── qgis_maptooldriller.h │ └── qgis_maptooldriller.pro ├── 05_map_tool_driller_part4 │ ├── README.md │ ├── maptooldriller.cpp │ ├── maptooldriller.h │ ├── qgis_maptooldriller.cpp │ ├── qgis_maptooldriller.h │ └── qgis_maptooldriller.pro ├── MASTER_BUG_FIXES ├── README.md └── TARGETS ├── source.json ├── stylesheets ├── print.css ├── pygment_trac.css └── stylesheet.css └── update_params.js /README.md: -------------------------------------------------------------------------------- 1 | ###Because... 2 | 3 | 1. The QGIS community doesn't have a good howto on building C++ plugins. Proof ( [here](http://hub.qgis.org/wiki/17/Writing_C++_Plugins_%5BNew%5D) and [here](http://gis.stackexchange.com/questions/34147/where-can-i-find-documentation-on-qgis-c-plugin-development) ) 4 | 5 | 2. Current code examples are old and don't cover the new QGIS 2.0 API ( [here](https://github.com/qgis/QGIS-Code-Examples) ) 6 | 7 | 3. C++ is fun 8 | 9 | 4. [@keppy](https://github.com/keppy) is the kind of dude who puts bugs in your butt to do certain projects 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /images/body-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/body-bg.jpg -------------------------------------------------------------------------------- /images/body-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/body-bg.png -------------------------------------------------------------------------------- /images/download-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/download-button.png -------------------------------------------------------------------------------- /images/github-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/github-button.png -------------------------------------------------------------------------------- /images/header-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/header-bg.jpg -------------------------------------------------------------------------------- /images/highlight-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/highlight-bg.jpg -------------------------------------------------------------------------------- /images/hr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/hr.png -------------------------------------------------------------------------------- /images/octocat-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/octocat-icon.png -------------------------------------------------------------------------------- /images/sidebar-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/sidebar-bg.jpg -------------------------------------------------------------------------------- /images/tar-gz-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/tar-gz-icon.png -------------------------------------------------------------------------------- /images/zip-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/images/zip-icon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | Qgis C++ Plugin Cookbook by thebigspoon 14 | 15 | 16 | 17 |
18 |
19 | 20 |
21 |

Qgis C++ Plugin Cookbook

22 |

A cookbook for building C++ Qgis and Qt plugins

23 |
24 | 25 |
26 | Download .zip 27 | Download .tar.gz 28 | View on GitHub 29 |
30 | 31 |
32 | 33 |
34 |

35 | Another Cookbook

36 | 37 |

QGIS uses the Qt Project 38 | as the main GUI building block. Both projects have C++ intefaces. Given that, 39 | it is surprising the QGIS community does not have a good tutorial on building plugins 40 | in the native interface ( see the next section for a guess why ):

41 | 42 |
    43 |
  • Some proof of the need here 44 | and here.

  • 45 |
  • Existing code examples ( that are not core C++ plugins themselves ) are old 46 | and don't cover the new QGIS 2.0 API ( here )

  • 47 |

48 | Should I Build QGIS Plugins in Python or C++?

49 | 50 |

Probably Python. The QGIS community has put a lot of effort into documenting how to build Python 51 | plugins. One benefit of using Python is that you don't have to deal with all the different operating 52 | systems, build enviroments and plugin distribution.

53 | 54 |

That said, if you are a C++ programmer and learning Python seems boring, then this 55 | tutorial will show you how to become familiar with the API basics. You can deal 56 | with the distribution issues on your own.

57 | 58 |

59 | How to Use the Cookbook

60 | 61 |

Go over to this repo's example plugins 62 | directory and go into 01_hello_world. Then read the README and get hacky.

63 | 64 |

65 | How to Contribute to the Cookbook

66 | 67 |
DISCLAIMER: Most of the recipes on here only cover
 68 | building tools with gcc on Ubuntu Linux
 69 | so go read about how to build on other environemnts
 70 | Then make examples for everyone here!
 71 | 
72 | 73 |
    74 |
  1. clone the repo

  2. 75 |
  3. install node

  4. 76 |
  5. get coffee

  6. 77 |
  7. make shit

  8. 78 |
  9. more to come

  10. 79 |

80 | Current Plugin Tutorials

81 | 82 |
    83 |
  1. Hello World( qmake versus cmake workflows )

  2. 84 |
  3. Map Tool Driller ( part 1 )

  4. 85 |
  5. Map Tool Driller ( part 2 )

  6. 86 |
  7. Map Tool Driller ( part 3 )

  8. 87 |
  9. Map Tool Driller ( part 4 )

  10. 88 |

89 | Authors and Contributors

90 | 91 |

Greg Corradini ( @thebigspoon ) and James Dominguez ( @keppy )

92 | 93 |

94 | Support or Contact

95 | 96 |

Drop it like it's hot on the issue page over here

97 |
98 | 99 | 103 | 104 | 105 |
106 |
107 | 108 | 109 | -------------------------------------------------------------------------------- /javascripts/main.js: -------------------------------------------------------------------------------- 1 | console.log('This would be the main JS file.'); 2 | -------------------------------------------------------------------------------- /params.json: -------------------------------------------------------------------------------- 1 | {"name":"Qgis C++ Plugin Cookbook","tagline":"A cookbook for building C++ Qgis and Qt plugins","body":"### Another Cookbook\r\nYep. QGIS uses the [Qt Project](http://qt-project.org/doc/qt-5.1/qtdoc/index.html) \r\nas the main GUI building block. Both projects have C++ intefaces. Given that, \r\nit is surprising the QGIS community does not have a good tutorial on building plugins\r\nin the native interface ( it's actually not that surpising. See the next section ):\r\n\r\n- Some proof of the need [here](http://hub.qgis.org/wiki/17/Writing_C++_Plugins_%5BNew%5D) \r\nand [here](http://gis.stackexchange.com/questions/34147/where-can-i-find-documentation-on-qgis-c-plugin-development).\r\n\r\n- Existing code examples ( that are not core C++ plugins themselves ) are old \r\nand don't cover the new QGIS 2.0 API ( [here](https://github.com/qgis/QGIS-Code-Examples) )\r\n\r\n### Should I Build QGIS Plugins in Python or C++?\r\nProbably Python. The QGIS community has put a lot of effort into documenting how to build Python\r\nplugins. One benefit of using Python is that you don't have to deal with all the different operating\r\nsystems, build enviroments and plugin distribution.\r\n\r\nThat said, if you are a C++ programmer and learning Python seems boring, then this \r\ntutorial will show you how to become familiar with the API basics. You can deal\r\nwith the distribution issues on your own.\r\n\r\n### How to Use the Cookbook\r\nGo over to this repo's [example plugins](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples) \r\ndirectory and go into `01_hello_world`.\r\n\r\n### How to Contribute to the Cookbook\r\n```bash\r\nDISCLAIMER: Most of the recipes by the auther only cover\r\nbuilding tools with gcc on Ubuntu Linux\r\n```\r\n\r\n1. clone the repo\r\n\r\n2. install node\r\n\r\n3. get coffee\r\n\r\n4. make money\r\n\r\n5. more to come\r\n\r\n6. udpate the next section\r\n\r\n### Current Plugin Tutorials\r\n\r\n1. [Hello World](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples/01_hello_world)( `qmake` versus `cmake` workflows )\r\n\r\n2. [Map Tool Driller ( part 1 )](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples/02_map_tool_driller_part1)\r\n\r\n3. [Map Tool Driller ( part 2 )](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples/03_map_tool_driller_part2)\r\n\r\n4. [Map Tool Driller ( part 3 )](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples/04_map_tool_driller_part3)\r\n\r\n5. Map Tool Driller ( part 4 )\r\n\r\n### Authors and Contributors\r\nGreg Corradini ( @thebigspoon ) and James Dominguez ( @keppy )\r\n\r\n### Support or Contact\r\nDrop it like it's hot on the [issue page over here](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/issues)\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."} -------------------------------------------------------------------------------- /plugin_code_examples/01_hello_world/01_hello_world.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/plugin_code_examples/01_hello_world/01_hello_world.zip -------------------------------------------------------------------------------- /plugin_code_examples/01_hello_world/README.md: -------------------------------------------------------------------------------- 1 | ###Build dependecies 2 | 3 | 1. You will need QGIS source and all the dependecies. The [build instructions](https://github.com/qgis/QGIS/blob/master/INSTALL#L85-L340) you should follow are very clear. 4 | 5 | ###Building 6 | 7 | 1. run `$ qmake qgis_hello_world.pro` to create the Makefile 8 | 9 | 2. run `make` to build the dynamic .so lib 10 | 11 | 3. copy or link it to the qgis plugins directory: `sudo cp liqgis_hello_world.so.1.0.0 /usr/lib/qgis/plugins/libqgis_hello_world.so` 12 | 13 | 14 | -------------------------------------------------------------------------------- /plugin_code_examples/01_hello_world/qgis_hello_world.cpp: -------------------------------------------------------------------------------- 1 | #include "qgis_hello_world.h" 2 | 3 | /*static*/ const QString HelloWorldPlugin::s_name = QObject::tr("Hello World Plugin"); 4 | /*static*/ const QString HelloWorldPlugin::s_description = QObject::tr("Sample Plugin"); 5 | /*static*/ const QString HelloWorldPlugin::s_category = QObject::tr("Plugins"); 6 | /*static*/ const QString HelloWorldPlugin::s_version = QObject::tr("Version 5.2.0"); 7 | /*static*/ const QString HelloWorldPlugin::s_icon = ""; 8 | /*static*/ const QgisPlugin::PLUGINTYPE HelloWorldPlugin::s_type = QgisPlugin::UI; 9 | 10 | QGISEXTERN QgisPlugin* classFactory(QgisInterface* qgis_if) 11 | { 12 | std::cout << "::classFactory" << std::endl; 13 | return new HelloWorldPlugin(qgis_if); 14 | } 15 | 16 | QGISEXTERN QString name() 17 | { 18 | std::cout << "::name" << std::endl; 19 | return HelloWorldPlugin::s_name; 20 | } 21 | 22 | QGISEXTERN QString description() 23 | { 24 | std::cout << "::description" << std::endl; 25 | return HelloWorldPlugin::s_description; 26 | } 27 | 28 | QGISEXTERN QString category() 29 | { 30 | std::cout << "::category" << std::endl; 31 | return HelloWorldPlugin::s_category; 32 | } 33 | 34 | QGISEXTERN int type() 35 | { 36 | std::cout << "::type" << std::endl; 37 | return HelloWorldPlugin::s_type; 38 | } 39 | 40 | QGISEXTERN QString version() 41 | { 42 | std::cout << "::version" << std::endl; 43 | return HelloWorldPlugin::s_version; 44 | } 45 | 46 | QGISEXTERN QString icon() 47 | { 48 | std::cout << "::icon" << std::endl; 49 | return HelloWorldPlugin::s_icon; 50 | } 51 | 52 | QGISEXTERN void unload(QgisPlugin* plugin) 53 | { 54 | std::cout << "::unload" << std::endl; 55 | delete plugin; 56 | } 57 | 58 | /*virtual*/ void HelloWorldPlugin::initGui() 59 | { 60 | std::cout << "HelloWorldPlugin::initGui" << std::endl; 61 | 62 | // add an action to the menu 63 | m_action = new QAction(QIcon("" ), tr("Hello World"), this); 64 | m_action->setWhatsThis(tr("Draw on the map canvas.")); 65 | connect(m_action, SIGNAL(triggered()), this, SLOT(StartOverlay())); 66 | m_qgis_if->addRasterToolBarIcon(m_action); 67 | m_qgis_if->addPluginToMenu(tr("&Hello World"), m_action); 68 | } 69 | 70 | void HelloWorldPlugin::StartOverlay() 71 | { 72 | std::cout << "HelloWorldPlugin::StartOverlay" << std::endl; 73 | 74 | // get the map canvas 75 | QgsMapCanvas* canvas = m_qgis_if->mapCanvas(); 76 | 77 | // connect to the render complete signal 78 | /* 79 | connect(canvas, SIGNAL(renderComplete(QPainter*)), 80 | this, SLOT(DrawOverlay(QPainter*))); 81 | */ 82 | 83 | // Layer QStrings 84 | QString mLayerPath = "/home/junkmob/QGIS-DEV/QGIS/tests/testdata/points.shp"; 85 | QString mLayerBaseName = "points"; 86 | QString mProviderName = "ogr"; 87 | 88 | // Get Vector Layer 89 | QgsVectorLayer * mLayer = new QgsVectorLayer(mLayerPath, mLayerBaseName, mProviderName); 90 | if (mLayer->isValid()) 91 | { 92 | QString mFeedback = "layer is valid"; 93 | QString mTag = "HelloWorld"; 94 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 95 | } 96 | else 97 | { 98 | QString mFeedback = "layer NOT valid"; 99 | QString mTag = "HelloWorld"; 100 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 101 | } 102 | 103 | // Add the Vector Layer to the Layer Registry 104 | QgsMapLayerRegistry::instance()->addMapLayer(mLayer, TRUE); 105 | 106 | // Add the Layer to the Layer Set 107 | QList mLayerSet; 108 | mLayerSet.append(QgsMapCanvasLayer(mLayer, TRUE)); 109 | 110 | // Create the Map Canvas 111 | canvas->setExtent(mLayer->extent()); 112 | canvas->enableAntiAliasing(true); 113 | canvas->setCanvasColor(QColor(255, 255, 255)); 114 | canvas->freeze(false); 115 | 116 | // add it to the canvas 117 | canvas->setLayerSet( mLayerSet ); 118 | canvas->setVisible(true); 119 | canvas->refresh(); 120 | 121 | } 122 | 123 | -------------------------------------------------------------------------------- /plugin_code_examples/01_hello_world/qgis_hello_world.h: -------------------------------------------------------------------------------- 1 | #ifndef QGIS_HELLO_WORLD_H 2 | #define QGIS_HELLO_WORLD_H 3 | 4 | #include "qgisplugin.h" 5 | #include "qgsmapcanvas.h" 6 | #include "qgisinterface.h" 7 | #include "qgsvectorlayer.h" 8 | #include "qgsmessagelog.h" 9 | #include "qgsmaplayerregistry.h" 10 | #include 11 | #include 12 | 13 | class HelloWorldPlugin : public QObject, public QgisPlugin 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | static const QString s_name, s_description, s_category, s_version, s_icon; 19 | static const QgisPlugin::PLUGINTYPE s_type; 20 | 21 | HelloWorldPlugin(QgisInterface* qgis_if) : QgisPlugin(s_name, s_description, s_category, s_version, s_type), m_qgis_if(qgis_if) 22 | { 23 | } 24 | 25 | // virtual methods from QgisPlugin 26 | virtual void initGui(); 27 | virtual void unload() 28 | { 29 | std::cout << "HelloWorldPlugin::unload" << std::endl; 30 | } 31 | 32 | public slots: 33 | void StartOverlay(); 34 | void DrawOverlay(QPainter* painter); 35 | 36 | private: 37 | QgisInterface* m_qgis_if; 38 | QAction* m_action; 39 | 40 | }; 41 | 42 | #endif // #ifndef QGIS_HELLO_WORLD_H 43 | -------------------------------------------------------------------------------- /plugin_code_examples/01_hello_world/qgis_hello_world.pro: -------------------------------------------------------------------------------- 1 | #QGIS_DIR = /home/junkmob/QGIS-APP/lib/qgis 2 | TEMPLATE = lib 3 | CONFIG = qt 4 | QT += xml qt3support 5 | LIBS += -L/home/junkmob/QGIS-APP/lib -lqgis_core -lqgis_gui 6 | #INCLUDEPATH += $$QGIS_DIR/src/ui $$QGIS_DIR/src/plugins $$QGIS_DIR/src/gui $$QGIS_DIR/src/raster $$QGIS_DIR/src/core $$QGIS_DIR 7 | INCLUDEPATH += /home/junkmob/QGIS-APP/include/qgis 8 | SOURCES = qgis_hello_world.cpp 9 | HEADERS = qgis_hello_world.h 10 | DEST = qgis_hello_world.so 11 | DEFINES += GUI_EXPORT= CORE_EXPORT= 12 | -------------------------------------------------------------------------------- /plugin_code_examples/02_map_tool_driller_part1/02_map_tool_driller_part1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/plugin_code_examples/02_map_tool_driller_part1/02_map_tool_driller_part1.zip -------------------------------------------------------------------------------- /plugin_code_examples/02_map_tool_driller_part1/README.md: -------------------------------------------------------------------------------- 1 | ###Build dependecies 2 | 3 | 1. You will need QGIS source and all the dependecies. The [build instructions](https://github.com/qgis/QGIS/blob/master/INSTALL#L85-L340) you should follow are very clear. 4 | 5 | ###Building 6 | 7 | 1. run `$ qmake qgis_maptooldriller.pro` to create the Makefile 8 | 9 | 2. run `make` to build the dynamic .so lib 10 | 11 | 3. copy or link it to the qgis plugins directory: `sudo cp liqgis_maptooldriller.so.1.0.0 /usr/lib/qgis/plugins/` 12 | 13 | 14 | -------------------------------------------------------------------------------- /plugin_code_examples/02_map_tool_driller_part1/maptooldriller.cpp: -------------------------------------------------------------------------------- 1 | #include "maptooldriller.h" 2 | #include "qgscursors.h" 3 | #include "qgsmapcanvas.h" 4 | #include "qgsmaptopixel.h" 5 | #include "qgsrubberband.h" 6 | #include "qgscoordinatereferencesystem.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | MapToolDriller::MapToolDriller(QgsMapCanvas* canvas) : QgsMapTool(canvas) 16 | { 17 | // set cursor 18 | QPixmap myCursor = QPixmap(( const char ** ) capture_point_cursor ); // const from qgscursors 19 | mCursor = QCursor( myCursor, 8, 8 ); //8,8 is the point in the cursor where clicks register 20 | /* 21 | ** TODO: 22 | ** there is no reason to hold a pointer 23 | ** to MapCanvas when when QgsMapTool has protected member 24 | ** and we are passed one in the constructor 25 | ** remoe it later to see if it still works 26 | */ 27 | mpMapCanvas = canvas; 28 | mpRubberBand = new QgsRubberBand( mpMapCanvas, QGis::Polygon ); 29 | mpRubberBand->setColor( Qt::red ); 30 | mpRubberBand->setWidth( 1 ); 31 | } 32 | 33 | MapToolDriller::~MapToolDriller() 34 | { 35 | if ( mpRubberBand != 0 ) { 36 | delete mpRubberBand; 37 | } 38 | } 39 | 40 | void MapToolDriller::canvasMoveEvent(QMouseEvent * e) 41 | { 42 | QgsPoint myOriginalPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() ); 43 | emit mouseMoved( myOriginalPoint ); 44 | } 45 | 46 | void MapToolDriller::canvasPressEvent(QMouseEvent * e) 47 | { 48 | Q_UNUSED( e ); 49 | } 50 | 51 | void MapToolDriller::canvasReleaseEvent(QMouseEvent * e) 52 | { 53 | if ( !mpMapCanvas || mpMapCanvas->isDrawing() ) 54 | { 55 | return; 56 | } 57 | 58 | QgsPoint myOriginalPoint = 59 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() ); 60 | emit mouseClicked( myOriginalPoint ); 61 | 62 | //make a little box for display 63 | 64 | QgsPoint myPoint1 = 65 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() - 1, e->y() - 1 ); 66 | QgsPoint myPoint2 = 67 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() + 1, e->y() - 1 ); 68 | QgsPoint myPoint3 = 69 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() + 1, e->y() + 1 ); 70 | QgsPoint myPoint4 = 71 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() - 1, e->y() + 1 ); 72 | 73 | mpRubberBand->reset( QGis::Polygon ); 74 | // convert screen coordinates to map coordinates 75 | mpRubberBand->addPoint( myPoint1, false ); //true - update canvas 76 | mpRubberBand->addPoint( myPoint2, false ); //true - update canvas 77 | mpRubberBand->addPoint( myPoint3, false ); //true - update canvas 78 | mpRubberBand->addPoint( myPoint4, true ); //true - update canvas 79 | mpRubberBand->show(); 80 | } 81 | 82 | void MapToolDriller::deactivate() 83 | { 84 | mpRubberBand->reset( QGis::Line ); 85 | QgsMapTool::deactivate(); 86 | } 87 | -------------------------------------------------------------------------------- /plugin_code_examples/02_map_tool_driller_part1/maptooldriller.h: -------------------------------------------------------------------------------- 1 | #ifndef MAPTOOLDRILLER_H 2 | #define MAPTOOLDRILLER_H 3 | 4 | #include "qgsmaptool.h" 5 | #include "qgspoint.h" 6 | #include "qgsmessagelog.h" 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | ** forward declarations instead of include 13 | ** to cut down compile time since we only 14 | ** want one class from the header 15 | */ 16 | class QgsRubberBand; 17 | 18 | class MapToolDriller : public QgsMapTool 19 | { 20 | Q_OBJECT; 21 | 22 | public: 23 | MapToolDriller(QgsMapCanvas* canvas); 24 | 25 | ~MapToolDriller(); 26 | 27 | //! Overridden mouse move event 28 | virtual void canvasMoveEvent(QMouseEvent * e); 29 | 30 | //! Overridden mouse press event 31 | virtual void canvasPressEvent(QMouseEvent * e); 32 | 33 | //! Overridden mouse release event 34 | virtual void canvasReleaseEvent(QMouseEvent * e); 35 | 36 | //! called when map tool is being deactivated 37 | virtual void deactivate(); 38 | 39 | void canvasClickHandler(const QgsPoint&); 40 | 41 | typedef QHash DrillResult; 42 | 43 | public slots: 44 | 45 | signals: 46 | void mouseMoved( QgsPoint ); 47 | 48 | void mouseClicked( QgsPoint ); 49 | 50 | private: 51 | //! Rubber band for dropping visual of click on map 52 | QgsRubberBand * mpRubberBand; 53 | 54 | QPointer mpMapCanvas; 55 | 56 | private slots: 57 | 58 | }; 59 | #endif 60 | -------------------------------------------------------------------------------- /plugin_code_examples/02_map_tool_driller_part1/qgis_maptooldriller.cpp: -------------------------------------------------------------------------------- 1 | #include "qgis_maptooldriller.h" 2 | #include "maptooldriller.h" 3 | #include "qgsmaptoolemitpoint.h" 4 | 5 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_name = QObject::tr("MapToolDrillerz"); 6 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_description = QObject::tr("Sample Plugin"); 7 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_category = QObject::tr("Plugins"); 8 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_version = QObject::tr("Version 0.1.1"); 9 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_icon = ""; 10 | /*static*/ const QgisPlugin::PLUGINTYPE Qgis_MapToolDrillerPLugin::s_type = QgisPlugin::UI; 11 | 12 | QGISEXTERN QgisPlugin* classFactory(QgisInterface* qgis_if) 13 | { 14 | std::cout << "::classFactory" << std::endl; 15 | return new Qgis_MapToolDrillerPLugin(qgis_if); 16 | } 17 | 18 | QGISEXTERN QString name() 19 | { 20 | std::cout << "::name" << std::endl; 21 | return Qgis_MapToolDrillerPLugin::s_name; 22 | } 23 | 24 | QGISEXTERN QString description() 25 | { 26 | std::cout << "::description" << std::endl; 27 | return Qgis_MapToolDrillerPLugin::s_description; 28 | } 29 | 30 | QGISEXTERN QString category() 31 | { 32 | std::cout << "::category" << std::endl; 33 | return Qgis_MapToolDrillerPLugin::s_category; 34 | } 35 | 36 | QGISEXTERN int type() 37 | { 38 | std::cout << "::type" << std::endl; 39 | return Qgis_MapToolDrillerPLugin::s_type; 40 | } 41 | 42 | QGISEXTERN QString version() 43 | { 44 | std::cout << "::version" << std::endl; 45 | return Qgis_MapToolDrillerPLugin::s_version; 46 | } 47 | 48 | QGISEXTERN QString icon() 49 | { 50 | std::cout << "::icon" << std::endl; 51 | return Qgis_MapToolDrillerPLugin::s_icon; 52 | } 53 | 54 | QGISEXTERN void unload(QgisPlugin* plugin) 55 | { 56 | std::cout << "::unload" << std::endl; 57 | delete plugin; 58 | } 59 | 60 | /*virtual*/ void Qgis_MapToolDrillerPLugin::initGui() 61 | { 62 | std::cout << "Qgis_MapToolDrillerPLugin::initGui" << std::endl; 63 | 64 | // add an action to the menu 65 | m_action = new QAction(QIcon("" ), tr("MapToolDriller"), this); 66 | m_action->setWhatsThis(tr("Click on the map canvas like never before")); 67 | connect(m_action, SIGNAL(triggered()), this, SLOT(StartOverlay())); 68 | 69 | m_qgis_if->addRasterToolBarIcon(m_action); 70 | m_qgis_if->addPluginToMenu(tr("&MapToolDriller"), m_action); 71 | 72 | // get the emit tool 73 | mEmitPointTool = new QgsMapToolEmitPoint( m_qgis_if->mapCanvas() ); 74 | connect( mEmitPointTool, SIGNAL( canvasClicked( const QgsPoint&, Qt::MouseButton ) ), 75 | this, SLOT( handleCanvasClick( const QgsPoint& ) ) ); 76 | 77 | } 78 | 79 | void Qgis_MapToolDrillerPLugin::handleCanvasClick( const QgsPoint &thePoint ) { 80 | QString mTag = "MapToolDriller"; 81 | QString mFeedback = "inside canvasReleaseEvent"; 82 | QgsMessageLog::instance()->logMessage( thePoint.toString(), mTag, QgsMessageLog::INFO ); 83 | 84 | QString xy = "Emitting..."; 85 | QgsMessageLog::instance()->logMessage( xy, mTag, QgsMessageLog::INFO ); 86 | } 87 | 88 | void Qgis_MapToolDrillerPLugin::StartOverlay() 89 | { 90 | std::cout << "Qgis_MapToolDrillerPLugin::StartOverlay" << std::endl; 91 | 92 | // Get the map canvas 93 | QgsMapCanvas* canvas = m_qgis_if->mapCanvas(); 94 | // set the tool 95 | canvas->setMapTool(mEmitPointTool); 96 | 97 | // Layer QStrings 98 | QString mLayerPath = "/home/junkmob/QGIS-DEV/QGIS/tests/testdata/points.shp"; 99 | QString mLayerBaseName = "points"; 100 | QString mProviderName = "ogr"; 101 | 102 | // Get Vector Layer 103 | QgsVectorLayer * mLayer = new QgsVectorLayer(mLayerPath, mLayerBaseName, mProviderName); 104 | if (mLayer->isValid()) 105 | { 106 | QString mFeedback = "layer is valid"; 107 | QString mTag = "MapToolDriller"; 108 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 109 | } 110 | else 111 | { 112 | QString mFeedback = "layer NOT valid"; 113 | QString mTag = "MapToolDriller"; 114 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 115 | } 116 | 117 | // Add the Vector Layer to the Layer Registry 118 | QgsMapLayerRegistry::instance()->addMapLayer(mLayer, TRUE); 119 | 120 | // Add the Layer to the Layer Set 121 | QList mLayerSet; 122 | mLayerSet.append(QgsMapCanvasLayer(mLayer, TRUE)); 123 | 124 | // Create the Map Canvas 125 | canvas->setExtent(mLayer->extent()); 126 | canvas->enableAntiAliasing(true); 127 | canvas->setCanvasColor(QColor(255, 255, 255)); 128 | canvas->freeze(false); 129 | 130 | // add it to the canvas 131 | canvas->setLayerSet( mLayerSet ); 132 | canvas->setVisible(true); 133 | canvas->refresh(); 134 | 135 | } 136 | 137 | -------------------------------------------------------------------------------- /plugin_code_examples/02_map_tool_driller_part1/qgis_maptooldriller.h: -------------------------------------------------------------------------------- 1 | #ifndef QGIS_MAPTOOLDRILLER_H 2 | #define QGIS_MAPTOOLDRILLER_H 3 | 4 | #include "qgsmaptoolemitpoint.h" 5 | #include "maptooldriller.h" // not used in part 1, we use qgismaptoolemitpoint.h instead 6 | #include "qgisplugin.h" 7 | #include "qgsmapcanvas.h" 8 | #include "qgisinterface.h" 9 | #include "qgsvectorlayer.h" 10 | #include "qgsmessagelog.h" 11 | #include "qgsmaplayerregistry.h" 12 | #include 13 | #include 14 | 15 | class Qgis_MapToolDrillerPLugin : public QObject, public QgisPlugin 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | static const QString s_name, s_description, s_category, s_version, s_icon; 21 | 22 | static const QgisPlugin::PLUGINTYPE s_type; 23 | 24 | Qgis_MapToolDrillerPLugin(QgisInterface* qgis_if) : 25 | QgisPlugin(s_name, s_description, s_category, s_version, s_type), m_qgis_if(qgis_if) 26 | { 27 | 28 | } 29 | 30 | // virtual methods from QgisPlugin 31 | virtual void initGui(); 32 | 33 | virtual void unload() 34 | { 35 | std::cout << "Qgis_MapToolDrillerPLugin::unload" << std::endl; 36 | } 37 | 38 | public slots: 39 | void StartOverlay(); 40 | 41 | void handleCanvasClick(const QgsPoint&); 42 | 43 | private: 44 | QgisInterface* m_qgis_if; 45 | 46 | QAction* m_action; 47 | 48 | QgsMapToolEmitPoint *mEmitPointTool; 49 | 50 | }; 51 | 52 | #endif // #ifndef QGIS_MAPTOOLDRILLER_H 53 | -------------------------------------------------------------------------------- /plugin_code_examples/02_map_tool_driller_part1/qgis_maptooldriller.pro: -------------------------------------------------------------------------------- 1 | #QGIS_DIR = /home/junkmob/QGIS-APP/lib/qgis 2 | TEMPLATE = lib 3 | CONFIG = qt 4 | QT += xml qt3support 5 | LIBS += -L/home/junkmob/QGIS-APP/lib -lqgis_core -lqgis_gui 6 | #INCLUDEPATH += $$QGIS_DIR/src/ui $$QGIS_DIR/src/plugins $$QGIS_DIR/src/gui $$QGIS_DIR/src/raster $$QGIS_DIR/src/core $$QGIS_DIR 7 | INCLUDEPATH += /home/junkmob/QGIS-APP/include/qgis 8 | SOURCES = qgis_maptooldriller.cpp maptooldriller.cpp 9 | HEADERS = qgis_maptooldriller.h maptooldriller.h 10 | DEST = qgis_maptooldriller.so 11 | DEFINES += GUI_EXPORT= CORE_EXPORT= 12 | -------------------------------------------------------------------------------- /plugin_code_examples/03_map_tool_driller_part2/03_map_tool_driller_part2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/plugin_code_examples/03_map_tool_driller_part2/03_map_tool_driller_part2.zip -------------------------------------------------------------------------------- /plugin_code_examples/03_map_tool_driller_part2/README.md: -------------------------------------------------------------------------------- 1 | ###Build dependecies 2 | 3 | 1. You will need QGIS source and all the dependecies. The [build instructions](https://github.com/qgis/QGIS/blob/master/INSTALL#L85-L340) you should follow are very clear. 4 | 5 | ###Building 6 | 7 | 1. run `$ qmake qgis_maptooldriller.pro` to create the Makefile 8 | 9 | 2. run `make` to build the dynamic .so lib 10 | 11 | 3. copy or link it to the qgis plugins directory: `sudo cp liqgis_maptooldriller.so.1.0.0 /usr/lib/qgis/plugins/` 12 | 13 | 14 | -------------------------------------------------------------------------------- /plugin_code_examples/03_map_tool_driller_part2/maptooldriller.cpp: -------------------------------------------------------------------------------- 1 | #include "maptooldriller.h" 2 | #include "qgscursors.h" 3 | #include "qgsmapcanvas.h" 4 | #include "qgsmaptopixel.h" 5 | #include "qgsrubberband.h" 6 | #include "qgscoordinatereferencesystem.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | MapToolDriller::MapToolDriller(QgsMapCanvas* canvas) : QgsMapTool(canvas) 16 | { 17 | // set cursor 18 | QPixmap myCursor = QPixmap(( const char ** ) capture_point_cursor ); // const from qgscursors 19 | mCursor = QCursor( myCursor, 8, 8 ); //8,8 is the point in the cursor where clicks register 20 | /* 21 | ** TODO: 22 | ** there is no reason to hold a pointer 23 | ** to MapCanvas when when QgsMapTool has protected member 24 | ** and we are passed one in the constructor 25 | ** remoe it later to see if it still works 26 | */ 27 | mpMapCanvas = canvas; 28 | mpRubberBand = new QgsRubberBand( mpMapCanvas, QGis::Polygon ); 29 | mpRubberBand->setColor( Qt::red ); 30 | mpRubberBand->setWidth( 1 ); 31 | } 32 | 33 | MapToolDriller::~MapToolDriller() 34 | { 35 | if ( mpRubberBand != 0 ) { 36 | delete mpRubberBand; 37 | } 38 | } 39 | 40 | void MapToolDriller::canvasMoveEvent(QMouseEvent * e) 41 | { 42 | QgsPoint myOriginalPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() ); 43 | emit mouseMoved( myOriginalPoint ); 44 | } 45 | 46 | void MapToolDriller::canvasPressEvent(QMouseEvent * e) 47 | { 48 | Q_UNUSED( e ); 49 | } 50 | 51 | void MapToolDriller::canvasReleaseEvent(QMouseEvent * e) 52 | { 53 | if ( !mpMapCanvas || mpMapCanvas->isDrawing() ) 54 | { 55 | return; 56 | } 57 | 58 | QgsPoint myOriginalPoint = 59 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() ); 60 | emit mouseClicked( myOriginalPoint ); 61 | 62 | //make a little box for display 63 | 64 | QgsPoint myPoint1 = 65 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() - 1, e->y() - 1 ); 66 | QgsPoint myPoint2 = 67 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() + 1, e->y() - 1 ); 68 | QgsPoint myPoint3 = 69 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() + 1, e->y() + 1 ); 70 | QgsPoint myPoint4 = 71 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() - 1, e->y() + 1 ); 72 | 73 | mpRubberBand->reset( QGis::Polygon ); 74 | // convert screen coordinates to map coordinates 75 | mpRubberBand->addPoint( myPoint1, false ); //true - update canvas 76 | mpRubberBand->addPoint( myPoint2, false ); //true - update canvas 77 | mpRubberBand->addPoint( myPoint3, false ); //true - update canvas 78 | mpRubberBand->addPoint( myPoint4, true ); //true - update canvas 79 | mpRubberBand->show(); 80 | } 81 | 82 | void MapToolDriller::deactivate() 83 | { 84 | mpRubberBand->reset( QGis::Line ); 85 | QgsMapTool::deactivate(); 86 | } 87 | -------------------------------------------------------------------------------- /plugin_code_examples/03_map_tool_driller_part2/maptooldriller.h: -------------------------------------------------------------------------------- 1 | #ifndef MAPTOOLDRILLER_H 2 | #define MAPTOOLDRILLER_H 3 | 4 | #include "qgsmaptool.h" 5 | #include "qgspoint.h" 6 | #include "qgsmessagelog.h" 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | ** forward declarations instead of include 13 | ** to cut down compile time since we only 14 | ** want one class from the header 15 | */ 16 | class QgsRubberBand; 17 | 18 | class MapToolDriller : public QgsMapTool 19 | { 20 | Q_OBJECT; 21 | 22 | public: 23 | MapToolDriller(QgsMapCanvas* canvas); 24 | 25 | ~MapToolDriller(); 26 | 27 | //! Overridden mouse move event 28 | virtual void canvasMoveEvent(QMouseEvent * e); 29 | 30 | //! Overridden mouse press event 31 | virtual void canvasPressEvent(QMouseEvent * e); 32 | 33 | //! Overridden mouse release event 34 | virtual void canvasReleaseEvent(QMouseEvent * e); 35 | 36 | //! called when map tool is being deactivated 37 | virtual void deactivate(); 38 | 39 | void canvasClickHandler(const QgsPoint&); 40 | 41 | typedef QHash DrillResult; 42 | 43 | public slots: 44 | 45 | signals: 46 | void mouseMoved( QgsPoint ); 47 | 48 | void mouseClicked( QgsPoint ); 49 | 50 | private: 51 | //! Rubber band for dropping visual of click on map 52 | QgsRubberBand * mpRubberBand; 53 | 54 | QPointer mpMapCanvas; 55 | 56 | private slots: 57 | 58 | }; 59 | #endif 60 | -------------------------------------------------------------------------------- /plugin_code_examples/03_map_tool_driller_part2/qgis_maptooldriller.cpp: -------------------------------------------------------------------------------- 1 | #include "qgis_maptooldriller.h" 2 | 3 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_name = QObject::tr("MapToolDrillerz"); 4 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_description = QObject::tr("Sample Plugin"); 5 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_category = QObject::tr("Plugins"); 6 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_version = QObject::tr("Version 0.1.1"); 7 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_icon = ""; 8 | /*static*/ const QgisPlugin::PLUGINTYPE Qgis_MapToolDrillerPLugin::s_type = QgisPlugin::UI; 9 | 10 | // for logging 11 | /*static*/ const QString Qgis_MapToolDrillerPLugin::mTag = QObject::tr("MapToolDriller"); 12 | 13 | QGISEXTERN QgisPlugin* classFactory(QgisInterface* qgis_if) 14 | { 15 | std::cout << "::classFactory" << std::endl; 16 | return new Qgis_MapToolDrillerPLugin(qgis_if); 17 | } 18 | 19 | QGISEXTERN QString name() 20 | { 21 | std::cout << "::name" << std::endl; 22 | return Qgis_MapToolDrillerPLugin::s_name; 23 | } 24 | 25 | QGISEXTERN QString description() 26 | { 27 | std::cout << "::description" << std::endl; 28 | return Qgis_MapToolDrillerPLugin::s_description; 29 | } 30 | 31 | QGISEXTERN QString category() 32 | { 33 | std::cout << "::category" << std::endl; 34 | return Qgis_MapToolDrillerPLugin::s_category; 35 | } 36 | 37 | QGISEXTERN int type() 38 | { 39 | std::cout << "::type" << std::endl; 40 | return Qgis_MapToolDrillerPLugin::s_type; 41 | } 42 | 43 | QGISEXTERN QString version() 44 | { 45 | std::cout << "::version" << std::endl; 46 | return Qgis_MapToolDrillerPLugin::s_version; 47 | } 48 | 49 | QGISEXTERN QString icon() 50 | { 51 | std::cout << "::icon" << std::endl; 52 | return Qgis_MapToolDrillerPLugin::s_icon; 53 | } 54 | 55 | QGISEXTERN void unload(QgisPlugin* plugin) 56 | { 57 | std::cout << "::unload" << std::endl; 58 | delete plugin; 59 | } 60 | 61 | /*virtual*/ Qgis_MapToolDrillerPLugin::~Qgis_MapToolDrillerPLugin() 62 | { 63 | 64 | } 65 | 66 | 67 | /*virtual*/ void Qgis_MapToolDrillerPLugin::initGui() 68 | { 69 | std::cout << "Qgis_MapToolDrillerPLugin::initGui" << std::endl; 70 | 71 | // add an action to the menu 72 | m_action = new QAction(QIcon("" ), tr("MapToolDriller"), this); 73 | m_action->setWhatsThis(tr("Click on the map canvas like never before")); 74 | connect(m_action, SIGNAL(triggered()), this, SLOT(StartOverlay())); 75 | 76 | m_qgis_if->addRasterToolBarIcon(m_action); 77 | m_qgis_if->addPluginToMenu(tr("&MapToolDriller"), m_action); 78 | 79 | // create our map tool 80 | mpMapTool = new MapToolDriller( m_qgis_if->mapCanvas() ); 81 | connect( mpMapTool, SIGNAL( mouseMoved( QgsPoint ) ), this, SLOT( mouseMoved( QgsPoint ) ) ); 82 | connect( mpMapTool, SIGNAL( mouseClicked( QgsPoint ) ), this, SLOT( mouseClicked( QgsPoint ) ) ); 83 | } 84 | 85 | 86 | void Qgis_MapToolDrillerPLugin::mouseClicked( QgsPoint thePoint ) 87 | { 88 | QString mFeedback = thePoint.toString(); 89 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 90 | } 91 | void Qgis_MapToolDrillerPLugin::mouseMoved( QgsPoint thePoint ) 92 | { 93 | QString mFeedback = thePoint.toString(); 94 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 95 | } 96 | 97 | void Qgis_MapToolDrillerPLugin::StartOverlay() 98 | { 99 | std::cout << "Qgis_MapToolDrillerPLugin::StartOverlay" << std::endl; 100 | 101 | // Get the map canvas 102 | QgsMapCanvas* canvas = m_qgis_if->mapCanvas(); 103 | // set the tool 104 | canvas->setMapTool(mpMapTool); 105 | 106 | // Layer QStrings 107 | QString mLayerPath = "/home/junkmob/QGIS-DEV/QGIS/tests/testdata/points.shp"; 108 | QString mLayerBaseName = "points"; 109 | QString mProviderName = "ogr"; 110 | 111 | // Get Vector Layer 112 | QgsVectorLayer * mLayer = new QgsVectorLayer(mLayerPath, mLayerBaseName, mProviderName); 113 | if (mLayer->isValid()) 114 | { 115 | QString mFeedback = "layer is valid"; 116 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 117 | } 118 | else 119 | { 120 | QString mFeedback = "layer NOT valid"; 121 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 122 | } 123 | 124 | // Add the Vector Layer to the Layer Registry 125 | QgsMapLayerRegistry::instance()->addMapLayer(mLayer, TRUE); 126 | 127 | // Add the Layer to the Layer Set 128 | QList mLayerSet; 129 | mLayerSet.append(QgsMapCanvasLayer(mLayer, TRUE)); 130 | 131 | // Create the Map Canvas 132 | canvas->setExtent(mLayer->extent()); 133 | canvas->enableAntiAliasing(true); 134 | canvas->setCanvasColor(QColor(255, 255, 255)); 135 | canvas->freeze(false); 136 | 137 | // add it to the canvas 138 | canvas->setLayerSet( mLayerSet ); 139 | canvas->setVisible(true); 140 | canvas->refresh(); 141 | 142 | } 143 | 144 | -------------------------------------------------------------------------------- /plugin_code_examples/03_map_tool_driller_part2/qgis_maptooldriller.h: -------------------------------------------------------------------------------- 1 | #ifndef QGIS_MAPTOOLDRILLER_H 2 | #define QGIS_MAPTOOLDRILLER_H 3 | 4 | #include "maptooldriller.h" 5 | #include "qgisplugin.h" 6 | #include "qgsmapcanvas.h" 7 | #include "qgisinterface.h" 8 | #include "qgsvectorlayer.h" 9 | #include "qgsmessagelog.h" 10 | #include "qgsmaplayerregistry.h" 11 | #include 12 | #include 13 | 14 | class Qgis_MapToolDrillerPLugin : public QObject, public QgisPlugin 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | static const QString s_name, s_description, s_category, s_version, s_icon; 20 | 21 | static const QgisPlugin::PLUGINTYPE s_type; 22 | 23 | static const QString mTag; 24 | 25 | 26 | //! constructor 27 | Qgis_MapToolDrillerPLugin(QgisInterface* qgis_if) : 28 | QgisPlugin(s_name, s_description, s_category, s_version, s_type), m_qgis_if(qgis_if) 29 | { 30 | 31 | } 32 | 33 | //! destructor 34 | virtual ~Qgis_MapToolDrillerPLugin(); 35 | 36 | // virtual methods from QgisPlugin 37 | virtual void initGui(); 38 | 39 | virtual void unload() 40 | { 41 | std::cout << "Qgis_MapToolDrillerPLugin::unload" << std::endl; 42 | } 43 | 44 | public slots: 45 | //! Called when mouse clicks on the canvas. Will populate text box with coords. 46 | void mouseClicked( QgsPoint thePoint ); 47 | 48 | //! Called when mouse moved over the canvas. 49 | void mouseMoved( QgsPoint thePoint ); 50 | 51 | void StartOverlay(); 52 | 53 | private: 54 | QgisInterface* m_qgis_if; 55 | 56 | QAction* m_action; 57 | 58 | MapToolDriller* mpMapTool; 59 | 60 | }; 61 | 62 | #endif // #ifndef QGIS_MAPTOOLDRILLER_H 63 | -------------------------------------------------------------------------------- /plugin_code_examples/03_map_tool_driller_part2/qgis_maptooldriller.pro: -------------------------------------------------------------------------------- 1 | #QGIS_DIR = /home/junkmob/QGIS-APP/lib/qgis 2 | TEMPLATE = lib 3 | CONFIG = qt 4 | QT += xml qt3support 5 | LIBS += -L/home/junkmob/QGIS-APP/lib -lqgis_core -lqgis_gui 6 | #INCLUDEPATH += $$QGIS_DIR/src/ui $$QGIS_DIR/src/plugins $$QGIS_DIR/src/gui $$QGIS_DIR/src/raster $$QGIS_DIR/src/core $$QGIS_DIR 7 | INCLUDEPATH += /home/junkmob/QGIS-APP/include/qgis 8 | SOURCES = qgis_maptooldriller.cpp maptooldriller.cpp 9 | HEADERS = qgis_maptooldriller.h maptooldriller.h 10 | DEST = qgis_maptooldriller.so 11 | DEFINES += GUI_EXPORT= CORE_EXPORT= 12 | -------------------------------------------------------------------------------- /plugin_code_examples/04_map_tool_driller_part3/04_map_tool_driller_part3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ranchodeluxe/qgis_cpp_plugin_cookbook/bf531f6c3cc0b53242ba252f3051ca75db25a152/plugin_code_examples/04_map_tool_driller_part3/04_map_tool_driller_part3.zip -------------------------------------------------------------------------------- /plugin_code_examples/04_map_tool_driller_part3/README.md: -------------------------------------------------------------------------------- 1 | ###Build dependecies 2 | 3 | 1. You will need QGIS source and all the dependecies. The [build instructions](https://github.com/qgis/QGIS/blob/master/INSTALL#L85-L340) you should follow are very clear. 4 | 5 | ###Building 6 | 7 | 1. run `$ qmake qgis_maptooldriller.pro` to create the Makefile 8 | 9 | 2. run `make` to build the dynamic .so lib 10 | 11 | 3. copy or link it to the qgis plugins directory: `sudo cp liqgis_maptooldriller.so.1.0.0 /usr/lib/qgis/plugins/` 12 | 13 | 14 | -------------------------------------------------------------------------------- /plugin_code_examples/04_map_tool_driller_part3/maptooldriller.cpp: -------------------------------------------------------------------------------- 1 | #include "maptooldriller.h" 2 | #include "qgscursors.h" 3 | #include "qgsmapcanvas.h" 4 | #include "qgsmaptopixel.h" 5 | #include "qgsrubberband.h" 6 | #include "qgscoordinatereferencesystem.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | MapToolDriller::MapToolDriller(QgsMapCanvas* canvas) : QgsMapTool(canvas) 16 | { 17 | // set cursor 18 | QPixmap myCursor = QPixmap(( const char ** ) capture_point_cursor ); // const from qgscursors 19 | mCursor = QCursor( myCursor, 8, 8 ); //8,8 is the point in the cursor where clicks register 20 | /* 21 | ** TODO: 22 | ** there is no reason to hold a pointer 23 | ** to MapCanvas when when QgsMapTool has protected member 24 | ** and we are passed one in the constructor 25 | ** remoe it later to see if it still works 26 | */ 27 | mpMapCanvas = canvas; 28 | mpRubberBand = new QgsRubberBand( mpMapCanvas, QGis::Polygon ); 29 | mpRubberBand->setColor( Qt::red ); 30 | mpRubberBand->setWidth( 1 ); 31 | } 32 | 33 | MapToolDriller::~MapToolDriller() 34 | { 35 | if ( mpRubberBand != 0 ) { 36 | delete mpRubberBand; 37 | } 38 | } 39 | 40 | void MapToolDriller::canvasMoveEvent(QMouseEvent * e) 41 | { 42 | QgsPoint myOriginalPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() ); 43 | emit mouseMoved( myOriginalPoint ); 44 | } 45 | 46 | void MapToolDriller::canvasPressEvent(QMouseEvent * e) 47 | { 48 | Q_UNUSED( e ); 49 | } 50 | 51 | void MapToolDriller::canvasReleaseEvent(QMouseEvent * e) 52 | { 53 | if ( !mpMapCanvas || mpMapCanvas->isDrawing() ) 54 | { 55 | return; 56 | } 57 | 58 | QgsPoint myOriginalPoint = 59 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() ); 60 | emit mouseClicked( myOriginalPoint ); 61 | 62 | //make a little box for display 63 | 64 | QgsPoint myPoint1 = 65 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() - 1, e->y() - 1 ); 66 | QgsPoint myPoint2 = 67 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() + 1, e->y() - 1 ); 68 | QgsPoint myPoint3 = 69 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() + 1, e->y() + 1 ); 70 | QgsPoint myPoint4 = 71 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() - 1, e->y() + 1 ); 72 | 73 | mpRubberBand->reset( QGis::Polygon ); 74 | // convert screen coordinates to map coordinates 75 | mpRubberBand->addPoint( myPoint1, false ); //true - update canvas 76 | mpRubberBand->addPoint( myPoint2, false ); //true - update canvas 77 | mpRubberBand->addPoint( myPoint3, false ); //true - update canvas 78 | mpRubberBand->addPoint( myPoint4, true ); //true - update canvas 79 | mpRubberBand->show(); 80 | } 81 | 82 | void MapToolDriller::deactivate() 83 | { 84 | mpRubberBand->reset( QGis::Line ); 85 | QgsMapTool::deactivate(); 86 | } 87 | -------------------------------------------------------------------------------- /plugin_code_examples/04_map_tool_driller_part3/maptooldriller.h: -------------------------------------------------------------------------------- 1 | #ifndef MAPTOOLDRILLER_H 2 | #define MAPTOOLDRILLER_H 3 | 4 | #include "qgsmaptool.h" 5 | #include "qgspoint.h" 6 | #include "qgsmessagelog.h" 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | ** forward declarations instead of include 13 | ** to cut down compile time since we only 14 | ** want one class from the header 15 | */ 16 | class QgsRubberBand; 17 | 18 | class MapToolDriller : public QgsMapTool 19 | { 20 | Q_OBJECT; 21 | 22 | public: 23 | MapToolDriller(QgsMapCanvas* canvas); 24 | 25 | ~MapToolDriller(); 26 | 27 | //! Overridden mouse move event 28 | virtual void canvasMoveEvent(QMouseEvent * e); 29 | 30 | //! Overridden mouse press event 31 | virtual void canvasPressEvent(QMouseEvent * e); 32 | 33 | //! Overridden mouse release event 34 | virtual void canvasReleaseEvent(QMouseEvent * e); 35 | 36 | //! called when map tool is being deactivated 37 | virtual void deactivate(); 38 | 39 | void canvasClickHandler(const QgsPoint&); 40 | 41 | typedef QHash DrillResult; 42 | 43 | public slots: 44 | 45 | signals: 46 | void mouseMoved( QgsPoint ); 47 | 48 | void mouseClicked( QgsPoint ); 49 | 50 | private: 51 | //! Rubber band for dropping visual of click on map 52 | QgsRubberBand * mpRubberBand; 53 | 54 | QPointer mpMapCanvas; 55 | 56 | private slots: 57 | 58 | }; 59 | #endif 60 | -------------------------------------------------------------------------------- /plugin_code_examples/04_map_tool_driller_part3/qgis_maptooldriller.cpp: -------------------------------------------------------------------------------- 1 | #include "qgis_maptooldriller.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_name = QObject::tr("MapToolDrillerz"); 15 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_description = QObject::tr("Sample Plugin"); 16 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_category = QObject::tr("Plugins"); 17 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_version = QObject::tr("Version 0.1.1"); 18 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_icon = ""; 19 | /*static*/ const QgisPlugin::PLUGINTYPE Qgis_MapToolDrillerPLugin::s_type = QgisPlugin::UI; 20 | 21 | // for logging 22 | /*static*/ const QString Qgis_MapToolDrillerPLugin::mTag = QObject::tr("MapToolDriller"); 23 | 24 | QGISEXTERN QgisPlugin* classFactory(QgisInterface* qgis_if) 25 | { 26 | std::cout << "::classFactory" << std::endl; 27 | return new Qgis_MapToolDrillerPLugin(qgis_if); 28 | } 29 | 30 | QGISEXTERN QString name() 31 | { 32 | std::cout << "::name" << std::endl; 33 | return Qgis_MapToolDrillerPLugin::s_name; 34 | } 35 | 36 | QGISEXTERN QString description() 37 | { 38 | std::cout << "::description" << std::endl; 39 | return Qgis_MapToolDrillerPLugin::s_description; 40 | } 41 | 42 | QGISEXTERN QString category() 43 | { 44 | std::cout << "::category" << std::endl; 45 | return Qgis_MapToolDrillerPLugin::s_category; 46 | } 47 | 48 | QGISEXTERN int type() 49 | { 50 | std::cout << "::type" << std::endl; 51 | return Qgis_MapToolDrillerPLugin::s_type; 52 | } 53 | 54 | QGISEXTERN QString version() 55 | { 56 | std::cout << "::version" << std::endl; 57 | return Qgis_MapToolDrillerPLugin::s_version; 58 | } 59 | 60 | QGISEXTERN QString icon() 61 | { 62 | std::cout << "::icon" << std::endl; 63 | return Qgis_MapToolDrillerPLugin::s_icon; 64 | } 65 | 66 | QGISEXTERN void unload(QgisPlugin* plugin) 67 | { 68 | std::cout << "::unload" << std::endl; 69 | delete plugin; 70 | } 71 | 72 | /*virtual*/ Qgis_MapToolDrillerPLugin::~Qgis_MapToolDrillerPLugin() 73 | { 74 | 75 | } 76 | 77 | 78 | /*virtual*/ void Qgis_MapToolDrillerPLugin::initGui() 79 | { 80 | std::cout << "Qgis_MapToolDrillerPLugin::initGui" << std::endl; 81 | 82 | // create the dockable widget 83 | mpDockWidget = new QDockWidget( tr( "MapToolDriller Dockable" ), m_qgis_if->mainWindow() ); 84 | mpDockWidget->setObjectName( "MapToolDriller" ); 85 | mpDockWidget->setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea ); 86 | m_qgis_if->addDockWidget( Qt::LeftDockWidgetArea, mpDockWidget ); 87 | 88 | // add an action to the menu 89 | m_action = new QAction(QIcon("" ), tr("MapToolDriller"), this); 90 | m_action->setCheckable( true ); 91 | m_action->setChecked( mpDockWidget->isVisible() ); 92 | m_action->setWhatsThis(tr("Click on the map canvas like never before")); 93 | connect(m_action, SIGNAL(triggered()), this, SLOT(StartOverlay())); 94 | m_qgis_if->addPluginToMenu(tr("&MapToolDriller"), m_action); 95 | m_qgis_if->addVectorToolBarIcon(m_action); 96 | 97 | // create our map tool 98 | mpMapTool = new MapToolDriller( m_qgis_if->mapCanvas() ); 99 | connect( mpMapTool, SIGNAL( mouseMoved( QgsPoint ) ), this, SLOT( mouseMoved( QgsPoint ) ) ); 100 | connect( mpMapTool, SIGNAL( mouseClicked( QgsPoint ) ), this, SLOT( mouseClicked( QgsPoint ) ) ); 101 | 102 | // create the widget dialog 103 | QWidget * mypWidget = new QWidget(); 104 | QGridLayout *mypLayout = new QGridLayout( mypWidget ); 105 | mypLayout->setColumnMinimumWidth( 0, 36 ); 106 | mypWidget->setLayout( mypLayout ); 107 | 108 | mpOnButton = new QPushButton( mypWidget ); 109 | mpOnButton->setText( tr("Drillerz Away") ); 110 | mpOnButton->setToolTip( tr( "Click to start drillerzen away" ) ); 111 | connect( mpOnButton, SIGNAL( clicked() ), this, SLOT( run() ) ); 112 | 113 | mpFeedbackEdit = new QLineEdit( mypWidget ); 114 | mpFeedbackEdit->setReadOnly( true ); 115 | mpFeedbackEdit->setToolTip( tr( "Copy this stuff if you think it's useful" ) ); 116 | 117 | mypLayout->addWidget( mpOnButton, 0, 0 ); 118 | mypLayout->addWidget( mpFeedbackEdit, 1, 0 ); 119 | 120 | // now add our custom widget to the dock - ownership of the widget is passed to the dock 121 | mpDockWidget->setWidget( mypWidget ); 122 | connect( mpDockWidget, SIGNAL( visibilityChanged( bool ) ), m_action, SLOT( setChecked( bool ) ) ); 123 | } 124 | 125 | 126 | void Qgis_MapToolDrillerPLugin::mouseClicked( QgsPoint thePoint ) 127 | { 128 | QString mFeedback = thePoint.toString(); 129 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 130 | mpFeedbackEdit->setText( mFeedback ); 131 | } 132 | void Qgis_MapToolDrillerPLugin::mouseMoved( QgsPoint thePoint ) 133 | { 134 | QString mFeedback = thePoint.toString(); 135 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 136 | } 137 | 138 | void Qgis_MapToolDrillerPLugin::run(){ 139 | m_qgis_if->mapCanvas()->setMapTool( mpMapTool ); 140 | } 141 | 142 | void Qgis_MapToolDrillerPLugin::help(){ 143 | // implement me 144 | } 145 | 146 | void Qgis_MapToolDrillerPLugin::showOrHide(){ 147 | if ( !mpDockWidget ) 148 | run(); 149 | else 150 | if ( m_action->isChecked() ) 151 | mpDockWidget->show(); 152 | else 153 | mpDockWidget->hide(); 154 | } 155 | 156 | 157 | void Qgis_MapToolDrillerPLugin::StartOverlay() 158 | { 159 | std::cout << "Qgis_MapToolDrillerPLugin::StartOverlay" << std::endl; 160 | 161 | // show or hide 162 | showOrHide(); 163 | 164 | // Get the map canvas 165 | QgsMapCanvas* canvas = m_qgis_if->mapCanvas(); 166 | 167 | // Layer QStrings 168 | QString mLayerPath = "/home/junkmob/QGIS-DEV/QGIS/tests/testdata/points.shp"; 169 | QString mLayerBaseName = "points"; 170 | QString mProviderName = "ogr"; 171 | 172 | // Get Vector Layer 173 | QgsVectorLayer * mLayer = new QgsVectorLayer(mLayerPath, mLayerBaseName, mProviderName); 174 | if (mLayer->isValid()) 175 | { 176 | QString mFeedback = "layer is valid"; 177 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 178 | } 179 | else 180 | { 181 | QString mFeedback = "layer NOT valid"; 182 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 183 | } 184 | 185 | // Add the Vector Layer to the Layer Registry 186 | QgsMapLayerRegistry::instance()->addMapLayer(mLayer, TRUE); 187 | 188 | // Add the Layer to the Layer Set 189 | QList mLayerSet; 190 | mLayerSet.append(QgsMapCanvasLayer(mLayer, TRUE)); 191 | 192 | // Create the Map Canvas 193 | canvas->setExtent(mLayer->extent()); 194 | canvas->enableAntiAliasing(true); 195 | canvas->setCanvasColor(QColor(255, 255, 255)); 196 | canvas->freeze(false); 197 | 198 | // add it to the canvas 199 | canvas->setLayerSet( mLayerSet ); 200 | canvas->setVisible(true); 201 | canvas->refresh(); 202 | 203 | } 204 | 205 | -------------------------------------------------------------------------------- /plugin_code_examples/04_map_tool_driller_part3/qgis_maptooldriller.h: -------------------------------------------------------------------------------- 1 | #ifndef QGIS_MAPTOOLDRILLER_H 2 | #define QGIS_MAPTOOLDRILLER_H 3 | 4 | #include "maptooldriller.h" 5 | 6 | #include "qgisplugin.h" 7 | #include "qgsmapcanvas.h" 8 | #include "qgisinterface.h" 9 | #include "qgsvectorlayer.h" 10 | #include "qgsmessagelog.h" 11 | #include "qgsmaplayerregistry.h" 12 | #include 13 | 14 | // forward declarations 15 | class QAction; 16 | class QToolBar; 17 | class QToolButton; 18 | class QPushButton; 19 | class QDockWidget; 20 | class QLineEdit; 21 | class QIcon; 22 | class QLabel; 23 | 24 | class Qgis_MapToolDrillerPLugin : public QObject, public QgisPlugin 25 | { 26 | Q_OBJECT 27 | 28 | public: 29 | static const QString s_name, s_description, s_category, s_version, s_icon; 30 | 31 | static const QgisPlugin::PLUGINTYPE s_type; 32 | 33 | static const QString mTag; 34 | 35 | //! constructor 36 | Qgis_MapToolDrillerPLugin(QgisInterface* qgis_if) : 37 | QgisPlugin(s_name, s_description, s_category, s_version, s_type), m_qgis_if(qgis_if) 38 | { 39 | 40 | } 41 | 42 | //! destructor 43 | virtual ~Qgis_MapToolDrillerPLugin(); 44 | 45 | virtual void unload(){ 46 | std::cout << "Qgis_MapToolDrillerPLugin::unload" << std::endl; 47 | } 48 | 49 | public slots: 50 | // virtual methods from QgisPlugin 51 | virtual void initGui(); 52 | 53 | void run(); 54 | 55 | void showOrHide(); 56 | 57 | void help(); 58 | 59 | //! Called when mouse clicks on the canvas. Will populate text box with coords. 60 | void mouseClicked( QgsPoint thePoint ); 61 | 62 | //! Called when mouse moved over the canvas. 63 | void mouseMoved( QgsPoint thePoint ); 64 | 65 | void StartOverlay(); 66 | 67 | private: 68 | 69 | MapToolDriller* mpMapTool; 70 | 71 | QPointer mpDockWidget; 72 | 73 | QPointer mpFeedbackEdit; 74 | 75 | QPushButton * mpOnButton; 76 | 77 | QgisInterface* m_qgis_if; 78 | 79 | QAction* m_action; 80 | 81 | 82 | }; 83 | 84 | #endif // #ifndef QGIS_MAPTOOLDRILLER_H 85 | -------------------------------------------------------------------------------- /plugin_code_examples/04_map_tool_driller_part3/qgis_maptooldriller.pro: -------------------------------------------------------------------------------- 1 | #QGIS_DIR = /home/junkmob/QGIS-APP/lib/qgis 2 | TEMPLATE = lib 3 | CONFIG = qt 4 | QT += xml qt3support 5 | LIBS += -L/home/junkmob/QGIS-APP/lib -lqgis_core -lqgis_gui 6 | #INCLUDEPATH += $$QGIS_DIR/src/ui $$QGIS_DIR/src/plugins $$QGIS_DIR/src/gui $$QGIS_DIR/src/raster $$QGIS_DIR/src/core $$QGIS_DIR 7 | INCLUDEPATH += /home/junkmob/QGIS-APP/include/qgis 8 | SOURCES = qgis_maptooldriller.cpp maptooldriller.cpp 9 | HEADERS = qgis_maptooldriller.h maptooldriller.h 10 | DEST = qgis_maptooldriller.so 11 | DEFINES += GUI_EXPORT= CORE_EXPORT= 12 | -------------------------------------------------------------------------------- /plugin_code_examples/05_map_tool_driller_part4/README.md: -------------------------------------------------------------------------------- 1 | ###Build dependecies 2 | 3 | 1. You will need QGIS source and all the dependecies. The [build instructions](https://github.com/qgis/QGIS/blob/master/INSTALL#L85-L340) you should follow are very clear. 4 | 5 | ###Building 6 | 7 | 1. run `$ qmake qgis_maptooldriller.pro` to create the Makefile 8 | 9 | 2. run `make` to build the dynamic .so lib 10 | 11 | 3. copy or link it to the qgis plugins directory: `sudo cp liqgis_maptooldriller.so.1.0.0 /usr/lib/qgis/plugins/` 12 | 13 | 14 | -------------------------------------------------------------------------------- /plugin_code_examples/05_map_tool_driller_part4/maptooldriller.cpp: -------------------------------------------------------------------------------- 1 | #include "maptooldriller.h" 2 | #include "qgscursors.h" 3 | #include "qgsmapcanvas.h" 4 | #include "qgsmaptopixel.h" 5 | #include "qgsrubberband.h" 6 | #include "qgscoordinatereferencesystem.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | MapToolDriller::MapToolDriller(QgsMapCanvas* canvas) : QgsMapTool(canvas) 16 | { 17 | // set cursor 18 | QPixmap myCursor = QPixmap(( const char ** ) capture_point_cursor ); // const from qgscursors 19 | mCursor = QCursor( myCursor, 8, 8 ); //8,8 is the point in the cursor where clicks register 20 | /* 21 | ** TODO: 22 | ** there is no reason to hold a pointer 23 | ** to MapCanvas when when QgsMapTool has protected member 24 | ** and we are passed one in the constructor 25 | ** remoe it later to see if it still works 26 | */ 27 | mpMapCanvas = canvas; 28 | mpRubberBand = new QgsRubberBand( mpMapCanvas, QGis::Polygon ); 29 | mpRubberBand->setColor( Qt::red ); 30 | mpRubberBand->setWidth( 1 ); 31 | } 32 | 33 | MapToolDriller::~MapToolDriller() 34 | { 35 | if ( mpRubberBand != 0 ) { 36 | delete mpRubberBand; 37 | } 38 | } 39 | 40 | void MapToolDriller::canvasMoveEvent(QMouseEvent * e) 41 | { 42 | QgsPoint myOriginalPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() ); 43 | emit mouseMoved( myOriginalPoint ); 44 | } 45 | 46 | void MapToolDriller::canvasPressEvent(QMouseEvent * e) 47 | { 48 | Q_UNUSED( e ); 49 | } 50 | 51 | void MapToolDriller::canvasReleaseEvent(QMouseEvent * e) 52 | { 53 | if ( !mpMapCanvas || mpMapCanvas->isDrawing() ) 54 | { 55 | return; 56 | } 57 | 58 | QgsPoint myOriginalPoint = 59 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() ); 60 | emit mouseClicked( myOriginalPoint ); 61 | 62 | //make a little box for display 63 | 64 | QgsPoint myPoint1 = 65 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() - 1, e->y() - 1 ); 66 | QgsPoint myPoint2 = 67 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() + 1, e->y() - 1 ); 68 | QgsPoint myPoint3 = 69 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() + 1, e->y() + 1 ); 70 | QgsPoint myPoint4 = 71 | mCanvas->getCoordinateTransform()->toMapCoordinates( e->x() - 1, e->y() + 1 ); 72 | 73 | mpRubberBand->reset( QGis::Polygon ); 74 | // convert screen coordinates to map coordinates 75 | mpRubberBand->addPoint( myPoint1, false ); //true - update canvas 76 | mpRubberBand->addPoint( myPoint2, false ); //true - update canvas 77 | mpRubberBand->addPoint( myPoint3, false ); //true - update canvas 78 | mpRubberBand->addPoint( myPoint4, true ); //true - update canvas 79 | mpRubberBand->show(); 80 | } 81 | 82 | void MapToolDriller::deactivate() 83 | { 84 | mpRubberBand->reset( QGis::Line ); 85 | QgsMapTool::deactivate(); 86 | } 87 | -------------------------------------------------------------------------------- /plugin_code_examples/05_map_tool_driller_part4/maptooldriller.h: -------------------------------------------------------------------------------- 1 | #ifndef MAPTOOLDRILLER_H 2 | #define MAPTOOLDRILLER_H 3 | 4 | #include "qgsmaptool.h" 5 | #include "qgspoint.h" 6 | #include "qgsmessagelog.h" 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | ** forward declarations instead of include 13 | ** to cut down compile time since we only 14 | ** want one class from the header 15 | */ 16 | class QgsRubberBand; 17 | 18 | class MapToolDriller : public QgsMapTool 19 | { 20 | Q_OBJECT; 21 | 22 | public: 23 | MapToolDriller(QgsMapCanvas* canvas); 24 | 25 | ~MapToolDriller(); 26 | 27 | //! Overridden mouse move event 28 | virtual void canvasMoveEvent(QMouseEvent * e); 29 | 30 | //! Overridden mouse press event 31 | virtual void canvasPressEvent(QMouseEvent * e); 32 | 33 | //! Overridden mouse release event 34 | virtual void canvasReleaseEvent(QMouseEvent * e); 35 | 36 | //! called when map tool is being deactivated 37 | virtual void deactivate(); 38 | 39 | void canvasClickHandler(const QgsPoint&); 40 | 41 | typedef QHash DrillResult; 42 | 43 | public slots: 44 | 45 | signals: 46 | void mouseMoved( QgsPoint ); 47 | 48 | void mouseClicked( QgsPoint ); 49 | 50 | private: 51 | //! Rubber band for dropping visual of click on map 52 | QgsRubberBand * mpRubberBand; 53 | 54 | QPointer mpMapCanvas; 55 | 56 | private slots: 57 | 58 | }; 59 | #endif 60 | -------------------------------------------------------------------------------- /plugin_code_examples/05_map_tool_driller_part4/qgis_maptooldriller.cpp: -------------------------------------------------------------------------------- 1 | #include "qgis_maptooldriller.h" 2 | 3 | #include "qgsgeometry.h" 4 | #include "qgsrectangle.h" 5 | #include "qgsfeature.h" 6 | #include "qgsfeaturerequest.h" 7 | #include "qgsfeatureiterator.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_name = QObject::tr("MapToolDrillerz"); 21 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_description = QObject::tr("Sample Plugin"); 22 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_category = QObject::tr("Plugins"); 23 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_version = QObject::tr("Version 0.1.1"); 24 | /*static*/ const QString Qgis_MapToolDrillerPLugin::s_icon = ""; 25 | /*static*/ const QgisPlugin::PLUGINTYPE Qgis_MapToolDrillerPLugin::s_type = QgisPlugin::UI; 26 | 27 | // for logging 28 | /*static*/ const QString Qgis_MapToolDrillerPLugin::mTag = QObject::tr("MapToolDriller"); 29 | 30 | QGISEXTERN QgisPlugin* classFactory(QgisInterface* qgis_if) 31 | { 32 | std::cout << "::classFactory" << std::endl; 33 | return new Qgis_MapToolDrillerPLugin(qgis_if); 34 | } 35 | 36 | QGISEXTERN QString name() 37 | { 38 | std::cout << "::name" << std::endl; 39 | return Qgis_MapToolDrillerPLugin::s_name; 40 | } 41 | 42 | QGISEXTERN QString description() 43 | { 44 | std::cout << "::description" << std::endl; 45 | return Qgis_MapToolDrillerPLugin::s_description; 46 | } 47 | 48 | QGISEXTERN QString category() 49 | { 50 | std::cout << "::category" << std::endl; 51 | return Qgis_MapToolDrillerPLugin::s_category; 52 | } 53 | 54 | QGISEXTERN int type() 55 | { 56 | std::cout << "::type" << std::endl; 57 | return Qgis_MapToolDrillerPLugin::s_type; 58 | } 59 | 60 | QGISEXTERN QString version() 61 | { 62 | std::cout << "::version" << std::endl; 63 | return Qgis_MapToolDrillerPLugin::s_version; 64 | } 65 | 66 | QGISEXTERN QString icon() 67 | { 68 | std::cout << "::icon" << std::endl; 69 | return Qgis_MapToolDrillerPLugin::s_icon; 70 | } 71 | 72 | QGISEXTERN void unload(QgisPlugin* plugin) 73 | { 74 | std::cout << "::unload" << std::endl; 75 | delete plugin; 76 | } 77 | 78 | /*virtual*/ Qgis_MapToolDrillerPLugin::~Qgis_MapToolDrillerPLugin() 79 | { 80 | 81 | } 82 | 83 | 84 | /*virtual*/ void Qgis_MapToolDrillerPLugin::initGui() 85 | { 86 | std::cout << "Qgis_MapToolDrillerPLugin::initGui" << std::endl; 87 | 88 | // create the dockable widget 89 | mpDockWidget = new QDockWidget( tr( "MapToolDriller Dockable" ), m_qgis_if->mainWindow() ); 90 | mpDockWidget->setObjectName( "MapToolDriller" ); 91 | mpDockWidget->setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea ); 92 | m_qgis_if->addDockWidget( Qt::LeftDockWidgetArea, mpDockWidget ); 93 | 94 | // add an action to the menu 95 | m_action = new QAction(QIcon("" ), tr("MapToolDriller"), this); 96 | m_action->setCheckable( true ); 97 | m_action->setChecked( mpDockWidget->isVisible() ); 98 | m_action->setWhatsThis(tr("Click on the map canvas like never before")); 99 | connect(m_action, SIGNAL(triggered()), this, SLOT(StartOverlay())); 100 | m_qgis_if->addPluginToMenu(tr("&MapToolDriller"), m_action); 101 | m_qgis_if->addVectorToolBarIcon(m_action); 102 | 103 | // connect QgisInterface.currentLayerChanged to our handler 104 | connect( m_qgis_if, SIGNAL( currentLayerChanged( QgsMapLayer* ) ), this, SLOT( currentLayerChanged( QgsMapLayer * ) ) ); 105 | 106 | // create our map tool 107 | mpMapTool = new MapToolDriller( m_qgis_if->mapCanvas() ); 108 | //connect( mpMapTool, SIGNAL( mouseMoved( QgsPoint ) ), this, SLOT( mouseMoved( QgsPoint ) ) ); 109 | connect( mpMapTool, SIGNAL( mouseClicked( QgsPoint ) ), this, SLOT( mouseClicked( QgsPoint ) ) ); 110 | 111 | // create the widget dialog 112 | QWidget * mypWidget = new QWidget(); 113 | QGridLayout *mypLayout = new QGridLayout( mypWidget ); 114 | mypLayout->setColumnMinimumWidth( 0, 36 ); 115 | mypWidget->setLayout( mypLayout ); 116 | 117 | mpOnButton = new QPushButton( mypWidget ); 118 | mpOnButton->setText( tr("Drillerz Away") ); 119 | mpOnButton->setToolTip( tr( "Click to start drillerzen away" ) ); 120 | connect( mpOnButton, SIGNAL( clicked() ), this, SLOT( run() ) ); 121 | 122 | mpFeedbackEdit = new QLineEdit( mypWidget ); 123 | mpFeedbackEdit->setReadOnly( true ); 124 | mpFeedbackEdit->setToolTip( tr( "Copy this stuff if you think it's useful" ) ); 125 | 126 | mypLayout->addWidget( mpOnButton, 0, 0 ); 127 | mypLayout->addWidget( mpFeedbackEdit, 1, 0 ); 128 | 129 | // now add our custom widget to the dock - ownership of the widget is passed to the dock 130 | mpDockWidget->setWidget( mypWidget ); 131 | connect( mpDockWidget, SIGNAL( visibilityChanged( bool ) ), m_action, SLOT( setChecked( bool ) ) ); 132 | } 133 | 134 | void Qgis_MapToolDrillerPLugin::currentLayerChanged( QgsMapLayer *currentLayer ) 135 | { 136 | QString mFeedback = ""; 137 | if( !currentLayer ){ 138 | mFeedback = "NULL layer pointer"; 139 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 140 | return; 141 | } 142 | 143 | if ( currentLayer->type() == QgsMapLayer::VectorLayer ) { 144 | // remove mpCurrentMapLayer's setSelected event handler 145 | try { 146 | disconnect( this, SLOT( selectionChanged( const QgsFeatureIds, const QgsFeatureIds, const bool ) ) ); 147 | } 148 | catch (...) { 149 | mFeedback = "could not disconnect this object from selectionChanged event"; 150 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 151 | } 152 | 153 | // cast the current layer to our vector layer ref 154 | mpCurrentMapLayer = dynamic_cast(currentLayer); 155 | connect( mpCurrentMapLayer, 156 | SIGNAL( selectionChanged( const QgsFeatureIds, const QgsFeatureIds, const bool ) ), 157 | this, 158 | SLOT( selectionChanged( const QgsFeatureIds, const QgsFeatureIds, const bool ) ) 159 | ); 160 | 161 | // set provider 162 | mpCurrentVectorProvider = mpCurrentMapLayer->dataProvider(); 163 | } 164 | else if( currentLayer->type() == QgsMapLayer::RasterLayer ) { 165 | mFeedback = "raster layers not supported yet"; 166 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 167 | } 168 | }; 169 | 170 | 171 | void Qgis_MapToolDrillerPLugin::mouseClicked( QgsPoint thePoint ) 172 | { 173 | /* 174 | QString mFeedback = thePoint.toString(); 175 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 176 | mpFeedbackEdit->setText( mFeedback ); 177 | */ 178 | // Get the map canvas 179 | QString mFeedback = ""; 180 | QgsMapCanvas* canvas = m_qgis_if->mapCanvas(); 181 | 182 | QgsGeometry *geom = QgsGeometry::fromPoint( thePoint ); 183 | QgsGeometry *buff = geom->buffer( ( canvas->mapUnitsPerPixel() * 20 ), 0 ); 184 | QgsRectangle rect = buff->boundingBox(); 185 | if( !mpCurrentMapLayer ) { 186 | //QMessageBox.information( self.iface.mainWindow(),"Info", "No layer currently selected in TOC" ) 187 | mFeedback = "current layer is NULL"; 188 | QgsMessageLog::instance()->logMessage( mFeedback , mTag, QgsMessageLog::INFO ); 189 | return; 190 | } 191 | 192 | QgsFeatureRequest *featRequest = new QgsFeatureRequest( rect ); 193 | QgsFeatureIterator iter = mpCurrentVectorProvider->getFeatures( *featRequest ); 194 | QgsFeature feat; 195 | mpFeatureIds.clear(); 196 | while( iter.nextFeature( feat ) ) { 197 | QgsGeometry *g = feat.geometry(); 198 | if ( g->intersects( rect ) ) { 199 | mpFeatureIds.insert( feat.id() ); 200 | } 201 | } 202 | 203 | if ( mpFeatureIds.count() > 0 ) { 204 | mpCurrentMapLayer->setSelectedFeatures( mpFeatureIds ); 205 | QgsMessageLog::instance()->logMessage( tr("setSelectedFeatures called"), mTag, QgsMessageLog::INFO ); 206 | } 207 | 208 | } 209 | 210 | void Qgis_MapToolDrillerPLugin::selectionChanged( const QgsFeatureIds selected, const QgsFeatureIds deselected, const bool clearAndSelect ) 211 | { 212 | if( mpFeatureIds.count() == 0 ) return; 213 | QString fieldName = "Class"; 214 | int fieldIndx = mpCurrentMapLayer->fieldNameIndex( fieldName ); 215 | 216 | QgsFeatureRequest featRequest = QgsFeatureRequest().setFilterFids( mpFeatureIds ); 217 | QgsFeatureIterator iter = mpCurrentMapLayer->getFeatures( featRequest ); 218 | QgsFeature feat; 219 | while( iter.nextFeature( feat ) ) { 220 | QgsAttributes attrs = feat.attributes(); 221 | QString class_value = attrs[ fieldIndx ].toString(); 222 | mpFeedbackEdit->setText( class_value ); 223 | } 224 | } 225 | 226 | void Qgis_MapToolDrillerPLugin::mouseMoved( QgsPoint thePoint ) 227 | { 228 | QString mFeedback = thePoint.toString(); 229 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 230 | } 231 | 232 | void Qgis_MapToolDrillerPLugin::run(){ 233 | m_qgis_if->mapCanvas()->setMapTool( mpMapTool ); 234 | } 235 | 236 | void Qgis_MapToolDrillerPLugin::help(){ 237 | // implement me 238 | } 239 | 240 | void Qgis_MapToolDrillerPLugin::showOrHide(){ 241 | if ( !mpDockWidget ) 242 | run(); 243 | else 244 | if ( m_action->isChecked() ) 245 | mpDockWidget->show(); 246 | else 247 | mpDockWidget->hide(); 248 | } 249 | 250 | 251 | void Qgis_MapToolDrillerPLugin::StartOverlay() 252 | { 253 | std::cout << "Qgis_MapToolDrillerPLugin::StartOverlay" << std::endl; 254 | 255 | // show or hide 256 | showOrHide(); 257 | 258 | // Get the map canvas 259 | QgsMapCanvas* canvas = m_qgis_if->mapCanvas(); 260 | 261 | // Layer QStrings 262 | QString mLayerPath = "/home/junkmob/QGIS-DEV/QGIS/tests/testdata/points.shp"; 263 | QString mLayerBaseName = "points"; 264 | QString mProviderName = "ogr"; 265 | 266 | // Get Vector Layer 267 | QgsVectorLayer * mLayer = new QgsVectorLayer(mLayerPath, mLayerBaseName, mProviderName); 268 | if (mLayer->isValid()) 269 | { 270 | QString mFeedback = "layer is valid"; 271 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 272 | } 273 | else 274 | { 275 | QString mFeedback = "layer NOT valid"; 276 | QgsMessageLog::instance()->logMessage( mFeedback, mTag, QgsMessageLog::INFO ); 277 | } 278 | 279 | // Add the Vector Layer to the Layer Registry 280 | QgsMapLayerRegistry::instance()->addMapLayer(mLayer, TRUE); 281 | 282 | // Add the Layer to the Layer Set 283 | QList mLayerSet; 284 | mLayerSet.append(QgsMapCanvasLayer(mLayer, TRUE)); 285 | 286 | // Create the Map Canvas 287 | canvas->setExtent(mLayer->extent()); 288 | canvas->enableAntiAliasing(true); 289 | canvas->setCanvasColor(QColor(255, 255, 255)); 290 | canvas->freeze(false); 291 | 292 | // add it to the canvas 293 | canvas->setLayerSet( mLayerSet ); 294 | canvas->setVisible(true); 295 | canvas->refresh(); 296 | 297 | } 298 | 299 | -------------------------------------------------------------------------------- /plugin_code_examples/05_map_tool_driller_part4/qgis_maptooldriller.h: -------------------------------------------------------------------------------- 1 | #ifndef QGIS_MAPTOOLDRILLER_H 2 | #define QGIS_MAPTOOLDRILLER_H 3 | 4 | #include "maptooldriller.h" 5 | 6 | #include "qgisplugin.h" 7 | #include "qgsmapcanvas.h" 8 | #include "qgisinterface.h" 9 | #include "qgsvectorlayer.h" 10 | #include "qgsvectordataprovider.h" 11 | #include "qgsmessagelog.h" 12 | #include "qgsmaplayerregistry.h" 13 | #include 14 | 15 | // forward declarations 16 | class QAction; 17 | class QToolBar; 18 | class QToolButton; 19 | class QPushButton; 20 | class QDockWidget; 21 | class QLineEdit; 22 | class QIcon; 23 | class QLabel; 24 | 25 | class Qgis_MapToolDrillerPLugin : public QObject, public QgisPlugin 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | static const QString s_name, s_description, s_category, s_version, s_icon; 31 | 32 | static const QgisPlugin::PLUGINTYPE s_type; 33 | 34 | static const QString mTag; 35 | 36 | //! constructor 37 | Qgis_MapToolDrillerPLugin(QgisInterface* qgis_if) : 38 | QgisPlugin(s_name, s_description, s_category, s_version, s_type), m_qgis_if(qgis_if) 39 | { 40 | 41 | } 42 | 43 | //! destructor 44 | virtual ~Qgis_MapToolDrillerPLugin(); 45 | 46 | virtual void unload(){ 47 | std::cout << "Qgis_MapToolDrillerPLugin::unload" << std::endl; 48 | } 49 | 50 | public slots: 51 | // virtual methods from QgisPlugin 52 | virtual void initGui(); 53 | 54 | void run(); 55 | 56 | void showOrHide(); 57 | 58 | void help(); 59 | 60 | //! Called when mouse clicks on the canvas. Will populate text box with coords. 61 | void mouseClicked( QgsPoint thePoint ); 62 | 63 | //! Called when mouse moved over the canvas. 64 | void mouseMoved( QgsPoint thePoint ); 65 | 66 | //! Called when QgisInterface.currentLayerChanged 67 | void currentLayerChanged( QgsMapLayer* currentLayer ); 68 | 69 | //! triggered after new selection is fired 70 | void selectionChanged(QgsFeatureIds, QgsFeatureIds, bool); 71 | 72 | void StartOverlay(); 73 | 74 | private: 75 | 76 | MapToolDriller* mpMapTool; 77 | 78 | QPointer mpDockWidget; 79 | 80 | QPointer mpFeedbackEdit; 81 | 82 | QPushButton * mpOnButton; 83 | 84 | QgisInterface* m_qgis_if; 85 | 86 | QAction* m_action; 87 | 88 | QgsVectorLayer* mpCurrentMapLayer; 89 | 90 | QgsVectorDataProvider* mpCurrentVectorProvider; 91 | 92 | QgsLegendInterface* mpLegendInterface; 93 | 94 | QgsFeatureIds mpFeatureIds; 95 | 96 | }; 97 | 98 | #endif // #ifndef QGIS_MAPTOOLDRILLER_H 99 | -------------------------------------------------------------------------------- /plugin_code_examples/05_map_tool_driller_part4/qgis_maptooldriller.pro: -------------------------------------------------------------------------------- 1 | #QGIS_DIR = /home/junkmob/QGIS-APP/lib/qgis 2 | TEMPLATE = lib 3 | CONFIG = qt 4 | QT += xml qt3support 5 | LIBS += -L/home/junkmob/QGIS-APP/lib -lqgis_core -lqgis_gui 6 | #INCLUDEPATH += $$QGIS_DIR/src/ui $$QGIS_DIR/src/plugins $$QGIS_DIR/src/gui $$QGIS_DIR/src/raster $$QGIS_DIR/src/core $$QGIS_DIR 7 | INCLUDEPATH += /home/junkmob/QGIS-APP/include/qgis 8 | SOURCES = qgis_maptooldriller.cpp maptooldriller.cpp 9 | HEADERS = qgis_maptooldriller.h maptooldriller.h 10 | DEST = qgis_maptooldriller.so 11 | DEFINES += GUI_EXPORT= CORE_EXPORT= 12 | -------------------------------------------------------------------------------- /plugin_code_examples/MASTER_BUG_FIXES: -------------------------------------------------------------------------------- 1 | 1. plugin_builder.py would be nice to have colored questions 2 | 3 | 2. coordinate_capture doesn't wipe last point after using the tool ever 4 | 5 | 3. whatever workflow problems are discovered in the cmake/plugin_builder workflow 6 | -------------------------------------------------------------------------------- /plugin_code_examples/README.md: -------------------------------------------------------------------------------- 1 | 1. Create a new directory for your example 2 | 3 | 2. Add your header and .cpp files 4 | 5 | 3. Create a tar/zipfile that includes all your code ( for easy download links ) 6 | 7 | 4. Create a readme for your example that explains any build information 8 | -------------------------------------------------------------------------------- /plugin_code_examples/TARGETS: -------------------------------------------------------------------------------- 1 | workflows: 2 | 3 | 1. Load Vector Layer 4 | 2. Log mouse coords on click with built in QgsEmitToolMapPoint 5 | 3. Subclass QgsMapTool and make a tool that emits points to logger onClick and onMove 6 | 4. Create a first-class GUI so we don't have to log to the logger anymore and we can present feedback in popup window 7 | 5. Build an info driller that gets all attributes for Vector or Raster layers 8 | 6. Introduce plugin_builder with cmake workflow 9 | 7. 10 | 11 | 12 | -------------------------------------------------------------------------------- /source.json: -------------------------------------------------------------------------------- 1 | ### Another Cookbook 2 | Yep. QGIS uses the [Qt Project](http://qt-project.org/doc/qt-5.1/qtdoc/index.html) 3 | as the main GUI building block. Both projects have C++ intefaces. Given that, 4 | it is surprising the QGIS community does not have a good tutorial on building plugins 5 | in the native interface ( it's actually not that surpising. See the next section ): 6 | 7 | - Some proof of the need [here](http://hub.qgis.org/wiki/17/Writing_C++_Plugins_%5BNew%5D) 8 | and [here](http://gis.stackexchange.com/questions/34147/where-can-i-find-documentation-on-qgis-c-plugin-development). 9 | 10 | - Existing code examples ( that are not core C++ plugins themselves ) are old 11 | and don't cover the new QGIS 2.0 API ( [here](https://github.com/qgis/QGIS-Code-Examples) ) 12 | 13 | ### Should I Build QGIS Plugins in Python or C++? 14 | Probably Python. The QGIS community has put a lot of effort into documenting how to build Python 15 | plugins. One benefit of using Python is that you don't have to deal with all the different operating 16 | systems, build enviroments and plugin distribution. 17 | 18 | That said, if you are a C++ programmer and learning Python seems boring, then this 19 | tutorial will show you how to become familiar with the API basics. You can deal 20 | with the distribution issues on your own. 21 | 22 | ### How to Use the Cookbook 23 | Go over to this repo's [example plugins](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples) 24 | directory and go into `01_hello_world`. 25 | 26 | ### How to Contribute to the Cookbook 27 | ```bash 28 | DISCLAIMER: Most of the recipes by the auther only cover 29 | building tools with gcc on Ubuntu Linux 30 | ``` 31 | 32 | 1. clone the repo 33 | 34 | 2. install node 35 | 36 | 3. get coffee 37 | 38 | 4. make money 39 | 40 | 5. more to come 41 | 42 | 6. udpate the next section 43 | 44 | ### Current Plugin Tutorials 45 | 46 | 1. [Hello World](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples/01_hello_world)( `qmake` versus `cmake` workflows ) 47 | 48 | 2. [Map Tool Driller ( part 1 )](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples/02_map_tool_driller_part1) 49 | 50 | 3. [Map Tool Driller ( part 2 )](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples/03_map_tool_driller_part2) 51 | 52 | 4. [Map Tool Driller ( part 3 )](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/tree/gh-pages/plugin_code_examples/04_map_tool_driller_part3) 53 | 54 | 5. Map Tool Driller ( part 4 ) 55 | 56 | ### Authors and Contributors 57 | Greg Corradini ( @thebigspoon ) and James Dominguez ( @keppy ) 58 | 59 | ### Support or Contact 60 | Drop it like it's hot on the [issue page over here](https://github.com/thebigspoon/qgis_cpp_plugin_cookbook/issues) 61 | -------------------------------------------------------------------------------- /stylesheets/print.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { 14 | margin: 0; 15 | padding: 0; 16 | border: 0; 17 | font-size: 100%; 18 | font: inherit; 19 | vertical-align: baseline; 20 | } 21 | /* HTML5 display-role reset for older browsers */ 22 | article, aside, details, figcaption, figure, 23 | footer, header, hgroup, menu, nav, section { 24 | display: block; 25 | } 26 | body { 27 | line-height: 1; 28 | } 29 | ol, ul { 30 | list-style: none; 31 | } 32 | blockquote, q { 33 | quotes: none; 34 | } 35 | blockquote:before, blockquote:after, 36 | q:before, q:after { 37 | content: ''; 38 | content: none; 39 | } 40 | table { 41 | border-collapse: collapse; 42 | border-spacing: 0; 43 | } 44 | body { 45 | font-size: 13px; 46 | line-height: 1.5; 47 | font-family: 'Helvetica Neue', Helvetica, Arial, serif; 48 | color: #000; 49 | } 50 | 51 | a { 52 | color: #d5000d; 53 | font-weight: bold; 54 | } 55 | 56 | header { 57 | padding-top: 35px; 58 | padding-bottom: 10px; 59 | } 60 | 61 | header h1 { 62 | font-weight: bold; 63 | letter-spacing: -1px; 64 | font-size: 48px; 65 | color: #303030; 66 | line-height: 1.2; 67 | } 68 | 69 | header h2 { 70 | letter-spacing: -1px; 71 | font-size: 24px; 72 | color: #aaa; 73 | font-weight: normal; 74 | line-height: 1.3; 75 | } 76 | #downloads { 77 | display: none; 78 | } 79 | #main_content { 80 | padding-top: 20px; 81 | } 82 | 83 | code, pre { 84 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal; 85 | color: #222; 86 | margin-bottom: 30px; 87 | font-size: 12px; 88 | } 89 | 90 | code { 91 | padding: 0 3px; 92 | } 93 | 94 | pre { 95 | border: solid 1px #ddd; 96 | padding: 20px; 97 | overflow: auto; 98 | } 99 | pre code { 100 | padding: 0; 101 | } 102 | 103 | ul, ol, dl { 104 | margin-bottom: 20px; 105 | } 106 | 107 | 108 | /* COMMON STYLES */ 109 | 110 | table { 111 | width: 100%; 112 | border: 1px solid #ebebeb; 113 | } 114 | 115 | th { 116 | font-weight: 500; 117 | } 118 | 119 | td { 120 | border: 1px solid #ebebeb; 121 | text-align: center; 122 | font-weight: 300; 123 | } 124 | 125 | form { 126 | background: #f2f2f2; 127 | padding: 20px; 128 | 129 | } 130 | 131 | 132 | /* GENERAL ELEMENT TYPE STYLES */ 133 | 134 | h1 { 135 | font-size: 2.8em; 136 | } 137 | 138 | h2 { 139 | font-size: 22px; 140 | font-weight: bold; 141 | color: #303030; 142 | margin-bottom: 8px; 143 | } 144 | 145 | h3 { 146 | color: #d5000d; 147 | font-size: 18px; 148 | font-weight: bold; 149 | margin-bottom: 8px; 150 | } 151 | 152 | h4 { 153 | font-size: 16px; 154 | color: #303030; 155 | font-weight: bold; 156 | } 157 | 158 | h5 { 159 | font-size: 1em; 160 | color: #303030; 161 | } 162 | 163 | h6 { 164 | font-size: .8em; 165 | color: #303030; 166 | } 167 | 168 | p { 169 | font-weight: 300; 170 | margin-bottom: 20px; 171 | } 172 | 173 | a { 174 | text-decoration: none; 175 | } 176 | 177 | p a { 178 | font-weight: 400; 179 | } 180 | 181 | blockquote { 182 | font-size: 1.6em; 183 | border-left: 10px solid #e9e9e9; 184 | margin-bottom: 20px; 185 | padding: 0 0 0 30px; 186 | } 187 | 188 | ul li { 189 | list-style: disc inside; 190 | padding-left: 20px; 191 | } 192 | 193 | ol li { 194 | list-style: decimal inside; 195 | padding-left: 3px; 196 | } 197 | 198 | dl dd { 199 | font-style: italic; 200 | font-weight: 100; 201 | } 202 | 203 | footer { 204 | margin-top: 40px; 205 | padding-top: 20px; 206 | padding-bottom: 30px; 207 | font-size: 13px; 208 | color: #aaa; 209 | } 210 | 211 | footer a { 212 | color: #666; 213 | } 214 | 215 | /* MISC */ 216 | .clearfix:after { 217 | clear: both; 218 | content: '.'; 219 | display: block; 220 | visibility: hidden; 221 | height: 0; 222 | } 223 | 224 | .clearfix {display: inline-block;} 225 | * html .clearfix {height: 1%;} 226 | .clearfix {display: block;} -------------------------------------------------------------------------------- /stylesheets/pygment_trac.css: -------------------------------------------------------------------------------- 1 | .highlight { background: #ffffff; } 2 | .highlight .c { color: #999988; font-style: italic } /* Comment */ 3 | .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 4 | .highlight .k { font-weight: bold } /* Keyword */ 5 | .highlight .o { font-weight: bold } /* Operator */ 6 | .highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 7 | .highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 8 | .highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ 9 | .highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 10 | .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 11 | .highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #aa0000 } /* Generic.Error */ 14 | .highlight .gh { color: #999999 } /* Generic.Heading */ 15 | .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 16 | .highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 17 | .highlight .go { color: #888888 } /* Generic.Output */ 18 | .highlight .gp { color: #555555 } /* Generic.Prompt */ 19 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 20 | .highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ 21 | .highlight .gt { color: #aa0000 } /* Generic.Traceback */ 22 | .highlight .kc { font-weight: bold } /* Keyword.Constant */ 23 | .highlight .kd { font-weight: bold } /* Keyword.Declaration */ 24 | .highlight .kn { font-weight: bold } /* Keyword.Namespace */ 25 | .highlight .kp { font-weight: bold } /* Keyword.Pseudo */ 26 | .highlight .kr { font-weight: bold } /* Keyword.Reserved */ 27 | .highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 28 | .highlight .m { color: #009999 } /* Literal.Number */ 29 | .highlight .s { color: #d14 } /* Literal.String */ 30 | .highlight .na { color: #008080 } /* Name.Attribute */ 31 | .highlight .nb { color: #0086B3 } /* Name.Builtin */ 32 | .highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ 33 | .highlight .no { color: #008080 } /* Name.Constant */ 34 | .highlight .ni { color: #800080 } /* Name.Entity */ 35 | .highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ 36 | .highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ 37 | .highlight .nn { color: #555555 } /* Name.Namespace */ 38 | .highlight .nt { color: #000080 } /* Name.Tag */ 39 | .highlight .nv { color: #008080 } /* Name.Variable */ 40 | .highlight .ow { font-weight: bold } /* Operator.Word */ 41 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 42 | .highlight .mf { color: #009999 } /* Literal.Number.Float */ 43 | .highlight .mh { color: #009999 } /* Literal.Number.Hex */ 44 | .highlight .mi { color: #009999 } /* Literal.Number.Integer */ 45 | .highlight .mo { color: #009999 } /* Literal.Number.Oct */ 46 | .highlight .sb { color: #d14 } /* Literal.String.Backtick */ 47 | .highlight .sc { color: #d14 } /* Literal.String.Char */ 48 | .highlight .sd { color: #d14 } /* Literal.String.Doc */ 49 | .highlight .s2 { color: #d14 } /* Literal.String.Double */ 50 | .highlight .se { color: #d14 } /* Literal.String.Escape */ 51 | .highlight .sh { color: #d14 } /* Literal.String.Heredoc */ 52 | .highlight .si { color: #d14 } /* Literal.String.Interpol */ 53 | .highlight .sx { color: #d14 } /* Literal.String.Other */ 54 | .highlight .sr { color: #009926 } /* Literal.String.Regex */ 55 | .highlight .s1 { color: #d14 } /* Literal.String.Single */ 56 | .highlight .ss { color: #990073 } /* Literal.String.Symbol */ 57 | .highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ 58 | .highlight .vc { color: #008080 } /* Name.Variable.Class */ 59 | .highlight .vg { color: #008080 } /* Name.Variable.Global */ 60 | .highlight .vi { color: #008080 } /* Name.Variable.Instance */ 61 | .highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ 62 | 63 | .type-csharp .highlight .k { color: #0000FF } 64 | .type-csharp .highlight .kt { color: #0000FF } 65 | .type-csharp .highlight .nf { color: #000000; font-weight: normal } 66 | .type-csharp .highlight .nc { color: #2B91AF } 67 | .type-csharp .highlight .nn { color: #000000 } 68 | .type-csharp .highlight .s { color: #A31515 } 69 | .type-csharp .highlight .sc { color: #A31515 } 70 | -------------------------------------------------------------------------------- /stylesheets/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | html, body, div, span, applet, object, iframe, 6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 7 | a, abbr, acronym, address, big, cite, code, 8 | del, dfn, em, img, ins, kbd, q, s, samp, 9 | small, strike, strong, sub, sup, tt, var, 10 | b, u, i, center, 11 | dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td, 14 | article, aside, canvas, details, embed, 15 | figure, figcaption, footer, header, hgroup, 16 | menu, nav, output, ruby, section, summary, 17 | time, mark, audio, video { 18 | margin: 0; 19 | padding: 0; 20 | border: 0; 21 | font-size: 100%; 22 | font: inherit; 23 | vertical-align: baseline; 24 | } 25 | /* HTML5 display-role reset for older browsers */ 26 | article, aside, details, figcaption, figure, 27 | footer, header, hgroup, menu, nav, section { 28 | display: block; 29 | } 30 | body { 31 | line-height: 1; 32 | } 33 | ol, ul { 34 | list-style: none; 35 | } 36 | blockquote, q { 37 | quotes: none; 38 | } 39 | blockquote:before, blockquote:after, 40 | q:before, q:after { 41 | content: ''; 42 | content: none; 43 | } 44 | table { 45 | border-collapse: collapse; 46 | border-spacing: 0; 47 | } 48 | 49 | /* LAYOUT STYLES */ 50 | body { 51 | font-size: 1em; 52 | line-height: 1.5; 53 | background: #e7e7e7 url(../images/body-bg.png) 0 0 repeat; 54 | font-family: 'Helvetica Neue', Helvetica, Arial, serif; 55 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8); 56 | color: #3d3d3d; 57 | } 58 | 59 | a { 60 | color: #b94a48; 61 | } 62 | 63 | a:hover { 64 | color: #c5000c; 65 | } 66 | 67 | header { 68 | padding-top: 35px; 69 | padding-bottom: 25px; 70 | } 71 | 72 | header h1 { 73 | font-family: 'Chivo', 'Helvetica Neue', Helvetica, Arial, serif; font-weight: 900; 74 | letter-spacing: -1px; 75 | font-size: 48px; 76 | color: #303030; 77 | line-height: 1.2; 78 | } 79 | 80 | header h2 { 81 | letter-spacing: -1px; 82 | font-size: 24px; 83 | color: #aaa; 84 | font-weight: normal; 85 | line-height: 1.3; 86 | } 87 | 88 | #container { 89 | background: transparent url(../images/highlight-bg.jpg) 50% 0 no-repeat; 90 | min-height: 595px; 91 | } 92 | 93 | .inner { 94 | width: 620px; 95 | margin: 0 auto; 96 | } 97 | 98 | #container .inner img { 99 | max-width: 100%; 100 | } 101 | 102 | #downloads { 103 | margin-bottom: 40px; 104 | } 105 | 106 | a.button { 107 | -moz-border-radius: 30px; 108 | -webkit-border-radius: 30px; 109 | border-radius: 30px; 110 | border-top: solid 1px #cbcbcb; 111 | border-left: solid 1px #b7b7b7; 112 | border-right: solid 1px #b7b7b7; 113 | border-bottom: solid 1px #b3b3b3; 114 | color: #303030; 115 | line-height: 25px; 116 | font-weight: bold; 117 | font-size: 15px; 118 | padding: 12px 8px 12px 8px; 119 | display: block; 120 | float: left; 121 | width: 179px; 122 | margin-right: 14px; 123 | background: #fdfdfd; /* Old browsers */ 124 | background: -moz-linear-gradient(top, #fdfdfd 0%, #f2f2f2 100%); /* FF3.6+ */ 125 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fdfdfd), color-stop(100%,#f2f2f2)); /* Chrome,Safari4+ */ 126 | background: -webkit-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* Chrome10+,Safari5.1+ */ 127 | background: -o-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* Opera 11.10+ */ 128 | background: -ms-linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* IE10+ */ 129 | background: linear-gradient(top, #fdfdfd 0%,#f2f2f2 100%); /* W3C */ 130 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fdfdfd', endColorstr='#f2f2f2',GradientType=0 ); /* IE6-9 */ 131 | -webkit-box-shadow: 10px 10px 5px #888; 132 | -moz-box-shadow: 10px 10px 5px #888; 133 | box-shadow: 0px 1px 5px #e8e8e8; 134 | } 135 | a.button:hover { 136 | border-top: solid 1px #b7b7b7; 137 | border-left: solid 1px #b3b3b3; 138 | border-right: solid 1px #b3b3b3; 139 | border-bottom: solid 1px #b3b3b3; 140 | background: #fafafa; /* Old browsers */ 141 | background: -moz-linear-gradient(top, #fdfdfd 0%, #f6f6f6 100%); /* FF3.6+ */ 142 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#fdfdfd), color-stop(100%,#f6f6f6)); /* Chrome,Safari4+ */ 143 | background: -webkit-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* Chrome10+,Safari5.1+ */ 144 | background: -o-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* Opera 11.10+ */ 145 | background: -ms-linear-gradient(top, #fdfdfd 0%,#f6f6f6 100%); /* IE10+ */ 146 | background: linear-gradient(top, #fdfdfd 0%,#f6f6f6, 100%); /* W3C */ 147 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fdfdfd', endColorstr='#f6f6f6',GradientType=0 ); /* IE6-9 */ 148 | } 149 | 150 | a.button span { 151 | padding-left: 50px; 152 | display: block; 153 | height: 23px; 154 | } 155 | 156 | #download-zip span { 157 | background: transparent url(../images/zip-icon.png) 12px 50% no-repeat; 158 | } 159 | #download-tar-gz span { 160 | background: transparent url(../images/tar-gz-icon.png) 12px 50% no-repeat; 161 | } 162 | #view-on-github span { 163 | background: transparent url(../images/octocat-icon.png) 12px 50% no-repeat; 164 | } 165 | #view-on-github { 166 | margin-right: 0; 167 | } 168 | 169 | code, pre { 170 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal; 171 | color: #222; 172 | margin-bottom: 30px; 173 | font-size: 14px; 174 | } 175 | 176 | code { 177 | background-color: #f2f2f2; 178 | border: solid 1px #ddd; 179 | padding: 0 3px; 180 | } 181 | 182 | pre { 183 | padding: 20px; 184 | background: #303030; 185 | color: #f2f2f2; 186 | text-shadow: none; 187 | overflow: auto; 188 | } 189 | pre code { 190 | color: #f2f2f2; 191 | background-color: #303030; 192 | border: none; 193 | padding: 0; 194 | } 195 | 196 | ul, ol, dl { 197 | margin-bottom: 20px; 198 | } 199 | 200 | 201 | /* COMMON STYLES */ 202 | 203 | hr { 204 | height: 1px; 205 | line-height: 1px; 206 | margin-top: 1em; 207 | padding-bottom: 1em; 208 | border: none; 209 | background: transparent url('../images/hr.png') 50% 0 no-repeat; 210 | } 211 | 212 | strong { 213 | font-weight: bold; 214 | } 215 | 216 | em { 217 | font-style: italic; 218 | } 219 | 220 | table { 221 | width: 100%; 222 | border: 1px solid #ebebeb; 223 | } 224 | 225 | th { 226 | font-weight: 500; 227 | } 228 | 229 | td { 230 | border: 1px solid #ebebeb; 231 | text-align: center; 232 | font-weight: 300; 233 | } 234 | 235 | form { 236 | background: #f2f2f2; 237 | padding: 20px; 238 | 239 | } 240 | 241 | 242 | /* GENERAL ELEMENT TYPE STYLES */ 243 | 244 | h1 { 245 | font-size: 32px; 246 | } 247 | 248 | h2 { 249 | font-size: 22px; 250 | font-weight: bold; 251 | color: #303030; 252 | margin-bottom: 8px; 253 | } 254 | 255 | h3 { 256 | color: #303030; 257 | font-size: 18px; 258 | font-weight: bold; 259 | margin-bottom: 8px; 260 | } 261 | 262 | h4 { 263 | font-size: 16px; 264 | color: #303030; 265 | font-weight: bold; 266 | } 267 | 268 | h5 { 269 | font-size: 1em; 270 | color: #303030; 271 | } 272 | 273 | h6 { 274 | font-size: .8em; 275 | color: #303030; 276 | } 277 | 278 | p { 279 | font-weight: 300; 280 | margin-bottom: 20px; 281 | } 282 | 283 | a { 284 | text-decoration: none; 285 | } 286 | 287 | p a { 288 | font-weight: 400; 289 | } 290 | 291 | blockquote { 292 | font-size: 1.6em; 293 | border-left: 10px solid #e9e9e9; 294 | margin-bottom: 20px; 295 | padding: 0 0 0 30px; 296 | } 297 | 298 | ul li { 299 | list-style: disc inside; 300 | padding-left: 20px; 301 | } 302 | 303 | ol li { 304 | list-style: decimal inside; 305 | padding-left: 3px; 306 | } 307 | 308 | dl dt { 309 | color: #303030; 310 | } 311 | 312 | footer { 313 | background: transparent url('../images/hr.png') 0 0 no-repeat; 314 | margin-top: 40px; 315 | padding-top: 20px; 316 | padding-bottom: 30px; 317 | font-size: 13px; 318 | color: #aaa; 319 | } 320 | 321 | footer a { 322 | color: #666; 323 | } 324 | footer a:hover { 325 | color: #444; 326 | } 327 | 328 | /* MISC */ 329 | .clearfix:after { 330 | clear: both; 331 | content: '.'; 332 | display: block; 333 | visibility: hidden; 334 | height: 0; 335 | } 336 | 337 | .clearfix {display: inline-block;} 338 | * html .clearfix {height: 1%;} 339 | .clearfix {display: block;} 340 | 341 | /* #Media Queries 342 | ================================================== */ 343 | 344 | /* Smaller than standard 960 (devices and browsers) */ 345 | @media only screen and (max-width: 959px) {} 346 | 347 | /* Tablet Portrait size to standard 960 (devices and browsers) */ 348 | @media only screen and (min-width: 768px) and (max-width: 959px) {} 349 | 350 | /* All Mobile Sizes (devices and browser) */ 351 | @media only screen and (max-width: 767px) { 352 | header { 353 | padding-top: 10px; 354 | padding-bottom: 10px; 355 | } 356 | #downloads { 357 | margin-bottom: 25px; 358 | } 359 | #download-zip, #download-tar-gz { 360 | display: none; 361 | } 362 | .inner { 363 | width: 94%; 364 | margin: 0 auto; 365 | } 366 | } 367 | 368 | /* Mobile Landscape Size to Tablet Portrait (devices and browsers) */ 369 | @media only screen and (min-width: 480px) and (max-width: 767px) {} 370 | 371 | /* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */ 372 | @media only screen and (max-width: 479px) {} 373 | -------------------------------------------------------------------------------- /update_params.js: -------------------------------------------------------------------------------- 1 | var params_json = require('./params.json'); 2 | var fs = require('fs'); 3 | 4 | 5 | /* 6 | ** clone 7 | */ 8 | function clone(obj) { 9 | // Handle the 3 simple types, and null or undefined 10 | if (null == obj || "object" != typeof obj) return obj; 11 | 12 | // Handle Date 13 | if (obj instanceof Date) { 14 | var copy = new Date(); 15 | copy.setTime(obj.getTime()); 16 | return copy; 17 | } 18 | 19 | // Handle Array 20 | if (obj instanceof Array) { 21 | var copy = []; 22 | for (var i = 0, len = obj.length; i < len; i++) { 23 | copy[i] = clone(obj[i]); 24 | } 25 | return copy; 26 | } 27 | 28 | // Handle Object 29 | if (obj instanceof Object) { 30 | var copy = {}; 31 | for (var attr in obj) { 32 | if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); 33 | } 34 | return copy; 35 | } 36 | 37 | throw new Error("Unable to copy obj! Its type isn't supported."); 38 | } 39 | 40 | /* 41 | ** 42 | ** get source 43 | ** 44 | */ 45 | var source_body; 46 | fs.readFile( './source.json', 'utf8', function( err, data ){ 47 | 48 | if( err ){ 49 | console.log( err ); 50 | } 51 | 52 | source_body = data; 53 | 54 | 55 | /* 56 | ** 57 | ** save old params 58 | ** 59 | */ 60 | fs.writeFile( './params.json.backup', JSON.stringify( clone( params_json ) ), function( err ){ 61 | 62 | if ( err ){ 63 | console.log( err ); 64 | } 65 | 66 | }); 67 | 68 | 69 | 70 | /* 71 | ** 72 | ** swap it and 73 | ** save new params.json 74 | ** 75 | */ 76 | params_json.body = source_body; 77 | fs.writeFile( './params.json', JSON.stringify( params_json ), function( err ){ 78 | 79 | if ( err ){ 80 | console.log( err ); 81 | } 82 | 83 | }); 84 | 85 | 86 | }); 87 | 88 | 89 | 90 | 91 | 92 | --------------------------------------------------------------------------------